diff --git a/.eslintrc.json b/.eslintrc.json index 61bebbf4836..2b52485689a 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -262,6 +262,12 @@ } ] } + }, + { + "files": ["bitwarden_license/bit-common/src/**/*.ts"], + "rules": { + "no-restricted-imports": ["error", { "patterns": ["@bitwarden/bit-common/*", "src/**/*"] }] + } } ] } diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aba7d4e0e0e..2ec9d3b1b40 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -87,6 +87,10 @@ apps/web/src/translation-constants.ts @bitwarden/team-platform-dev apps/browser/src/autofill @bitwarden/team-autofill-dev apps/desktop/src/autofill @bitwarden/team-autofill-dev libs/common/src/autofill @bitwarden/team-autofill-dev +# DuckDuckGo integration +apps/desktop/native-messaging-test-runner @bitwarden/team-autofill-dev +apps/desktop/src/services/native-message-handler.service.ts @bitwarden/team-autofill-dev +apps/desktop/src/services/native-messaging.service.ts @bitwarden/team-autofill-dev ## Component Library ## .storybook @bitwarden/team-component-library diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index b034136f585..1ff67671419 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -224,7 +224,7 @@ jobs: project: Clients environment: ${{ needs.setup.outputs.environment-name }} tag: ${{ inputs.branch-or-tag }} - slack-channel: team-eng-qa-devops + slack-channel: alerts-deploy-qa event: 'start' commit-sha: ${{ needs.artifact-check.outputs.artifact-build-commit }} url: https://github.com/bitwarden/clients/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/version-bump.yml b/.github/workflows/version-bump.yml index 246ca9a533d..0341f2a57af 100644 --- a/.github/workflows/version-bump.yml +++ b/.github/workflows/version-bump.yml @@ -452,6 +452,38 @@ jobs: PR_NUMBER: ${{ steps.create-pr.outputs.pr_number }} run: gh pr merge $PR_NUMBER --squash --auto --delete-branch + - name: Report upcoming browser release version to Slack + if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} && ${{ steps.set-final-version-output.outputs.version_browser != '' }} + uses: bitwarden/gh-actions/report-upcoming-release-version@main + with: + version: ${{ steps.set-final-version-output.outputs.version_browser }} + project: browser + AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + + - name: Report upcoming cli release version to Slack + if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} && ${{ steps.set-final-version-output.outputs.version_cli != '' }} + uses: bitwarden/gh-actions/report-upcoming-release-version@main + with: + version: ${{ steps.set-final-version-output.outputs.version_cli }} + project: cli + AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + + - name: Report upcoming desktop release version to Slack + if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} && ${{ steps.set-final-version-output.outputs.version_desktop != '' }} + uses: bitwarden/gh-actions/report-upcoming-release-version@main + with: + version: ${{ steps.set-final-version-output.outputs.version_desktop }} + project: desktop + AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + + - name: Report upcoming web release version to Slack + if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} && ${{ steps.set-final-version-output.outputs.version_web != '' }} + uses: bitwarden/gh-actions/report-upcoming-release-version@main + with: + version: ${{ steps.set-final-version-output.outputs.version_web }} + project: web + AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + cut_rc: name: Cut RC branch if: ${{ inputs.cut_rc_branch == true }} diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 42c16140223..378035731fb 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "القياسات الحيوية للمتصفح غير مدعومة على هذا الجهاز." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "فشل القياسات الحيوية" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "إنشاء بريد إلكتروني مستعار مع خدمة إعادة توجيه خارجية." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "اسم المضيف", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 6ac5c64ddd2..3de2043bb96 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Brauzer biometrikləri bu cihazda dəstəklənmir." }, + "biometricsNotUnlockedTitle": { + "message": "İstifadəçi kilidlənib və ya hesabdan çıxış edib" + }, + "biometricsNotUnlockedDesc": { + "message": "Lütfən bu istifadəçinin kilidini masaüstü tətbiqində açıb yenidən sınayın." + }, "biometricsFailedTitle": { "message": "Biometrik uğursuzdur" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Xarici yönləndirmə xidməti ilə e-poçt ləqəbi yaradın." }, + "forwarderError": { + "message": "$SERVICENAME$ xətası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Veb sayt: $WEBSITE$. Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Yararsız $SERVICENAME$ API jetonu", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Yararsız $SERVICENAME$ API jetonu: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ maskalı e-poçt hesab kimliyi alına bilmir.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Yararsız $SERVICENAME$ domeni.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Yararsız $SERVICENAME$ url-si.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Bilinməyən $SERVICENAME$ xətası baş verdi.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Bilinməyən yönləndirici: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Host adı", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Hədəf qovluğa təyin etmə xətası." + }, + "new": { + "message": "Yeni" } } diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index fb99a0a95d7..dca728a871d 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Біяметрыя ў браўзеры не падтрымліваецца на гэтай прыладзе." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Генерыраваць псеўданім электроннай пошты са знешнім сэрвісам перасылкі." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Назва вузла", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 609131a66a1..db8254c3b4c 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Устройството не поддържа потвърждаване с биометрични данни." }, + "biometricsNotUnlockedTitle": { + "message": "Потребителят е заключен или отписан" + }, + "biometricsNotUnlockedDesc": { + "message": "Отключете потребителя в настолното приложение и опитайте отново." + }, "biometricsFailedTitle": { "message": "Неуспешно удостоверяване чрез биометрични данни" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Създайте псевдоним на е-поща с външна услуга за препращане." }, + "forwarderError": { + "message": "Грешка от $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Уебсайт: $WEBSITE$. Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не може да бъде получен идентификатор на маскиран чрез е-поща акаунт от $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Неправилен домейн за $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Неправилен адрес на $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Възникна неочаквана грешка свързана с $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестна пренасочваща услуга: „$SERVICENAME$“.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име на сървъра", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Грешка при задаването на целева папка." + }, + "new": { + "message": "Ново" } } diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index c0ccd92d7a8..87c797d957a 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "ব্রাউজার বায়োমেট্রিক্স এই ডিভাইসে সমর্থিত নয়।" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index 53c5c4ed44e..ea69b2593f8 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 2e282e30ee1..f35e9023ad3 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -375,7 +375,7 @@ "message": "Altres" }, "unlockMethods": { - "message": "Unlock options" + "message": "Opcions de desbloqueig" }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Configura un mètode de desbloqueig per canviar l'acció del temps d'espera de la caixa forta." @@ -384,10 +384,10 @@ "message": "Configura un mètode de desbloqueig a Configuració" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Temps de sessió" }, "otherOptions": { - "message": "Other options" + "message": "Altres opcions" }, "rateExtension": { "message": "Valora aquesta extensió" @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "La biometria del navegador no és compatible amb aquest dispositiu." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "La biometria ha fallat" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Genera un àlies de correu electrònic amb un servei de reenviament extern." }, + "forwarderError": { + "message": "Error de $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generat per Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Lloc web: $WEBSITE$. Generat per Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom de l'amfitrió", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "S'ha produït un error en assignar la carpeta de destinació." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 794e2d995da..3a331e2ba74 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometrie v prohlížeči není na tomto zařízení podporována." }, + "biometricsNotUnlockedTitle": { + "message": "Uživatel uzamčen nebo odhlášen" + }, + "biometricsNotUnlockedDesc": { + "message": "Odemkněte tohoto uživatele v programu pro počítač a zkuste to znovu." + }, "biometricsFailedTitle": { "message": "Biometrika selhala" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Vygenerovat e-mailový alias pomocí externí služby pro přesměrování." }, + "forwarderError": { + "message": "Chyba $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webová stránka: $WEBSITE$. Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Neplatný token API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Neplatný token API $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nelze získat maskované ID e-mailového účtu $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Neplatná doména $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Neplatné URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Došlo k neznámé chybě $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Neznámý přeposílatel: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Název hostitele", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Chyba při přiřazování cílové složky." + }, + "new": { + "message": "Nové" } } diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index d43cb2b25dc..7597e52998d 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 57f87d7a8eb..eae8e6553fe 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browserbiometri understøttes ikke på denne enhed." }, + "biometricsNotUnlockedTitle": { + "message": "Bruger låst eller logget ud" + }, + "biometricsNotUnlockedDesc": { + "message": "Oplås denne bruger op i computerprogrammet og forsøg igen." + }, "biometricsFailedTitle": { "message": "Biometri mislykkedes" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generér et e-mail alias med en ekstern viderestillingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$-fejl: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Websted: $WEBSITE$. Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Ugyldigt $SERVICENAME$ API-token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Ugyldigt $SERVICENAME$ API-token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Kan ikke få $SERVICENAME$ maskeret e-mailkonto-ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ugyldigt $SERVICENAME$-domæne.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ugyldig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ukendt $SERVICENAME$-fejl opstod.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ukendt videresender: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Værtsnavn", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Fejl ved tildeling af målmappe." + }, + "new": { + "message": "Ny/Nyt" } } diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 58e0f17053e..53a60619e5b 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -7,7 +7,7 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Zu Hause, am Arbeitsplatz oder unterwegs schützt Bitwarden Passwörter, Passkeys und vertrauliche Informationen", + "message": "Bitwarden schützt alle deine Passwörter, Passkeys und vertrauliche Informationen - egal, wo du bist.", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometrie im Browser wird auf diesem Gerät nicht unterstützt." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrie fehlgeschlagen" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generiere ein E-Mail-Alias mit einem externen Weiterleitungsdienst." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Fehler beim Zuweisen des Ziel-Ordners." + }, + "new": { + "message": "Neu" } } diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 60659eeb657..0bb5df78b22 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Τα βιομετρικά στοιχεία του προγράμματος περιήγησης δεν υποστηρίζονται σε αυτήν τη συσκευή." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Ο βιομετρικός έλεγχος απέτυχε" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Δημιουργήστε ένα alias email με μια εξωτερική υπηρεσία προώθησης." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 828cca3c855..28ad7b2d42e 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -3148,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index bbaf77b714c..49e2677d81e 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 9e154437ffc..7dfe7100f6c 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index d460a54ac88..07d28a384a5 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -125,7 +125,7 @@ "message": "Agregar identidad" }, "unlockVaultMenu": { - "message": "Desbloquea la caja fuerte" + "message": "Desbloquea tu caja fuerte" }, "loginToVaultMenu": { "message": "Inicia sesión en tu caja fuerte" @@ -229,7 +229,7 @@ "message": "Centro de ayuda de Bitwarden" }, "communityForums": { - "message": "Explorar los foros de la comunidad Bitwarden" + "message": "Explora los foros de la comunidad Bitwarden" }, "contactSupport": { "message": "Contactar al soporte de Bitwarden" @@ -384,7 +384,7 @@ "message": "Configure un método de desbloqueo en Configuración" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Tiempo de sesión agotado" }, "otherOptions": { "message": "Otras opciones" @@ -685,7 +685,7 @@ "message": "¿Debería Bitwarden recordar esta contraseña por ti?" }, "notificationAddSave": { - "message": "Sí, guardar ahora" + "message": "Guardar" }, "enableChangedPasswordNotification": { "message": "Solicitar la actualización de los datos de inicio de sesión existentes" @@ -700,7 +700,7 @@ "message": "Solicitar guardar y usar claves de acceso" }, "usePasskeysDesc": { - "message": "Solicitar guardar claves de paso nuevas o acceder con claves de paso almacenadas en su caja fuerte. Se aplica a todas las cuentas accedidas." + "message": "Solicita guardar nuevas claves de acceso o inicia sesión con claves de acceso almacenadas en tu caja fuerte. Se aplica a todas las cuentas que hayan iniciado sesión." }, "notificationChangeDesc": { "message": "¿Desea actualizar esta contraseña en Bitwarden?" @@ -709,7 +709,7 @@ "message": "Actualizar" }, "notificationUnlockDesc": { - "message": "Desbloquea tu bóveda Bitwarden para completar la solicitud de autollenado." + "message": "Desbloquea tu caja fuerte de Bitwarden para completar la solicitud de autocompletado." }, "notificationUnlock": { "message": "Desbloquear" @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "La biometría del navegador no es compatible con este dispositivo." }, + "biometricsNotUnlockedTitle": { + "message": "Usuario bloqueado o desconectado" + }, + "biometricsNotUnlockedDesc": { + "message": "Por favor, desbloquea a este usuario en la aplicación de escritorio e inténtalo de nuevo." + }, "biometricsFailedTitle": { "message": "Fallo de biométrica" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Genera un alias de correo electrónico con un servicio de reenvío externo." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generado por Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Sitio web: $WEBSITE$. Generado por Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token de API $SERVICENAME$ no válido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token de API $SERVICENAME$ no válido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "No se puede obtener el ID de la cuenta de correo electrónico enmascarado de $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Dominio $SERVICENAME$ no válido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ no válida.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Se ha producido un error $SERVICENAME$ desconocido.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Redirigidor desconocido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nombre del servidor", "description": "Part of a URL." @@ -2804,13 +2912,13 @@ "message": "Verificación requerida por el sitio inicial. Esta característica aún no está implementada para cuentas sin contraseña maestra." }, "logInWithPasskey": { - "message": "¿Iniciar sesión con contraseña?" + "message": "¿Iniciar sesión con clave de acceso?" }, "passkeyAlreadyExists": { "message": "Ya existe una clave de acceso para esta aplicación." }, "noPasskeysFoundForThisApplication": { - "message": "No se encontraron contraseñas para esta aplicación." + "message": "No se encontraron claves de acceso para esta aplicación." }, "noMatchingPasskeyLogin": { "message": "No tiene un inicio de sesión que coincida para este sitio." @@ -2819,10 +2927,10 @@ "message": "Confirmar" }, "savePasskey": { - "message": "Guardar clave" + "message": "Guardar clave de acceso" }, "savePasskeyNewLogin": { - "message": "Guardar contraseña como nuevo inicio de sesión" + "message": "Guardar clave de acceso como nuevo inicio de sesión" }, "choosePasskey": { "message": "Elija un inicio de sesión para guardar esta clave de acceso" @@ -2831,7 +2939,7 @@ "message": "Elemento de clave de acceso" }, "overwritePasskey": { - "message": "¿Sobrescribir contraseña?" + "message": "¿Sobrescribir clave de acceso?" }, "overwritePasskeyAlert": { "message": "Este elemento ya contiene una clave de acceso. ¿Está seguro de que desea sobrescribir la contraseña actual?" @@ -3010,16 +3118,16 @@ "message": "Éxito" }, "removePasskey": { - "message": "Eliminar passkey" + "message": "Eliminar clave de acceso" }, "passkeyRemoved": { - "message": "Passkey eliminada" + "message": "Clave de acceso eliminada" }, "unassignedItemsBannerNotice": { - "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." + "message": "Aviso: Los elementos de organización no asignados ya no son visibles en la vista de Todas las cajas fuertes y solo son accesibles a través de la Consola de Administrador." }, "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: El 16 de mayo de 2024, los elementos de organización no asignados no serán visibles en la vista de Todas las cajas fuertes y solo serán accesibles a través de la Consola de Administrador." }, "unassignedItemsBannerCTAPartOne": { "message": "Asignar estos elementos a una colección de", @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error al asignar la carpeta de destino." + }, + "new": { + "message": "Nuevo" } } diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 40b127f0591..fc42daaa170 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Brauseri biomeetria ei ole selles seadmes toetatud" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biomeetria nurjus" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Genereeri e-posti alias, kasutades selleks välist teenuspakkujat." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hosti nimi", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 0d4790b2711..151bed7ef2e 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Nabigatzailearen biometria ezin da gailu honetan erabili." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Emaileko ezizen bat sortu kanpoko bidalketa zerbitzu batekin." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ostalariaren izena", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 6620f33c1e0..9ce3af7c323 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "بیومتریک مرورگر در این دستگاه پشتیبانی نمی‌شود." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "زیست‌سنجی ناموفق بود" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "یک نام مستعار ایمیل با یک سرویس ارسال خارجی ایجاد کنید." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "نام میزبان", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 7af0c95a1d2..cb11a76332e 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -7,7 +7,7 @@ "description": "Extension name, MUST be less than 40 characters (Safari restriction)" }, "extDesc": { - "message": "Kotona, töissä tai reissussa, Bitwarden suojaa helposti salasanasi, suojausavaimesi ja arkaluonteiset tietosi.", + "message": "Kotona, töissä tai reissussa, Bitwarden suojaa salasanasi, suojausavaimesi ja arkaluonteiset tietosi helposti.", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -697,10 +697,10 @@ "message": "Tarjoa kirjautumistiedon salasanan päivitystä, kun verkkosivustolla havaitaan uusi salasana. Koskee kaikkia kirjautuneita tilejä." }, "enableUsePasskeys": { - "message": "Tarjoa salausavainten tallennusta ja käyttöä" + "message": "Tarjoa suojausvainten tallennusta ja käyttöä" }, "usePasskeysDesc": { - "message": "Tarjoa tallennusta uusille salausavaimille tai kirjautumista holvissasi olevilla salausavaimilla. Koskee kaikkia kirjautuneita tilejä." + "message": "Tarjoa tallennusta uusille suojausavaimille tai kirjautumista holvissasi olevilla salausavaimilla. Koskee kaikkia kirjautuneita tilejä." }, "notificationChangeDesc": { "message": "Haluatko päivittää salasanan Bitwardeniin?" @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Selaimen biometriaa ei tueta tällä laitteella." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometria epäonnistui" }, @@ -2172,11 +2178,113 @@ "message": "Palvelu" }, "forwardedEmail": { - "message": "Sähköpostialias välitykseen" + "message": "Sähköpostialias ohjaukseen" }, "forwardedEmailDesc": { "message": "Luo sähköpostialias ulkoisella ohjauspalvelulla." }, + "forwarderError": { + "message": "$SERVICENAME$ -virhe: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Verkkosivusto: $WEBSITE$. Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ -palvelun peittämän sähköpostitilin tunnistetta ei saatu.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Virheellinen $SERVICENAME$ -verkkotunnus.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Virheellinen $SERVICENAME$ -URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Tapahtui tuntematon $SERVICENAME$ -virhe.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Tuntematon ohjaaja: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Isäntä", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Virhe määritettäessä kohdekansiota." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 6e52afd7db6..3e582b8baf0 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Ang browser biometrics ay hindi sinusuportahan sa device na ito." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Bumuo ng isang email alias na may isang panlabas na serbisyo sa pagpapasa." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Pangalan ng Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index d53961be291..733a4bd5cef 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Le déverrouillage biométrique dans le navigateur n’est pas pris en charge sur cet appareil" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Le déverrouillage biométique a échoué\n" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Générer un alias de courriel avec un service de transfert externe." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom d'hôte", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 0c2ce6114a3..6a3402ed8d8 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -176,239 +176,239 @@ "message": "Continuar á aplicación web?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Podes cambiar o teu contrasinal mestre na aplicación web de Bitwarden." }, "fingerprintPhrase": { - "message": "Fingerprint phrase", + "message": "Frase de pegada dactilar", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "yourAccountsFingerprint": { - "message": "Your account's fingerprint phrase", + "message": "Frase de pegada dactilar da túa conta", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { - "message": "Two-step login" + "message": "Autenticación en dous pasos" }, "logOut": { - "message": "Log out" + "message": "Pechar sesión" }, "about": { - "message": "About" + "message": "Acerca de" }, "version": { - "message": "Version" + "message": "Versión" }, "save": { - "message": "Save" + "message": "Gardar" }, "move": { - "message": "Move" + "message": "Mover" }, "addFolder": { - "message": "Add folder" + "message": "Engadir cartafol" }, "name": { - "message": "Name" + "message": "Nome" }, "editFolder": { - "message": "Edit folder" + "message": "Editar cartafol" }, "deleteFolder": { - "message": "Delete folder" + "message": "Eliminar cartafol" }, "folders": { - "message": "Folders" + "message": "Cartafois" }, "noFolders": { - "message": "There are no folders to list." + "message": "Non hai cartafois que listar." }, "helpFeedback": { - "message": "Help & feedback" + "message": "Axuda e comentarios" }, "helpCenter": { - "message": "Bitwarden Help center" + "message": "Centro de axuda de Bitwarden" }, "communityForums": { - "message": "Explore Bitwarden community forums" + "message": "Explorar os foros da comunidade de Bitwarden" }, "contactSupport": { - "message": "Contact Bitwarden support" + "message": "Contactar co soporte de Bitwarden" }, "sync": { - "message": "Sync" + "message": "Sincronizar" }, "syncVaultNow": { - "message": "Sync vault now" + "message": "Sincronizar caixa forte agora" }, "lastSync": { - "message": "Last sync:" + "message": "Última sincronización:" }, "passGen": { - "message": "Password generator" + "message": "Xerador de contrasinais" }, "generator": { - "message": "Generator", + "message": "Xerador", "description": "Short for 'Password Generator'." }, "passGenInfo": { - "message": "Automatically generate strong, unique passwords for your logins." + "message": "Xera automaticamente contrasinais fortes e únicos para os seus inicios de sesión." }, "bitWebVault": { - "message": "Bitwarden web vault" + "message": "Caixa forte web de Bitwarden" }, "importItems": { - "message": "Import items" + "message": "Importar elementos" }, "select": { - "message": "Select" + "message": "Seleccionar" }, "generatePassword": { - "message": "Generate password" + "message": "Xerar contrasinal" }, "regeneratePassword": { - "message": "Regenerate password" + "message": "Volver xerar contrasinal" }, "options": { - "message": "Options" + "message": "Opcións" }, "length": { - "message": "Length" + "message": "Lonxitude" }, "passwordMinLength": { - "message": "Minimum password length" + "message": "Lonxitude mínima do contrasinal" }, "uppercase": { - "message": "Uppercase (A-Z)" + "message": "Maiúsculas (A-Z)" }, "lowercase": { - "message": "Lowercase (a-z)" + "message": "Minúsculas (a-z)" }, "numbers": { - "message": "Numbers (0-9)" + "message": "Números (0-9)" }, "specialCharacters": { - "message": "Special characters (!@#$%^&*)" + "message": "Caracteres especiais (!@#$%^&*)" }, "numWords": { - "message": "Number of words" + "message": "Número de palabras" }, "wordSeparator": { - "message": "Word separator" + "message": "Separador de palabras" }, "capitalize": { - "message": "Capitalize", + "message": "Facer a primeira letra da palabra maiúscula", "description": "Make the first letter of a work uppercase." }, "includeNumber": { - "message": "Include number" + "message": "Incluír número" }, "minNumbers": { - "message": "Minimum numbers" + "message": "Mínimo de números" }, "minSpecial": { - "message": "Minimum special" + "message": "Mínimo de caracteres especiais" }, "avoidAmbChar": { - "message": "Avoid ambiguous characters" + "message": "Evitar caracteres ambiguos" }, "searchVault": { - "message": "Search vault" + "message": "Buscar na caixa forte" }, "edit": { - "message": "Edit" + "message": "Editar" }, "view": { - "message": "View" + "message": "Ver" }, "noItemsInList": { - "message": "There are no items to list." + "message": "Non hai elementos que listar." }, "itemInformation": { - "message": "Item information" + "message": "Información do elemento" }, "username": { - "message": "Username" + "message": "Nome de usuario" }, "password": { - "message": "Password" + "message": "Contrasinal" }, "totp": { - "message": "Authenticator secret" + "message": "Secreto de autenticador" }, "passphrase": { - "message": "Passphrase" + "message": "Frase de contrasinal" }, "favorite": { - "message": "Favorite" + "message": "Favorito" }, "notes": { - "message": "Notes" + "message": "Notas" }, "note": { - "message": "Note" + "message": "Nota" }, "editItem": { - "message": "Edit item" + "message": "Editar elemento" }, "folder": { - "message": "Folder" + "message": "Cartafol" }, "deleteItem": { - "message": "Delete item" + "message": "Eliminar elemento" }, "viewItem": { - "message": "View item" + "message": "Ver elemento" }, "launch": { - "message": "Launch" + "message": "Iniciar" }, "website": { - "message": "Website" + "message": "Sitio web" }, "toggleVisibility": { - "message": "Toggle visibility" + "message": "Alternar visibilidade" }, "manage": { - "message": "Manage" + "message": "Xestionar" }, "other": { - "message": "Other" + "message": "Outro" }, "unlockMethods": { - "message": "Unlock options" + "message": "Opcións de desbloqueo" }, "unlockMethodNeededToChangeTimeoutActionDesc": { - "message": "Set up an unlock method to change your vault timeout action." + "message": "Configura un método de desbloqueo para cambiar a túa acción de peche de sesión da caixa forte." }, "unlockMethodNeeded": { - "message": "Set up an unlock method in Settings" + "message": "Configura un método de desbloqueo nos axustes" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Tempo de sesión esgotado" }, "otherOptions": { - "message": "Other options" + "message": "Outras opcións" }, "rateExtension": { - "message": "Rate the extension" + "message": "Valorar a extensión" }, "rateExtensionDesc": { - "message": "Please consider helping us out with a good review!" + "message": "Por favor, considera axudarnos cunha boa recensión!" }, "browserNotSupportClipboard": { - "message": "Your web browser does not support easy clipboard copying. Copy it manually instead." + "message": "O teu navegador web non soporta copia doada ao portapapeis. Cópiao manualmente no seu lugar." }, "verifyIdentity": { - "message": "Verify identity" + "message": "Verificar identidade" }, "yourVaultIsLocked": { - "message": "Your vault is locked. Verify your identity to continue." + "message": "A túa caixa forte está bloqueada. Verifica a túa identidade para continuar." }, "unlock": { - "message": "Unlock" + "message": "Desbloquear" }, "loggedInAsOn": { - "message": "Logged in as $EMAIL$ on $HOSTNAME$.", + "message": "Conectado coma $EMAIL$ en $HOSTNAME$.", "placeholders": { "email": { "content": "$1", @@ -421,79 +421,79 @@ } }, "invalidMasterPassword": { - "message": "Invalid master password" + "message": "Contrasinal mestre non válido" }, "vaultTimeout": { - "message": "Vault timeout" + "message": "Tempo de espera da caixa forte" }, "lockNow": { - "message": "Lock now" + "message": "Bloquear agora" }, "lockAll": { - "message": "Lock all" + "message": "Bloquear todo" }, "immediately": { - "message": "Immediately" + "message": "Inmediatamente" }, "tenSeconds": { - "message": "10 seconds" + "message": "10 segundos" }, "twentySeconds": { - "message": "20 seconds" + "message": "20 segundos" }, "thirtySeconds": { - "message": "30 seconds" + "message": "30 segundos" }, "oneMinute": { - "message": "1 minute" + "message": "1 minuto" }, "twoMinutes": { - "message": "2 minutes" + "message": "2 minutos" }, "fiveMinutes": { - "message": "5 minutes" + "message": "5 minutos" }, "fifteenMinutes": { - "message": "15 minutes" + "message": "15 minutos" }, "thirtyMinutes": { - "message": "30 minutes" + "message": "30 minutos" }, "oneHour": { - "message": "1 hour" + "message": "1 hora" }, "fourHours": { - "message": "4 hours" + "message": "4 horas" }, "onLocked": { - "message": "On system lock" + "message": "Ao bloquear o sistema" }, "onRestart": { - "message": "On browser restart" + "message": "Ao reiniciar o navegador" }, "never": { - "message": "Never" + "message": "Nunca" }, "security": { - "message": "Security" + "message": "Seguridade" }, "errorOccurred": { - "message": "An error has occurred" + "message": "Produciuse un erro" }, "emailRequired": { - "message": "Email address is required." + "message": "É preciso un enderezo de correo electrónico." }, "invalidEmail": { - "message": "Invalid email address." + "message": "Enderezo de correo electrónico non válido." }, "masterPasswordRequired": { - "message": "Master password is required." + "message": "É preciso o contrasinal mestre." }, "confirmMasterPasswordRequired": { - "message": "Master password retype is required." + "message": "É preciso volver escribir o contrasinal mestre." }, "masterPasswordMinlength": { - "message": "Master password must be at least $VALUE$ characters long.", + "message": "O contrasinal mestre debe ter polo menos $VALUE$ caracteres de lonxitude.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -503,28 +503,28 @@ } }, "masterPassDoesntMatch": { - "message": "Master password confirmation does not match." + "message": "A confirmación de contrasinal mestre non coincide." }, "newAccountCreated": { - "message": "Your new account has been created! You may now log in." + "message": "A túa nova conta foi creada! Podes iniciar sesión agora." }, "youSuccessfullyLoggedIn": { - "message": "You successfully logged in" + "message": "Iniciaches sesión correctamente" }, "youMayCloseThisWindow": { - "message": "You may close this window" + "message": "Podes pechar está ventá" }, "masterPassSent": { - "message": "We've sent you an email with your master password hint." + "message": "Enviámoste un correo electrónico coa túa pista de contrasinal mestre." }, "verificationCodeRequired": { - "message": "Verification code is required." + "message": "É preciso código de verificación." }, "invalidVerificationCode": { - "message": "Invalid verification code" + "message": "Código de verificación non válido" }, "valueCopied": { - "message": "$VALUE$ copied", + "message": "$VALUE$ copiado", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -549,7 +549,7 @@ "message": "Copy Authenticator key (TOTP)" }, "loggedOut": { - "message": "Logged out" + "message": "Sesión pechada" }, "loginExpired": { "message": "Your login session has expired." @@ -558,46 +558,46 @@ "message": "Are you sure you want to log out?" }, "yes": { - "message": "Yes" + "message": "Si" }, "no": { - "message": "No" + "message": "Non" }, "unexpectedError": { - "message": "An unexpected error has occurred." + "message": "Produciuse un erro inesperado." }, "nameRequired": { - "message": "Name is required." + "message": "Requírese o nome." }, "addedFolder": { - "message": "Folder added" + "message": "Cartafol engadido" }, "twoStepLoginConfirmation": { "message": "Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be set up on the bitwarden.com web vault. Do you want to visit the website now?" }, "editedFolder": { - "message": "Folder saved" + "message": "Cartafol gardado" }, "deleteFolderConfirmation": { - "message": "Are you sure you want to delete this folder?" + "message": "Estás seguro de que queres eliminar este cartafol?" }, "deletedFolder": { - "message": "Folder deleted" + "message": "Cartafol eliminado" }, "gettingStartedTutorial": { - "message": "Getting started tutorial" + "message": "Tutorial introdutivo" }, "gettingStartedTutorialVideo": { "message": "Watch our getting started tutorial to learn how to get the most out of the browser extension." }, "syncingComplete": { - "message": "Syncing complete" + "message": "Sincronización completa" }, "syncingFailed": { - "message": "Syncing failed" + "message": "Sincronización fallida" }, "passwordCopied": { - "message": "Password copied" + "message": "Contrasinal copiado" }, "uri": { "message": "URI" @@ -613,47 +613,47 @@ } }, "newUri": { - "message": "New URI" + "message": "Nova URI" }, "addedItem": { - "message": "Item added" + "message": "Elemento engadido" }, "editedItem": { - "message": "Item saved" + "message": "Elemento gardado" }, "deleteItemConfirmation": { - "message": "Do you really want to send to the trash?" + "message": "Realmente queres enviar ao lixo?" }, "deletedItem": { - "message": "Item sent to trash" + "message": "Elemento enviado ao lixo" }, "overwritePassword": { - "message": "Overwrite password" + "message": "Sobrescribir contrasinal" }, "overwritePasswordConfirmation": { - "message": "Are you sure you want to overwrite the current password?" + "message": "Estás seguro de que queres sobrescribir o contrasinal actual?" }, "overwriteUsername": { - "message": "Overwrite username" + "message": "Sobrescribir nome de usuario" }, "overwriteUsernameConfirmation": { - "message": "Are you sure you want to overwrite the current username?" + "message": "Estás seguro de que queres sobrescribir o nome de usuario actual?" }, "searchFolder": { - "message": "Search folder" + "message": "Buscar cartafol" }, "searchCollection": { - "message": "Search collection" + "message": "Buscar colección" }, "searchType": { - "message": "Search type" + "message": "Buscar tipo" }, "noneFolder": { - "message": "No folder", + "message": "Sen cartafol", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Solicita engadir inicio de sesión" }, "addLoginNotificationDesc": { "message": "Ask to add an item if one isn't found in your vault." @@ -662,19 +662,19 @@ "message": "Ask to add an item if one isn't found in your vault. Applies to all logged in accounts." }, "showCardsCurrentTab": { - "message": "Show cards on Tab page" + "message": "Amosar tarxetas no separador" }, "showCardsCurrentTabDesc": { - "message": "List card items on the Tab page for easy auto-fill." + "message": "Lista os elementos de tarxeta no separador para fácil auto-completado." }, "showIdentitiesCurrentTab": { - "message": "Show identities on Tab page" + "message": "Mostrar identidades no separador" }, "showIdentitiesCurrentTabDesc": { - "message": "List identity items on the Tab page for easy auto-fill." + "message": "Lista os elementos de identidade no separador para fácil auto-completado." }, "clearClipboard": { - "message": "Clear clipboard", + "message": "Limpar portapapeis", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { @@ -685,7 +685,7 @@ "message": "Should Bitwarden remember this password for you?" }, "notificationAddSave": { - "message": "Save" + "message": "Gardar" }, "enableChangedPasswordNotification": { "message": "Ask to update existing login" @@ -706,13 +706,13 @@ "message": "Do you want to update this password in Bitwarden?" }, "notificationChangeSave": { - "message": "Update" + "message": "Actualizar" }, "notificationUnlockDesc": { "message": "Unlock your Bitwarden vault to complete the auto-fill request." }, "notificationUnlock": { - "message": "Unlock" + "message": "Desbloquear" }, "enableContextMenuItem": { "message": "Show context menu options" @@ -731,7 +731,7 @@ "message": "Choose the default way that URI match detection is handled for logins when performing actions such as auto-fill." }, "theme": { - "message": "Theme" + "message": "Tema" }, "themeDesc": { "message": "Change the application's color theme." @@ -740,25 +740,25 @@ "message": "Change the application's color theme. Applies to all logged in accounts." }, "dark": { - "message": "Dark", + "message": "Escuro", "description": "Dark color" }, "light": { - "message": "Light", + "message": "Claro", "description": "Light color" }, "solarizedDark": { - "message": "Solarized dark", + "message": "Solarizado escuro", "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Export vault" + "message": "Exportar caixa forte" }, "fileFormat": { - "message": "File format" + "message": "Formato de ficheiro" }, "warning": { - "message": "WARNING", + "message": "ADVERTENCIA", "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { @@ -777,7 +777,7 @@ "message": "Enter your master password to export your vault data." }, "shared": { - "message": "Shared" + "message": "Compartido" }, "learnOrg": { "message": "Learn about organizations" @@ -789,7 +789,7 @@ "message": "Move to organization" }, "share": { - "message": "Share" + "message": "Compartir" }, "movedItemToOrg": { "message": "$ITEMNAME$ moved to $ORGNAME$", @@ -808,58 +808,58 @@ "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved." }, "learnMore": { - "message": "Learn more" + "message": "Máis información" }, "authenticatorKeyTotp": { - "message": "Authenticator key (TOTP)" + "message": "Clave de autenticación (TOTP)" }, "verificationCodeTotp": { - "message": "Verification code (TOTP)" + "message": "Código de verificación (TOTP)" }, "copyVerificationCode": { - "message": "Copy verification code" + "message": "Copiar código de verificación" }, "attachments": { - "message": "Attachments" + "message": "Anexos" }, "deleteAttachment": { - "message": "Delete attachment" + "message": "Eliminar anexos" }, "deleteAttachmentConfirmation": { - "message": "Are you sure you want to delete this attachment?" + "message": "Estás seguro de que queres eliminar este anexo?" }, "deletedAttachment": { - "message": "Attachment deleted" + "message": "Anexo eliminado" }, "newAttachment": { - "message": "Add new attachment" + "message": "Engadir novo anexo" }, "noAttachments": { - "message": "No attachments." + "message": "Sen anexos." }, "attachmentSaved": { - "message": "Attachment saved" + "message": "Anexo gardado" }, "file": { - "message": "File" + "message": "Ficheiro" }, "selectFile": { - "message": "Select a file" + "message": "Selecciona un ficheiro" }, "maxFileSize": { - "message": "Maximum file size is 500 MB." + "message": "O tamaño máximo de ficheiro é de 500 MB." }, "featureUnavailable": { - "message": "Feature unavailable" + "message": "Característica non dispoñible" }, "encryptionKeyMigrationRequired": { "message": "Encryption key migration required. Please login through the web vault to update your encryption key." }, "premiumMembership": { - "message": "Premium membership" + "message": "Membresía de luxo" }, "premiumManage": { - "message": "Manage membership" + "message": "Xestionar membresía" }, "premiumManageAlert": { "message": "You can manage your membership on the bitwarden.com web vault. Do you want to visit the website now?" @@ -970,13 +970,13 @@ "message": "To start the WebAuthn 2FA verification. Click the button below to open a new tab and follow the instructions provided in the new tab." }, "webAuthnNewTabOpen": { - "message": "Open new tab" + "message": "Abrir novo separador" }, "webAuthnAuthenticate": { - "message": "Authenticate WebAuthn" + "message": "Autenticar con WebAuthn" }, "loginUnavailable": { - "message": "Login unavailable" + "message": "Inicio de sesión non dispoñíbel" }, "noTwoStepProviders": { "message": "This account has two-step login set up, however, none of the configured two-step providers are supported by this web browser." @@ -1021,7 +1021,7 @@ "message": "Use any WebAuthn compatible security key to access your account." }, "emailTitle": { - "message": "Email" + "message": "Correo electrónico" }, "emailDesc": { "message": "Verification codes will be emailed to you." @@ -1039,10 +1039,10 @@ "message": "For advanced users. You can specify the base URL of each service independently." }, "baseUrl": { - "message": "Server URL" + "message": "URL do servidor" }, "apiUrl": { - "message": "API server URL" + "message": "URL do servidor da API" }, "webVaultUrl": { "message": "Web vault server URL" @@ -1073,7 +1073,7 @@ "message": "Edit browser settings." }, "autofillOverlayVisibilityOff": { - "message": "Off", + "message": "Apagado", "description": "Overlay setting select option for disabling autofill overlay" }, "autofillOverlayVisibilityOnFieldFocus": { @@ -1130,35 +1130,35 @@ "message": "Lock the vault" }, "customFields": { - "message": "Custom fields" + "message": "Campos personalizados" }, "copyValue": { - "message": "Copy value" + "message": "Copiar valor" }, "value": { - "message": "Value" + "message": "Valor" }, "newCustomField": { - "message": "New custom field" + "message": "Novo campo personalizado" }, "dragToSort": { - "message": "Drag to sort" + "message": "Arrastra para ordenar" }, "cfTypeText": { - "message": "Text" + "message": "Texto" }, "cfTypeHidden": { - "message": "Hidden" + "message": "Agochado" }, "cfTypeBoolean": { - "message": "Boolean" + "message": "Booleano" }, "cfTypeLinked": { - "message": "Linked", + "message": "Vinculado", "description": "This describes a field that is 'linked' (tied) to another field." }, "linkedValue": { - "message": "Linked value", + "message": "Valor vinculado", "description": "This describes a value that is 'linked' (tied) to another value." }, "popup2faCloseMessage": { @@ -1183,76 +1183,76 @@ "message": "Indicate how many logins you have for the current web page." }, "cardholderName": { - "message": "Cardholder name" + "message": "Nome do titular da tarxeta" }, "number": { - "message": "Number" + "message": "Número" }, "brand": { - "message": "Brand" + "message": "Marca" }, "expirationMonth": { - "message": "Expiration month" + "message": "Mes de expiración" }, "expirationYear": { - "message": "Expiration year" + "message": "Ano de vencemento" }, "expiration": { - "message": "Expiration" + "message": "Vencemento" }, "january": { - "message": "January" + "message": "Xaneiro" }, "february": { - "message": "February" + "message": "Febreiro" }, "march": { - "message": "March" + "message": "Marzo" }, "april": { - "message": "April" + "message": "Abril" }, "may": { - "message": "May" + "message": "Maio" }, "june": { - "message": "June" + "message": "Xuño" }, "july": { - "message": "July" + "message": "Xullo" }, "august": { - "message": "August" + "message": "Agosto" }, "september": { - "message": "September" + "message": "Setembro" }, "october": { - "message": "October" + "message": "Outubro" }, "november": { - "message": "November" + "message": "Novembro" }, "december": { - "message": "December" + "message": "Decembro" }, "securityCode": { - "message": "Security code" + "message": "Código de seguridade" }, "ex": { "message": "ex." }, "title": { - "message": "Title" + "message": "Título" }, "mr": { - "message": "Mr" + "message": "Sr" }, "mrs": { - "message": "Mrs" + "message": "Sra" }, "ms": { - "message": "Ms" + "message": "Srta" }, "dr": { "message": "Dr" @@ -1261,112 +1261,112 @@ "message": "Mx" }, "firstName": { - "message": "First name" + "message": "Nome" }, "middleName": { - "message": "Middle name" + "message": "Segundo nome" }, "lastName": { - "message": "Last name" + "message": "Apelido" }, "fullName": { - "message": "Full name" + "message": "Nome completo" }, "identityName": { - "message": "Identity name" + "message": "Nome de identidade" }, "company": { - "message": "Company" + "message": "Empresa" }, "ssn": { - "message": "Social Security number" + "message": "Número da seguridade social" }, "passportNumber": { - "message": "Passport number" + "message": "Número de pasaporte" }, "licenseNumber": { - "message": "License number" + "message": "Número de licencia" }, "email": { - "message": "Email" + "message": "Correo electrónico" }, "phone": { - "message": "Phone" + "message": "Teléfono" }, "address": { - "message": "Address" + "message": "Enderezo" }, "address1": { - "message": "Address 1" + "message": "Enderezo 1" }, "address2": { - "message": "Address 2" + "message": "Enderezo 2" }, "address3": { - "message": "Address 3" + "message": "Enderezo 3" }, "cityTown": { - "message": "City / Town" + "message": "Localidade" }, "stateProvince": { - "message": "State / Province" + "message": "Estado / Provincia" }, "zipPostalCode": { - "message": "Zip / Postal code" + "message": "Código postal" }, "country": { - "message": "Country" + "message": "País" }, "type": { - "message": "Type" + "message": "Tipo" }, "typeLogin": { - "message": "Login" + "message": "Inicio de sesión" }, "typeLogins": { - "message": "Logins" + "message": "Inicios se sesión" }, "typeSecureNote": { - "message": "Secure note" + "message": "Nota segura" }, "typeCard": { - "message": "Card" + "message": "Tarxeta" }, "typeIdentity": { - "message": "Identity" + "message": "Identidade" }, "passwordHistory": { - "message": "Password history" + "message": "Historial de contrasinais" }, "back": { - "message": "Back" + "message": "Atrás" }, "collections": { - "message": "Collections" + "message": "Coleccións" }, "favorites": { - "message": "Favorites" + "message": "Favoritos" }, "popOutNewWindow": { "message": "Pop out to a new window" }, "refresh": { - "message": "Refresh" + "message": "Actualizar" }, "cards": { - "message": "Cards" + "message": "Tarxetas" }, "identities": { - "message": "Identities" + "message": "Identidades" }, "logins": { - "message": "Logins" + "message": "Inicios de sesión" }, "secureNotes": { - "message": "Secure notes" + "message": "Notas seguras" }, "clear": { - "message": "Clear", + "message": "Limpar", "description": "To clear something out. example: To clear browser history." }, "checkPassword": { @@ -1385,25 +1385,25 @@ "message": "This password was not found in any known data breaches. It should be safe to use." }, "baseDomain": { - "message": "Base domain", + "message": "Dominio base", "description": "Domain name. Ex. website.com" }, "domainName": { - "message": "Domain name", + "message": "Nome de dominio", "description": "Domain name. Ex. website.com" }, "host": { - "message": "Host", + "message": "Anfitrión", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { - "message": "Exact" + "message": "Exacto" }, "startsWith": { - "message": "Starts with" + "message": "Comeza por" }, "regEx": { - "message": "Regular expression", + "message": "Expresión regular", "description": "A programming term, also known as 'RegEx'." }, "matchDetection": { @@ -1426,20 +1426,20 @@ "description": "The URI of one of the current open tabs in the browser." }, "organization": { - "message": "Organization", + "message": "Organización", "description": "An entity of multiple related people (ex. a team or business organization)." }, "types": { - "message": "Types" + "message": "Tipos" }, "allItems": { - "message": "All items" + "message": "Todos os elementos" }, "noPasswordsInList": { - "message": "There are no passwords to list." + "message": "Non hai contrasinais que listar." }, "remove": { - "message": "Remove" + "message": "Eliminar" }, "default": { "message": "Default" @@ -1524,10 +1524,10 @@ "message": "You must select at least one collection." }, "cloneItem": { - "message": "Clone item" + "message": "Clonar elemento" }, "clone": { - "message": "Clone" + "message": "Clonar" }, "passwordGeneratorPolicyInEffect": { "message": "One or more organization policies are affecting your generator settings." @@ -1536,11 +1536,11 @@ "message": "Vault timeout action" }, "lock": { - "message": "Lock", + "message": "Bloquear", "description": "Verb form: to make secure or inaccesible by" }, "trash": { - "message": "Trash", + "message": "Lixo", "description": "Noun: a special folder to hold deleted items" }, "searchTrash": { @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -1764,21 +1770,21 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "searchSends": { - "message": "Search Sends", + "message": "Buscar Sends", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "addSend": { - "message": "Add Send", + "message": "Engadir Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendTypeText": { - "message": "Text" + "message": "Texto" }, "sendTypeFile": { - "message": "File" + "message": "Ficheiro" }, "allSends": { - "message": "All Sends", + "message": "Todos os Sends", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCountReached": { @@ -1786,7 +1792,7 @@ "description": "This text will be displayed after a Send has been accessed the maximum amount of times." }, "expired": { - "message": "Expired" + "message": "Caducado" }, "pendingDeletion": { "message": "Pending deletion" @@ -1795,14 +1801,14 @@ "message": "Password protected" }, "copySendLink": { - "message": "Copy Send link", + "message": "Copiar ligazón Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { "message": "Remove Password" }, "delete": { - "message": "Delete" + "message": "Eliminar" }, "removedPassword": { "message": "Password removed" @@ -1859,10 +1865,10 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "oneDay": { - "message": "1 day" + "message": "1 día" }, "days": { - "message": "$DAYS$ days", + "message": "$DAYS$ días", "placeholders": { "days": { "content": "$1", @@ -1871,7 +1877,7 @@ } }, "custom": { - "message": "Custom" + "message": "Personalizado" }, "maximumAccessCount": { "message": "Maximum Access Count" @@ -1907,14 +1913,14 @@ "message": "Current access count" }, "createSend": { - "message": "New Send", + "message": "Novo Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { - "message": "New password" + "message": "Novo contrasinal" }, "sendDisabled": { - "message": "Send removed", + "message": "Send eliminado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { @@ -1922,11 +1928,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { - "message": "Send created", + "message": "Send creado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Send saved", + "message": "Send gardado", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { @@ -2027,10 +2033,10 @@ "description": "Default title for the user verification dialog." }, "hours": { - "message": "Hours" + "message": "Horas" }, "minutes": { - "message": "Minutes" + "message": "Minutos" }, "vaultTimeoutPolicyInEffect": { "message": "Your organization policies have set your maximum allowed vault timeout to $HOURS$ hour(s) and $MINUTES$ minute(s).", @@ -2129,7 +2135,7 @@ } }, "error": { - "message": "Error" + "message": "Erro" }, "regenerateUsername": { "message": "Regenerate username" @@ -2154,13 +2160,13 @@ "message": "Use your domain's configured catch-all inbox." }, "random": { - "message": "Random" + "message": "Aleatorio" }, "randomWord": { - "message": "Random word" + "message": "Palabra aleatoria" }, "websiteName": { - "message": "Website name" + "message": "Nome do sitio web" }, "whatWouldYouLikeToGenerate": { "message": "What would you like to generate?" @@ -2177,15 +2183,117 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { - "message": "Hostname", + "message": "Nome do anfitrión", "description": "Part of a URL." }, "apiAccessToken": { - "message": "API Access Token" + "message": "Token de acceso á API" }, "apiKey": { - "message": "API Key" + "message": "Clave da API" }, "ssoKeyConnectorError": { "message": "Key connector error: make sure key connector is available and working correctly." @@ -2221,7 +2329,7 @@ "message": "Server version" }, "selfHostedServer": { - "message": "self-hosted" + "message": "autoaloxado" }, "thirdParty": { "message": "Third-party" @@ -2389,17 +2497,17 @@ "message": "Organization SSO identifier is required." }, "eu": { - "message": "EU", + "message": "UE", "description": "European Union" }, "accessDenied": { "message": "Access denied. You do not have permission to view this page." }, "general": { - "message": "General" + "message": "Xeral" }, "display": { - "message": "Display" + "message": "Amosar" }, "accountSuccessfullyCreated": { "message": "Account successfully created!" @@ -3019,7 +3127,7 @@ "message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console." }, "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: O 16 de maio de 2024, os elementos de organización non asignados non serán visíbeis na vista de Todas as caixas fortes e só serán accesíbeis a través da Consola de Administrador." }, "unassignedItemsBannerCTAPartOne": { "message": "Assign these items to a collection from the", @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index d8b9b1ec9ee..e13e60a7040 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "מכשיר זה לא תומך בזיהוי ביומטרי בדפדפן." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "יצירת כינוי דוא״ל עם שירות העברה חיצוני." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "שם מארח", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 8b08a8a5c21..1c28b559011 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "ब्राउज़र बॉयोमीट्रिक्स इस डिवाइस पर समर्थित नहीं है।" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index d00e32b1397..badd7e72bd6 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometrija preglednika nije podržana na ovom uređaju." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrija neuspješna" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generiraj pseudonim e-pošte s vanjskom uslugom prosljeđivanja." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Naziv poslužitelja", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index 65342fa51b0..d15fc585bbd 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "A böngésző biometrikus adatait ez az eszköz nem támogatja." }, + "biometricsNotUnlockedTitle": { + "message": "A felhasználó zárolva van vagy kijelentkezett." + }, + "biometricsNotUnlockedDesc": { + "message": "Oldjuk fel a felhasználó zárolását az asztali alkalmazásban és próbáljuk újra." + }, "biometricsFailedTitle": { "message": "A biometria nem sikerült." }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Email álnév generálása külső továbbító szolgáltatással." }, + "forwarderError": { + "message": "$SERVICENAME$ hiba: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webhely: $WEBSITE$. Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "$SERVICENAME$ API vezérjel érvénytelen.", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "$SERVICENAME$ API vezérjel érvénytelen: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nem lehet beolvasni $SERVICENAME$ maszkolt email fiók azonosítót.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "$SERVICENAME$ domain érvénytelen.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "$SERVICENAME$ webcím érvénytelen.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ismeretlen $SERVICENAME$ hiba történt.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ismeretlen továbbító: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Kiszolglónév", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Hiba történt a célmappa hozzárendelése során." + }, + "new": { + "message": "Új" } } diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index d0c317a1773..2357fa81ef5 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -3,11 +3,11 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden Pengelola Sandi", "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", + "message": "Bitwarden memudahkan Anda menyimpan kata sandi, kata kunci, dan informasi sensitif dimanapun Anda berada", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -92,13 +92,13 @@ "message": "Isi otomatis" }, "autoFillLogin": { - "message": "Auto-fill login" + "message": "Autofill masuk" }, "autoFillCard": { - "message": "Auto-fill card" + "message": "Autofill kartu" }, "autoFillIdentity": { - "message": "Auto-fill identity" + "message": "Autofill identitas" }, "generatePasswordCopied": { "message": "Membuat Kata Sandi (tersalin)" @@ -110,19 +110,19 @@ "message": "Tidak ada info masuk yang cocok." }, "noCards": { - "message": "No cards" + "message": "Tanpa kartu" }, "noIdentities": { - "message": "No identities" + "message": "Tanpa identitas" }, "addLoginMenu": { - "message": "Add login" + "message": "Tambahkan Info Masuk" }, "addCardMenu": { - "message": "Add card" + "message": "Tambahkan kartu" }, "addIdentityMenu": { - "message": "Add identity" + "message": "Tambahkan identitas" }, "unlockVaultMenu": { "message": "Buka brankas Anda" @@ -173,10 +173,10 @@ "message": "Ubah Kata Sandi Utama" }, "continueToWebApp": { - "message": "Continue to web app?" + "message": "Lanjut ke aplikasi web?" }, "changeMasterPasswordOnWebConfirmation": { - "message": "You can change your master password on the Bitwarden web app." + "message": "Anda dapat merubah sandi utama di aplikasi Bitwarden web." }, "fingerprintPhrase": { "message": "Frasa Sidik Jari", @@ -226,13 +226,13 @@ "message": "Bantuan & Umpan Balik" }, "helpCenter": { - "message": "Bitwarden Help center" + "message": "Pusat Bantuan Bitwarden" }, "communityForums": { - "message": "Explore Bitwarden community forums" + "message": "Telusuri forum Bitwarden" }, "contactSupport": { - "message": "Contact Bitwarden support" + "message": "Kontak dukungan Bitwarden" }, "sync": { "message": "Sinkronisasi" @@ -275,7 +275,7 @@ "message": "Panjang" }, "passwordMinLength": { - "message": "Minimum password length" + "message": "Panjang kata sandi minimum" }, "uppercase": { "message": "Huruf besar (A-Z)" @@ -333,7 +333,7 @@ "message": "Kata Sandi" }, "totp": { - "message": "Authenticator secret" + "message": "Kode Autentikator" }, "passphrase": { "message": "Frasa Sandi" @@ -375,19 +375,19 @@ "message": "Lainnya" }, "unlockMethods": { - "message": "Unlock options" + "message": "Pilihan Penguncian" }, "unlockMethodNeededToChangeTimeoutActionDesc": { - "message": "Set up an unlock method to change your vault timeout action." + "message": "Mengatur metode pembukaan kunci untuk mengubah tindakan batas waktu brankas Anda." }, "unlockMethodNeeded": { - "message": "Set up an unlock method in Settings" + "message": "Mengatur metode penguncian di Pengaturan" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Batas waktu sesi" }, "otherOptions": { - "message": "Other options" + "message": "Opsi lainnya" }, "rateExtension": { "message": "Nilai Ekstensi" @@ -430,7 +430,7 @@ "message": "Kunci Sekarang" }, "lockAll": { - "message": "Lock all" + "message": "Kunci semua" }, "immediately": { "message": "Segera" @@ -490,10 +490,10 @@ "message": "Kata sandi utama diperlukan." }, "confirmMasterPasswordRequired": { - "message": "Master password retype is required." + "message": "Sandi utama diperlukan." }, "masterPasswordMinlength": { - "message": "Master password must be at least $VALUE$ characters long.", + "message": "Kata sandi utama harus $VALUE$ karakter.", "description": "The Master Password must be at least a specific number of characters long.", "placeholders": { "value": { @@ -509,10 +509,10 @@ "message": "Akun baru Anda telah dibuat! Sekarang Anda bisa masuk." }, "youSuccessfullyLoggedIn": { - "message": "You successfully logged in" + "message": "Anda berhasil masuk" }, "youMayCloseThisWindow": { - "message": "You may close this window" + "message": "Anda dapat menutup jendela ini" }, "masterPassSent": { "message": "Kami telah mengirimi Anda email dengan petunjuk sandi utama Anda." @@ -537,16 +537,16 @@ "message": "Tidak dapat mengisi otomatis item yang dipilih pada laman ini. Salin dan tempel informasinya sebagai gantinya." }, "totpCaptureError": { - "message": "Unable to scan QR code from the current webpage" + "message": "Tidak dapat memindai kode QR dari laman ini" }, "totpCaptureSuccess": { - "message": "Authenticator key added" + "message": "Kunci Autentikator ditambahkan" }, "totpCapture": { - "message": "Scan authenticator QR code from current webpage" + "message": "Pindai kode QR autentikator dari laman ini" }, "copyTOTP": { - "message": "Copy Authenticator key (TOTP)" + "message": "Salin kunci Autentikator (TOTP)" }, "loggedOut": { "message": "Keluar" @@ -653,7 +653,7 @@ "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { - "message": "Ask to add login" + "message": "Tanya untuk penambahan login" }, "addLoginNotificationDesc": { "message": "\"Notifikasi Penambahan Info Masuk\" secara otomatis akan meminta Anda untuk menyimpan info masuk baru ke brankas Anda saat Anda masuk untuk pertama kalinya." @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometrik peramban tidak didukung di perangkat ini." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 94e0e479151..7f33070b024 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "L'autenticazione biometrica del browser non è supportata su questo dispositivo." }, + "biometricsNotUnlockedTitle": { + "message": "Utente bloccato o uscito" + }, + "biometricsNotUnlockedDesc": { + "message": "Sblocca questo utente nell'applicazione desktop e riprova." + }, "biometricsFailedTitle": { "message": "Autenticazione biometrica fallita" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Genera un alias email con un servizio di inoltro esterno." }, + "forwarderError": { + "message": "Errore $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Sito web: $WEBSITE$. Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token API $SERVICENAME$ non valido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token API $SERVICENAME$ non valido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Impossibile ottenere l'ID dell'account email mascherato di $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Dominio $SERVICENAME$ non valido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ non valido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Errore di $SERVICENAME$ sconosciuto.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Mittente sconosciuto: \"$SERVICENAME$\".", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome host", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Errore nell'assegnazione della cartella di destinazione." + }, + "new": { + "message": "Nuovo" } } diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 0bfe8a84b3d..48abec40543 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -3,11 +3,11 @@ "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", + "message": "自宅、職場、または外出先でも、Bitwarden はすべてのパスワード、パスキー、機密情報を簡単に保護します。", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "このデバイスではブラウザの生体認証に対応していません。" }, + "biometricsNotUnlockedTitle": { + "message": "ユーザーがロックまたはログアウトしました" + }, + "biometricsNotUnlockedDesc": { + "message": "デスクトップアプリでこのユーザーのロックを解除して、もう一度やり直してください。" + }, "biometricsFailedTitle": { "message": "生体認証に失敗しました" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "外部転送サービスを使用してメールエイリアスを生成します。" }, + "forwarderError": { + "message": "$SERVICENAME$ エラー: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "ウェブサイト: $WEBSITE$ Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "不正な$SERVICENAME$ API トークン", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "不正な$SERVICENAME$ API トークン: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ マスク済みメールアカウント ID を取得できませんでした。", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "不正な $SERVICENAME$ ドメインです。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "不正な $SERVICENAME$ URL です。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "不明な $SERVICENAME$ エラーが起きました。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "不明な転送先: '$SERVICENAME$'", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "ホスト名", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "ターゲットフォルダーの割り当てに失敗しました。" + }, + "new": { + "message": "新規作成" } } diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index 1ee37ad5de7..a65e2eaa46a 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 275723e0cf4..b9be5eae61b 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "ಬ್ರೌಸರ್ ಬಯೋಮೆಟ್ರಿಕ್ಸ್ ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index 116c87a3116..6f0bfe9756e 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "이 기기에서는 생체 인식이 지원되지 않습니다." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index c160ae5788b..48e4342527c 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Šiame įrenginyje biometrikos negalima naudoti." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrika nepavyko" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Sugeneruoti el. pašto slapyvardį su išorine persiuntimo paslauga." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Pagrindinio kompiuterio vardas", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Klaida priskiriant tikslinį aplanką." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index c7ec65403d9..ea7bca0b09f 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -3,11 +3,11 @@ "message": "Bitwarden" }, "extName": { - "message": "Bitwarden Password Manager", + "message": "Bitwarden paroļu pārvaldnieks", "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", + "message": "Bitwarden viegli aizsargā visas paroles, paroļu atslēgas un jutīgu informāciju mājās, darbā vai ceļā", "description": "Extension description, MUST be less than 112 characters (Safari restriction)" }, "loginOrCreateNewAccount": { @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Šajā ierīcē netiek atbalstīta pārlūka biometrija." }, + "biometricsNotUnlockedTitle": { + "message": "Lietotājs aizslēgts vai izrakstījies" + }, + "biometricsNotUnlockedDesc": { + "message": "Lūgums atslēgt šo lietotāju darbvirsmas lietotnē un mēģināt vēlreiz." + }, "biometricsFailedTitle": { "message": "Biometrija neizdevās" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Izveidot e-pastu aizstājvārdu ar ārēju pārvirzīšanas pakalpojumu." }, + "forwarderError": { + "message": "$SERVICENAME$ kļūda: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Tīmekļvietne: $WEBSITE$. Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nederīga $SERVICENAME$ API pilnvara", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nederīga $SERVICENAME$ API pilnvara: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Neizdevās iegūt $SERVICENAME$ aizsegta e-pasta konta Id.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nederīgs $SERVICENAME$ domēna vārds.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nederīgs $SERVICENAME$ URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Atgadījās nezināma $SERVICENAME$ kļūda.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Nezināms pārsūtītājs: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Resursdatora nosaukums", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Kļūda mērķa mapes piešķiršanā." + }, + "new": { + "message": "Jauns" } } diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 0d7049b8552..2ba4c54ec16 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index f44649d1c30..4994f4c0646 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 8d54140b0e6..767c4983295 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometri i nettleseren støttes ikke på denne enheten." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometri mislyktes" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generer et e-postalias med en ekstern videresendingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Vertsnavn ", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 0319dea3a41..e56e24e3f79 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Dit apparaat ondersteunt geen browserbiometrie." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrie mislukt" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Genereer een e-mailalias met een externe doorschakelservice." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostnaam", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Fout bij toewijzen doelmap." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index b34ce5bf669..bfcb50d20fa 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Dane biometryczne przeglądarki nie są obsługiwane na tym urządzeniu." }, + "biometricsNotUnlockedTitle": { + "message": "Użytkownik zablokowany lub wylogowany" + }, + "biometricsNotUnlockedDesc": { + "message": "Odblokuj tego użytkownika w aplikacji desktopowej i spróbuj ponownie." + }, "biometricsFailedTitle": { "message": "Dane biometryczne są błędne" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Wygeneruj alias adresu e-mail z zewnętrznej usługi przekierowania." }, + "forwarderError": { + "message": "Błąd $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Wygenerowane przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Strona internetowa: $WEBSITE$. Wygenerowano przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nieprawidłowy token API dla $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nieprawidłowy token API dla $SERVICENAME$, błąd: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nie można uzyskać ID maskowanego konta e-mail dla $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nieprawidłowa domena $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nieprawidłowy adres URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Wystąpił nieznany błąd w $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nazwa hosta", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Wystąpił błąd podczas przypisywania folderu." + }, + "new": { + "message": "Nowy" } } diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index c9ade42eb5d..b0b154b4c3b 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -375,7 +375,7 @@ "message": "Outros" }, "unlockMethods": { - "message": "Unlock options" + "message": "Opções de desbloqueio" }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Configure um método de desbloqueio para alterar o tempo limite do cofre." @@ -384,10 +384,10 @@ "message": "Configure um método de desbloqueio nas Configurações" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Tempo limite da sessão" }, "otherOptions": { - "message": "Other options" + "message": "Outras opções" }, "rateExtension": { "message": "Avaliar a Extensão" @@ -697,10 +697,10 @@ "message": "Pedir para atualizar a senha de uma credencial quando uma alteração for detectada em um site. Aplica-se a todas as contas conectadas." }, "enableUsePasskeys": { - "message": "Pedir para salvar e usar as senhas" + "message": "Pedir para salvar e usar chaves de acesso" }, "usePasskeysDesc": { - "message": "Pedir para salvar novas senhas ou entrar com as senhas armazenadas no seu cofre. Aplica-se a todas as contas conectadas." + "message": "Pedir para salvar novas chaves de acesso ou entrar com as mesmas armazenadas no seu cofre. Aplica-se a todas as contas conectadas." }, "notificationChangeDesc": { "message": "Você quer atualizar esta senha no Bitwarden?" @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "A biometria com o navegador não é suportada neste dispositivo." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometria falhou" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Gere um apelido de e-mail com um serviço de encaminhamento externo." }, + "forwarderError": { + "message": "Erro $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token de API $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token de API $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter a máscara do ID da conta de email $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ inválida.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro $SERVICENAME$ desconhecido.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Encaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome do host", "description": "Part of a URL." @@ -2795,22 +2903,22 @@ "message": "Chave de acesso" }, "passkeyNotCopied": { - "message": "A senha não será copiada" + "message": "A chave de acesso não será copiada" }, "passkeyNotCopiedAlert": { - "message": "A senha não será copiada para o item clonado. Deseja continuar clonando este item?" + "message": "A chave de acesso não será copiada para o item clonado. Deseja continuar clonando este item?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { - "message": "Verificação exigida pelo site inicial. Esse recurso ainda não está implementado para contas sem senha mestra." + "message": "Verificação requerida pelo site que a iniciou. Esse recurso ainda não está implementado para contas sem senha mestra." }, "logInWithPasskey": { - "message": "Fazer login com a senha?" + "message": "Fazer login com chave de acesso?" }, "passkeyAlreadyExists": { - "message": "Uma senha já existe para este aplicativo." + "message": "Uma chave de acesso já existe para este aplicativo." }, "noPasskeysFoundForThisApplication": { - "message": "Nenhuma senha encontrada para este aplicativo." + "message": "Nenhuma chave de acesso encontrada para este aplicativo." }, "noMatchingPasskeyLogin": { "message": "Você não tem um login correspondente para este site." @@ -2819,22 +2927,22 @@ "message": "Confirmar" }, "savePasskey": { - "message": "Salvar senha" + "message": "Salvar chave de acesso" }, "savePasskeyNewLogin": { - "message": "Salvar senha como novo login" + "message": "Salvar chave de acesso como um novo login" }, "choosePasskey": { "message": "Escolha um login para salvar esta chave de acesso" }, "passkeyItem": { - "message": "Passkey Item" + "message": "Item de chave de acesso" }, "overwritePasskey": { - "message": "Sobrescrever senha?" + "message": "Sobrescrever chave de acesso?" }, "overwritePasskeyAlert": { - "message": "Este item já contém uma senha. Tem certeza que deseja substituir a senha de acesso atual?" + "message": "Este item já contém uma chave de acesso. Tem certeza que deseja substituir a atual?" }, "featureNotSupported": { "message": "Recurso ainda não suportado" @@ -3010,7 +3118,7 @@ "message": "Sucesso" }, "removePasskey": { - "message": "Remover senha" + "message": "Remover chave de acesso" }, "passkeyRemoved": { "message": "Chave de acesso removida" @@ -3033,18 +3141,21 @@ "message": "Painel de administração" }, "accountSecurity": { - "message": "Account security" + "message": "Segurança da conta" }, "notifications": { - "message": "Notifications" + "message": "Notificações" }, "appearance": { - "message": "Appearance" + "message": "Aparência" }, "errorAssigningTargetCollection": { "message": "Erro ao atribuir coleção de destino." }, "errorAssigningTargetFolder": { "message": "Erro ao atribuir pasta de destino." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 3cb55214d6b..db85e2dd286 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "A biometria do navegador não é suportada neste dispositivo." }, + "biometricsNotUnlockedTitle": { + "message": "Utilizador bloqueado ou com sessão terminada" + }, + "biometricsNotUnlockedDesc": { + "message": "Por favor, desbloqueie este utilizador na aplicação para computador e tente novamente." + }, "biometricsFailedTitle": { "message": "Falha na biometria" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Gerar um alias de e-mail com um serviço de reencaminhamento externo." }, + "forwarderError": { + "message": "Erro no $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token da API de $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token da API de $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter o ID da conta de e-mail mascarada de $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio de $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL de $SERVICENAME$ inválido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro desconhecido de $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Reencaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome de domínio", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Erro ao atribuir a pasta de destino." + }, + "new": { + "message": "Novo" } } diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 8f02fd076db..af6b4fce48a 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometria browserului nu este acceptată pe acest dispozitiv." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrica a eșuat" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generați un alias de e-mail cu un serviciu de redirecționare extern." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nume server", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 8f0d211056f..3e46637299c 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Биометрия в браузере не поддерживается этом устройстве." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Сбой биометрии" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Создать псевдоним электронной почты для внешней службы пересылки." }, + "forwarderError": { + "message": "Ошибка $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Сайт: $WEBSITE$. Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неверный токен API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неверный токен $SERVICENAME$ API: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не удалось получить скрытый идентификатор email аккаунта $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Недопустимый домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Некорректный URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Произошла неизвестная ошибка $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестный форвардер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Имя хоста", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Ошибка при назначении целевой папки." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index f4f13a4f559..87ace5e49cf 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "බ්රව්සර් biometrics මෙම උපාංගය මත සහය නොදක්වයි." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index db11a308559..180bbfe6af9 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometria v prehliadači nie je podporovaná na tomto zariadení." }, + "biometricsNotUnlockedTitle": { + "message": "Používateľ je zamknutý alebo odhlásený" + }, + "biometricsNotUnlockedDesc": { + "message": "Prosím, odomknite tohto používateľa v počítačovej aplikácii a skúste to znova." + }, "biometricsFailedTitle": { "message": "Biometria zlyhala" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Vytvoriť e-mailový alias pomocou externej služby preposielania." }, + "forwarderError": { + "message": "$SERVICENAME$ chyba: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Vygenerované Bitwardenom.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webstránka: $WEBSITE$. Vygenerované Bitwardenom.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Neplatný token API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Neplatný token API $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nepodarilo sa získať ID maskovaného e-mailového účtu $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Neplatná doména $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Neplatná url adresa $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Vyskytla sa neznáma chyba $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Nepodporovaná služba: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Názov hostiteľa", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Chyba pri priraďovaní cieľového priečinka." + }, + "new": { + "message": "Nová" } } diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index b098546de2d..c011d8727cd 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 621bd5953f3..9976384e96a 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -375,7 +375,7 @@ "message": "Остало" }, "unlockMethods": { - "message": "Unlock options" + "message": "Опције деблокирања" }, "unlockMethodNeededToChangeTimeoutActionDesc": { "message": "Подесите метод откључавања да бисте променили радњу временског ограничења сефа." @@ -384,10 +384,10 @@ "message": "Подесите метод откључавања у подешавањима" }, "sessionTimeoutHeader": { - "message": "Session timeout" + "message": "Истек сесије" }, "otherOptions": { - "message": "Other options" + "message": "Остале опције" }, "rateExtension": { "message": "Оцени овај додатак" @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Биометрија прегледача није подржана на овом уређају." }, + "biometricsNotUnlockedTitle": { + "message": "Корисник је закључан или одјављен" + }, + "biometricsNotUnlockedDesc": { + "message": "Откључајте овог корисника у десктоп апликацији и покушајте поново." + }, "biometricsFailedTitle": { "message": "Биометрија није успела" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Генеришите псеудоним е-поште помоћу екстерне услуге прослеђивања." }, + "forwarderError": { + "message": "$SERVICENAME$ грешка: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Вебсајт: $WEBSITE$. Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Погрешан АПИ токен $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Погрешан АПИ токен $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Није могуће добити ИД налога маскираног имејла $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Погрешан домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Погрешан УРЛ $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Непозната грешка $SERVICENAME$-а.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Непознати шпедитер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име домаћина", "description": "Part of a URL." @@ -3033,18 +3141,21 @@ "message": "Администраторска конзола" }, "accountSecurity": { - "message": "Account security" + "message": "Безбедност налога" }, "notifications": { - "message": "Notifications" + "message": "Обавештења" }, "appearance": { - "message": "Appearance" + "message": "Изглед" }, "errorAssigningTargetCollection": { "message": "Грешка при додељивању циљне колекције." }, "errorAssigningTargetFolder": { "message": "Грешка при додељивању циљне фасцикле." + }, + "new": { + "message": "Ново" } } diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 96776e70601..0a183ae000a 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Biometri i webbläsaren stöds inte på den här enheten." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometri misslyckades" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Skapa ett e-postalias med en extern vidarebefordranstjänst." }, + "forwarderError": { + "message": "$SERVICENAME$-fel: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ogiltig $SERVICENAME$-domän.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ogiltig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Värdnamn", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index b45fdef39e8..0a54e1026a0 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index 6318d27189e..2d409fd06ff 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Browser biometrics is not supported on this device." }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index e91397a6e21..4864d6895da 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Tarayıcı biyometrisi bu cihazda desteklenmiyor." }, + "biometricsNotUnlockedTitle": { + "message": "Kullanıcı kilitlendi ve oturumu kapatıldı" + }, + "biometricsNotUnlockedDesc": { + "message": "Lütfen masaüstü uygulamasından bu kullanıcının kilidini açıp yeniden deneyin." + }, "biometricsFailedTitle": { "message": "Biyometri doğrulanamadı" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Harici bir yönlendirme servisiyle e-posta maskesi oluştur." }, + "forwarderError": { + "message": "$SERVICENAME$ hatası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Web sitesi: $WEBSITE$. Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Sunucu", "description": "Part of a URL." @@ -3036,15 +3144,18 @@ "message": "Hesap güvenliği" }, "notifications": { - "message": "Notifications" + "message": "Bildirimler" }, "appearance": { - "message": "Appearance" + "message": "Görünüm" }, "errorAssigningTargetCollection": { - "message": "Hedef koleksiyonu atama hatası." + "message": "Hedef koleksiyon atama hatası." }, "errorAssigningTargetFolder": { - "message": "Hedef klasörü atama hatası." + "message": "Hedef klasör atama hatası." + }, + "new": { + "message": "Yeni" } } diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index a92a68571e7..91e6663f4e8 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Біометрія в браузері не підтримується на цьому пристрої." }, + "biometricsNotUnlockedTitle": { + "message": "Користувач заблокований або вийшов із системи" + }, + "biometricsNotUnlockedDesc": { + "message": "Розблокуйте цього користувача в програмі для комп'ютера і повторіть спробу." + }, "biometricsFailedTitle": { "message": "Збій біометрії" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Згенеруйте псевдонім е-пошти зі стороннім сервісом пересилання." }, + "forwarderError": { + "message": "Помилка $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Згенеровано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Вебсайт: $WEBSITE$. Згенеровано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Недійсний токен API для $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Недійсний токен API для $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не вдалося отримати ідентифікатор замаскованої е-пошти облікового запису для $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Недійсний домен для $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Недійсна URL-адреса для $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Сталася невідома помилка $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Невідомий засіб переспрямування: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ім'я вузла", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Помилка призначення цільової теки." + }, + "new": { + "message": "Новий" } } diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index 77ce3ea507a..13d89dae94d 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "Nhận dạng sinh trắc học trên trình duyệt không được hỗ trợ trên thiết bị này" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "Biometrics failed" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Tên máy chủ", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index bedd9933838..4da1ecb4067 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "此设备不支持浏览器生物识别。" }, + "biometricsNotUnlockedTitle": { + "message": "用户已锁定或已注销" + }, + "biometricsNotUnlockedDesc": { + "message": "请在桌面应用程序中解锁此用户,然后重试。" + }, "biometricsFailedTitle": { "message": "生物识别失败" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "使用外部转发服务生成一个电子邮件别名。" }, + "forwarderError": { + "message": "$SERVICENAME$ 错误:$ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "网站:$WEBSITE$。由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "无效的 $SERVICENAME$ API 令牌", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "无效的 $SERVICENAME$ API 令牌:$ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "无效的 $SERVICENAME$ 域名。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "无效的 $SERVICENAME$ URL。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "发生未知的 $SERVICENAME$ 错误。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "未知的转发服务:$SERVICENAME$。", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主机名", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "分配目标文件夹时出错。" + }, + "new": { + "message": "新建" } } diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 4519e879818..1f65928e4b8 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -1714,6 +1714,12 @@ "biometricsNotSupportedDesc": { "message": "此裝置不支援瀏覽器生物特徵辨識。" }, + "biometricsNotUnlockedTitle": { + "message": "User locked or logged out" + }, + "biometricsNotUnlockedDesc": { + "message": "Please unlock this user in the desktop application and try again." + }, "biometricsFailedTitle": { "message": "生物特徵辨識失敗" }, @@ -2177,6 +2183,108 @@ "forwardedEmailDesc": { "message": "使用外部轉寄服務產生一個電子郵件別名。" }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主機名稱", "description": "Part of a URL." @@ -3046,5 +3154,8 @@ }, "errorAssigningTargetFolder": { "message": "Error assigning target folder." + }, + "new": { + "message": "New" } } diff --git a/apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts b/apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts deleted file mode 100644 index b7f6f98ea23..00000000000 --- a/apps/browser/src/admin-console/background/service-factories/organization-service.factory.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service"; - -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory"; -import { StateServiceInitOptions } from "../../../platform/background/service-factories/state-service.factory"; - -type OrganizationServiceFactoryOptions = FactoryOptions; - -export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions & - StateServiceInitOptions; - -export function organizationServiceFactory( - cache: { organizationService?: AbstractOrganizationService } & CachedServices, - opts: OrganizationServiceInitOptions, -): Promise { - return factory( - cache, - "organizationService", - opts, - async () => new OrganizationService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts b/apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts deleted file mode 100644 index b00693bd564..00000000000 --- a/apps/browser/src/admin-console/background/service-factories/policy-service.factory.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PolicyService as AbstractPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -import { - organizationServiceFactory, - OrganizationServiceInitOptions, -} from "./organization-service.factory"; - -type PolicyServiceFactoryOptions = FactoryOptions; - -export type PolicyServiceInitOptions = PolicyServiceFactoryOptions & - StateProviderInitOptions & - OrganizationServiceInitOptions; - -export function policyServiceFactory( - cache: { policyService?: AbstractPolicyService } & CachedServices, - opts: PolicyServiceInitOptions, -): Promise { - return factory( - cache, - "policyService", - opts, - async () => - new PolicyService( - await stateProviderFactory(cache, opts), - await organizationServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/account-service.factory.ts b/apps/browser/src/auth/background/service-factories/account-service.factory.ts deleted file mode 100644 index 9b7ad05ec49..00000000000 --- a/apps/browser/src/auth/background/service-factories/account-service.factory.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service"; - -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "../../../platform/background/service-factories/global-state-provider.factory"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - MessagingServiceInitOptions, - messagingServiceFactory, -} from "../../../platform/background/service-factories/messaging-service.factory"; - -type AccountServiceFactoryOptions = FactoryOptions; - -export type AccountServiceInitOptions = AccountServiceFactoryOptions & - MessagingServiceInitOptions & - LogServiceInitOptions & - GlobalStateProviderInitOptions; - -export function accountServiceFactory( - cache: { accountService?: AccountService } & CachedServices, - opts: AccountServiceInitOptions, -): Promise { - return factory( - cache, - "accountService", - opts, - async () => - new AccountServiceImplementation( - await messagingServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await globalStateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/auth-request-service.factory.ts b/apps/browser/src/auth/background/service-factories/auth-request-service.factory.ts deleted file mode 100644 index c18fd1a112a..00000000000 --- a/apps/browser/src/auth/background/service-factories/auth-request-service.factory.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { AuthRequestService, AuthRequestServiceAbstraction } from "@bitwarden/auth/common"; - -import { - apiServiceFactory, - ApiServiceInitOptions, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - appIdServiceFactory, - AppIdServiceInitOptions, -} from "../../../platform/background/service-factories/app-id-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - FactoryOptions, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory"; -import { - internalMasterPasswordServiceFactory, - MasterPasswordServiceInitOptions, -} from "./master-password-service.factory"; - -type AuthRequestServiceFactoryOptions = FactoryOptions; - -export type AuthRequestServiceInitOptions = AuthRequestServiceFactoryOptions & - AppIdServiceInitOptions & - AccountServiceInitOptions & - MasterPasswordServiceInitOptions & - CryptoServiceInitOptions & - ApiServiceInitOptions & - StateProviderInitOptions; - -export function authRequestServiceFactory( - cache: { authRequestService?: AuthRequestServiceAbstraction } & CachedServices, - opts: AuthRequestServiceInitOptions, -): Promise { - return factory( - cache, - "authRequestService", - opts, - async () => - new AuthRequestService( - await appIdServiceFactory(cache, opts), - await accountServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await apiServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts b/apps/browser/src/auth/background/service-factories/auth-service.factory.ts deleted file mode 100644 index f600efa18d5..00000000000 --- a/apps/browser/src/auth/background/service-factories/auth-service.factory.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { AuthService as AbstractAuthService } from "@bitwarden/common/auth/abstractions/auth.service"; -import { AuthService } from "@bitwarden/common/auth/services/auth.service"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - FactoryOptions, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - MessagingServiceInitOptions, - messagingServiceFactory, -} from "../../../platform/background/service-factories/messaging-service.factory"; -import { - StateServiceInitOptions, - stateServiceFactory, -} from "../../../platform/background/service-factories/state-service.factory"; - -import { AccountServiceInitOptions, accountServiceFactory } from "./account-service.factory"; -import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory"; - -type AuthServiceFactoryOptions = FactoryOptions; - -export type AuthServiceInitOptions = AuthServiceFactoryOptions & - AccountServiceInitOptions & - MessagingServiceInitOptions & - CryptoServiceInitOptions & - ApiServiceInitOptions & - StateServiceInitOptions & - TokenServiceInitOptions; - -export function authServiceFactory( - cache: { authService?: AbstractAuthService } & CachedServices, - opts: AuthServiceInitOptions, -): Promise { - return factory( - cache, - "authService", - opts, - async () => - new AuthService( - await accountServiceFactory(cache, opts), - await messagingServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await apiServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/avatar-service.factory.ts b/apps/browser/src/auth/background/service-factories/avatar-service.factory.ts deleted file mode 100644 index 456edfa93da..00000000000 --- a/apps/browser/src/auth/background/service-factories/avatar-service.factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/auth/abstractions/avatar.service"; -import { AvatarService } from "@bitwarden/common/auth/services/avatar.service"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -type AvatarServiceFactoryOptions = FactoryOptions; - -export type AvatarServiceInitOptions = AvatarServiceFactoryOptions & - ApiServiceInitOptions & - StateProviderInitOptions; - -export function avatarServiceFactory( - cache: { avatarService?: AvatarServiceAbstraction } & CachedServices, - opts: AvatarServiceInitOptions, -): Promise { - return factory( - cache, - "avatarService", - opts, - async () => - new AvatarService( - await apiServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts b/apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts deleted file mode 100644 index 42a8232c3e6..00000000000 --- a/apps/browser/src/auth/background/service-factories/device-trust-service.factory.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; -import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation"; - -import { - DevicesApiServiceInitOptions, - devicesApiServiceFactory, -} from "../../../background/service-factories/devices-api-service.factory"; -import { - AppIdServiceInitOptions, - appIdServiceFactory, -} from "../../../platform/background/service-factories/app-id-service.factory"; -import { - CryptoFunctionServiceInitOptions, - cryptoFunctionServiceFactory, -} from "../../../platform/background/service-factories/crypto-function-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - CachedServices, - FactoryOptions, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - I18nServiceInitOptions, - i18nServiceFactory, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "../../../platform/background/service-factories/key-generation-service.factory"; -import { logServiceFactory } from "../../../platform/background/service-factories/log-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; -import { - StateProviderInitOptions, - stateProviderFactory, -} from "../../../platform/background/service-factories/state-provider.factory"; -import { - SecureStorageServiceInitOptions, - secureStorageServiceFactory, -} from "../../../platform/background/service-factories/storage-service.factory"; - -import { - UserDecryptionOptionsServiceInitOptions, - userDecryptionOptionsServiceFactory, -} from "./user-decryption-options-service.factory"; - -type DeviceTrustServiceFactoryOptions = FactoryOptions; - -export type DeviceTrustServiceInitOptions = DeviceTrustServiceFactoryOptions & - KeyGenerationServiceInitOptions & - CryptoFunctionServiceInitOptions & - CryptoServiceInitOptions & - EncryptServiceInitOptions & - AppIdServiceInitOptions & - DevicesApiServiceInitOptions & - I18nServiceInitOptions & - PlatformUtilsServiceInitOptions & - StateProviderInitOptions & - SecureStorageServiceInitOptions & - UserDecryptionOptionsServiceInitOptions; - -export function deviceTrustServiceFactory( - cache: { deviceTrustService?: DeviceTrustServiceAbstraction } & CachedServices, - opts: DeviceTrustServiceInitOptions, -): Promise { - return factory( - cache, - "deviceTrustService", - opts, - async () => - new DeviceTrustService( - await keyGenerationServiceFactory(cache, opts), - await cryptoFunctionServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await appIdServiceFactory(cache, opts), - await devicesApiServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await secureStorageServiceFactory(cache, opts), - await userDecryptionOptionsServiceFactory(cache, opts), - await logServiceFactory(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 deleted file mode 100644 index eb5ba3a264c..00000000000 --- a/apps/browser/src/auth/background/service-factories/kdf-config-service.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -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/key-connector-service.factory.ts b/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts deleted file mode 100644 index c602acadaed..00000000000 --- a/apps/browser/src/auth/background/service-factories/key-connector-service.factory.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { KeyConnectorService as AbstractKeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; -import { KeyConnectorService } from "@bitwarden/common/auth/services/key-connector.service"; - -import { - OrganizationServiceInitOptions, - organizationServiceFactory, -} from "../../../admin-console/background/service-factories/organization-service.factory"; -import { - apiServiceFactory, - ApiServiceInitOptions, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "../../../platform/background/service-factories/key-generation-service.factory"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory"; -import { - internalMasterPasswordServiceFactory, - MasterPasswordServiceInitOptions, -} from "./master-password-service.factory"; -import { TokenServiceInitOptions, tokenServiceFactory } from "./token-service.factory"; - -type KeyConnectorServiceFactoryOptions = FactoryOptions & { - keyConnectorServiceOptions: { - logoutCallback: (expired: boolean, userId?: string) => Promise; - }; -}; - -export type KeyConnectorServiceInitOptions = KeyConnectorServiceFactoryOptions & - AccountServiceInitOptions & - MasterPasswordServiceInitOptions & - CryptoServiceInitOptions & - ApiServiceInitOptions & - TokenServiceInitOptions & - LogServiceInitOptions & - OrganizationServiceInitOptions & - KeyGenerationServiceInitOptions & - StateProviderInitOptions; - -export function keyConnectorServiceFactory( - cache: { keyConnectorService?: AbstractKeyConnectorService } & CachedServices, - opts: KeyConnectorServiceInitOptions, -): Promise { - return factory( - cache, - "keyConnectorService", - opts, - async () => - new KeyConnectorService( - await accountServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await apiServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await organizationServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - opts.keyConnectorServiceOptions.logoutCallback, - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/login-email-service.factory.ts b/apps/browser/src/auth/background/service-factories/login-email-service.factory.ts deleted file mode 100644 index 6e98a9a8860..00000000000 --- a/apps/browser/src/auth/background/service-factories/login-email-service.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { LoginEmailServiceAbstraction, LoginEmailService } from "@bitwarden/auth/common"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -type LoginEmailServiceFactoryOptions = FactoryOptions; - -export type LoginEmailServiceInitOptions = LoginEmailServiceFactoryOptions & - StateProviderInitOptions; - -export function loginEmailServiceFactory( - cache: { loginEmailService?: LoginEmailServiceAbstraction } & CachedServices, - opts: LoginEmailServiceInitOptions, -): Promise { - return factory( - cache, - "loginEmailService", - opts, - async () => new LoginEmailService(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 deleted file mode 100644 index 83ebcaa11e6..00000000000 --- a/apps/browser/src/auth/background/service-factories/login-strategy-service.factory.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { LoginStrategyService, LoginStrategyServiceAbstraction } from "@bitwarden/auth/common"; - -import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - vaultTimeoutSettingsServiceFactory, - VaultTimeoutSettingsServiceInitOptions, -} from "../../../background/service-factories/vault-timeout-settings-service.factory"; -import { - apiServiceFactory, - ApiServiceInitOptions, -} from "../../../platform/background/service-factories/api-service.factory"; -import { appIdServiceFactory } from "../../../platform/background/service-factories/app-id-service.factory"; -import { - billingAccountProfileStateServiceFactory, - BillingAccountProfileStateServiceInitOptions, -} from "../../../platform/background/service-factories/billing-account-profile-state-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - environmentServiceFactory, - EnvironmentServiceInitOptions, -} from "../../../platform/background/service-factories/environment-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - globalStateProviderFactory, - GlobalStateProviderInitOptions, -} from "../../../platform/background/service-factories/global-state-provider.factory"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - messagingServiceFactory, - MessagingServiceInitOptions, -} from "../../../platform/background/service-factories/messaging-service.factory"; -import { - platformUtilsServiceFactory, - PlatformUtilsServiceInitOptions, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../../platform/background/service-factories/state-service.factory"; -import { - passwordStrengthServiceFactory, - PasswordStrengthServiceInitOptions, -} from "../../../tools/background/service_factories/password-strength-service.factory"; - -import { accountServiceFactory, AccountServiceInitOptions } from "./account-service.factory"; -import { - authRequestServiceFactory, - AuthRequestServiceInitOptions, -} from "./auth-request-service.factory"; -import { - deviceTrustServiceFactory, - DeviceTrustServiceInitOptions, -} from "./device-trust-service.factory"; -import { kdfConfigServiceFactory, KdfConfigServiceInitOptions } from "./kdf-config-service.factory"; -import { - keyConnectorServiceFactory, - KeyConnectorServiceInitOptions, -} from "./key-connector-service.factory"; -import { - internalMasterPasswordServiceFactory, - MasterPasswordServiceInitOptions, -} from "./master-password-service.factory"; -import { tokenServiceFactory, TokenServiceInitOptions } from "./token-service.factory"; -import { twoFactorServiceFactory, TwoFactorServiceInitOptions } from "./two-factor-service.factory"; -import { - internalUserDecryptionOptionServiceFactory, - UserDecryptionOptionsServiceInitOptions, -} from "./user-decryption-options-service.factory"; - -type LoginStrategyServiceFactoryOptions = FactoryOptions; - -export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions & - AccountServiceInitOptions & - MasterPasswordServiceInitOptions & - CryptoServiceInitOptions & - ApiServiceInitOptions & - TokenServiceInitOptions & - PlatformUtilsServiceInitOptions & - MessagingServiceInitOptions & - LogServiceInitOptions & - KeyConnectorServiceInitOptions & - EnvironmentServiceInitOptions & - StateServiceInitOptions & - TwoFactorServiceInitOptions & - I18nServiceInitOptions & - EncryptServiceInitOptions & - PolicyServiceInitOptions & - PasswordStrengthServiceInitOptions & - DeviceTrustServiceInitOptions & - AuthRequestServiceInitOptions & - UserDecryptionOptionsServiceInitOptions & - GlobalStateProviderInitOptions & - BillingAccountProfileStateServiceInitOptions & - VaultTimeoutSettingsServiceInitOptions & - KdfConfigServiceInitOptions; - -export function loginStrategyServiceFactory( - cache: { loginStrategyService?: LoginStrategyServiceAbstraction } & CachedServices, - opts: LoginStrategyServiceInitOptions, -): Promise { - return factory( - cache, - "loginStrategyService", - opts, - async () => - new LoginStrategyService( - await accountServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await apiServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - await appIdServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await messagingServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await keyConnectorServiceFactory(cache, opts), - await environmentServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - await twoFactorServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await passwordStrengthServiceFactory(cache, opts), - await policyServiceFactory(cache, opts), - await deviceTrustServiceFactory(cache, opts), - await authRequestServiceFactory(cache, opts), - await internalUserDecryptionOptionServiceFactory(cache, opts), - await globalStateProviderFactory(cache, opts), - await billingAccountProfileStateServiceFactory(cache, opts), - await vaultTimeoutSettingsServiceFactory(cache, opts), - await kdfConfigServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/master-password-service.factory.ts b/apps/browser/src/auth/background/service-factories/master-password-service.factory.ts deleted file mode 100644 index 37fcf789ff2..00000000000 --- a/apps/browser/src/auth/background/service-factories/master-password-service.factory.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - InternalMasterPasswordServiceAbstraction, - MasterPasswordServiceAbstraction, -} from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; -import { MasterPasswordService } from "@bitwarden/common/auth/services/master-password/master-password.service"; - -import { - encryptServiceFactory, - EncryptServiceInitOptions, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - keyGenerationServiceFactory, - KeyGenerationServiceInitOptions, -} from "../../../platform/background/service-factories/key-generation-service.factory"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../../platform/background/service-factories/state-service.factory"; - -type MasterPasswordServiceFactoryOptions = FactoryOptions; - -export type MasterPasswordServiceInitOptions = MasterPasswordServiceFactoryOptions & - StateProviderInitOptions & - StateServiceInitOptions & - KeyGenerationServiceInitOptions & - EncryptServiceInitOptions; - -export function internalMasterPasswordServiceFactory( - cache: { masterPasswordService?: InternalMasterPasswordServiceAbstraction } & CachedServices, - opts: MasterPasswordServiceInitOptions, -): Promise { - return factory( - cache, - "masterPasswordService", - opts, - async () => - new MasterPasswordService( - await stateProviderFactory(cache, opts), - await stateServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - ), - ); -} - -export async function masterPasswordServiceFactory( - cache: { masterPasswordService?: InternalMasterPasswordServiceAbstraction } & CachedServices, - opts: MasterPasswordServiceInitOptions, -): Promise { - return (await internalMasterPasswordServiceFactory( - cache, - opts, - )) as MasterPasswordServiceAbstraction; -} diff --git a/apps/browser/src/auth/background/service-factories/pin-service.factory.ts b/apps/browser/src/auth/background/service-factories/pin-service.factory.ts deleted file mode 100644 index f15e7fe7620..00000000000 --- a/apps/browser/src/auth/background/service-factories/pin-service.factory.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { PinServiceAbstraction, PinService } from "@bitwarden/auth/common"; - -import { - CryptoFunctionServiceInitOptions, - cryptoFunctionServiceFactory, -} from "../../../platform/background/service-factories/crypto-function-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "../../../platform/background/service-factories/key-generation-service.factory"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - StateProviderInitOptions, - stateProviderFactory, -} from "../../../platform/background/service-factories/state-provider.factory"; -import { - StateServiceInitOptions, - stateServiceFactory, -} from "../../../platform/background/service-factories/state-service.factory"; - -import { AccountServiceInitOptions, accountServiceFactory } from "./account-service.factory"; -import { KdfConfigServiceInitOptions, kdfConfigServiceFactory } from "./kdf-config-service.factory"; -import { - MasterPasswordServiceInitOptions, - masterPasswordServiceFactory, -} from "./master-password-service.factory"; - -type PinServiceFactoryOptions = FactoryOptions; - -export type PinServiceInitOptions = PinServiceFactoryOptions & - AccountServiceInitOptions & - CryptoFunctionServiceInitOptions & - EncryptServiceInitOptions & - KdfConfigServiceInitOptions & - KeyGenerationServiceInitOptions & - LogServiceInitOptions & - MasterPasswordServiceInitOptions & - StateProviderInitOptions & - StateServiceInitOptions; - -export function pinServiceFactory( - cache: { pinService?: PinServiceAbstraction } & CachedServices, - opts: PinServiceInitOptions, -): Promise { - return factory( - cache, - "pinService", - opts, - async () => - new PinService( - await accountServiceFactory(cache, opts), - await cryptoFunctionServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await kdfConfigServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await masterPasswordServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await stateServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/sso-login-service.factory.ts b/apps/browser/src/auth/background/service-factories/sso-login-service.factory.ts deleted file mode 100644 index 2747d9ff442..00000000000 --- a/apps/browser/src/auth/background/service-factories/sso-login-service.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/sso-login.service.abstraction"; -import { SsoLoginService } from "@bitwarden/common/auth/services/sso-login.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -type SsoLoginServiceFactoryOptions = FactoryOptions; - -export type SsoLoginServiceInitOptions = SsoLoginServiceFactoryOptions & StateProviderInitOptions; - -export function ssoLoginServiceFactory( - cache: { ssoLoginService?: SsoLoginServiceAbstraction } & CachedServices, - opts: SsoLoginServiceInitOptions, -): Promise { - return factory( - cache, - "ssoLoginService", - opts, - async () => new SsoLoginService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/auth/background/service-factories/token-service.factory.ts b/apps/browser/src/auth/background/service-factories/token-service.factory.ts deleted file mode 100644 index ba42998209e..00000000000 --- a/apps/browser/src/auth/background/service-factories/token-service.factory.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { TokenService as AbstractTokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TokenService } from "@bitwarden/common/auth/services/token.service"; - -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "../../../platform/background/service-factories/global-state-provider.factory"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "../../../platform/background/service-factories/key-generation-service.factory"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; -import { - SingleUserStateProviderInitOptions, - singleUserStateProviderFactory, -} from "../../../platform/background/service-factories/single-user-state-provider.factory"; -import { - SecureStorageServiceInitOptions, - secureStorageServiceFactory, -} from "../../../platform/background/service-factories/storage-service.factory"; - -type TokenServiceFactoryOptions = FactoryOptions; - -export type TokenServiceInitOptions = TokenServiceFactoryOptions & - SingleUserStateProviderInitOptions & - GlobalStateProviderInitOptions & - PlatformUtilsServiceInitOptions & - SecureStorageServiceInitOptions & - KeyGenerationServiceInitOptions & - EncryptServiceInitOptions & - LogServiceInitOptions; - -export function tokenServiceFactory( - cache: { tokenService?: AbstractTokenService } & CachedServices, - opts: TokenServiceInitOptions, -): Promise { - return factory( - cache, - "tokenService", - opts, - async () => - new TokenService( - await singleUserStateProviderFactory(cache, opts), - await globalStateProviderFactory(cache, opts), - (await platformUtilsServiceFactory(cache, opts)).supportsSecureStorage(), - await secureStorageServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - ), - ); -} 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 deleted file mode 100644 index 5af5eb00177..00000000000 --- a/apps/browser/src/auth/background/service-factories/two-factor-service.factory.ts +++ /dev/null @@ -1,44 +0,0 @@ -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, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; - -type TwoFactorServiceFactoryOptions = FactoryOptions; - -export type TwoFactorServiceInitOptions = TwoFactorServiceFactoryOptions & - I18nServiceInitOptions & - PlatformUtilsServiceInitOptions & - GlobalStateProvider; - -export async function twoFactorServiceFactory( - cache: { twoFactorService?: AbstractTwoFactorService } & CachedServices, - opts: TwoFactorServiceInitOptions, -): Promise { - const service = await factory( - cache, - "twoFactorService", - opts, - async () => - new TwoFactorService( - await i18nServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await globalStateProviderFactory(cache, opts), - ), - ); - service.init(); - return service; -} diff --git a/apps/browser/src/auth/background/service-factories/user-decryption-options-service.factory.ts b/apps/browser/src/auth/background/service-factories/user-decryption-options-service.factory.ts deleted file mode 100644 index 549639a3c78..00000000000 --- a/apps/browser/src/auth/background/service-factories/user-decryption-options-service.factory.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - InternalUserDecryptionOptionsServiceAbstraction, - UserDecryptionOptionsService, - UserDecryptionOptionsServiceAbstraction, -} from "@bitwarden/auth/common"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -type UserDecryptionOptionsServiceFactoryOptions = FactoryOptions; - -export type UserDecryptionOptionsServiceInitOptions = UserDecryptionOptionsServiceFactoryOptions & - StateProviderInitOptions; - -export function userDecryptionOptionsServiceFactory( - cache: { - userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction; - } & CachedServices, - opts: UserDecryptionOptionsServiceInitOptions, -): Promise { - return factory( - cache, - "userDecryptionOptionsService", - opts, - async () => new UserDecryptionOptionsService(await stateProviderFactory(cache, opts)), - ); -} - -export async function internalUserDecryptionOptionServiceFactory( - cache: { - userDecryptionOptionsService?: InternalUserDecryptionOptionsServiceAbstraction; - } & CachedServices, - opts: UserDecryptionOptionsServiceInitOptions, -): Promise { - return (await userDecryptionOptionsServiceFactory( - cache, - opts, - )) as InternalUserDecryptionOptionsServiceAbstraction; -} diff --git a/apps/browser/src/auth/background/service-factories/user-verification-api-service.factory.ts b/apps/browser/src/auth/background/service-factories/user-verification-api-service.factory.ts deleted file mode 100644 index f8d43877632..00000000000 --- a/apps/browser/src/auth/background/service-factories/user-verification-api-service.factory.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { UserVerificationApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/user-verification/user-verification-api.service.abstraction"; -import { UserVerificationApiService } from "@bitwarden/common/auth/services/user-verification/user-verification-api.service"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; - -type UserVerificationApiServiceFactoryOptions = FactoryOptions; - -export type UserVerificationApiServiceInitOptions = UserVerificationApiServiceFactoryOptions & - ApiServiceInitOptions; - -export function userVerificationApiServiceFactory( - cache: { userVerificationApiService?: UserVerificationApiServiceAbstraction } & CachedServices, - opts: UserVerificationApiServiceInitOptions, -): Promise { - return factory( - cache, - "userVerificationApiService", - opts, - async () => new UserVerificationApiService(await apiServiceFactory(cache, opts)), - ); -} 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 deleted file mode 100644 index 5b5a4250454..00000000000 --- a/apps/browser/src/auth/background/service-factories/user-verification-service.factory.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { UserVerificationService as AbstractUserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; -import { UserVerificationService } from "@bitwarden/common/auth/services/user-verification/user-verification.service"; - -import { - VaultTimeoutSettingsServiceInitOptions, - vaultTimeoutSettingsServiceFactory, -} from "../../../background/service-factories/vault-timeout-settings-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - I18nServiceInitOptions, - i18nServiceFactory, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - platformUtilsServiceFactory, - PlatformUtilsServiceInitOptions, -} from "../../../platform/background/service-factories/platform-utils-service.factory"; -import { - StateServiceInitOptions, - stateServiceFactory, -} 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, -} from "./master-password-service.factory"; -import { PinServiceInitOptions, pinServiceFactory } from "./pin-service.factory"; -import { - userDecryptionOptionsServiceFactory, - UserDecryptionOptionsServiceInitOptions, -} from "./user-decryption-options-service.factory"; -import { - UserVerificationApiServiceInitOptions, - userVerificationApiServiceFactory, -} from "./user-verification-api-service.factory"; - -type UserVerificationServiceFactoryOptions = FactoryOptions; - -export type UserVerificationServiceInitOptions = UserVerificationServiceFactoryOptions & - StateServiceInitOptions & - CryptoServiceInitOptions & - AccountServiceInitOptions & - MasterPasswordServiceInitOptions & - I18nServiceInitOptions & - UserVerificationApiServiceInitOptions & - UserDecryptionOptionsServiceInitOptions & - PinServiceInitOptions & - LogServiceInitOptions & - VaultTimeoutSettingsServiceInitOptions & - PlatformUtilsServiceInitOptions & - KdfConfigServiceInitOptions; - -export function userVerificationServiceFactory( - cache: { userVerificationService?: AbstractUserVerificationService } & CachedServices, - opts: UserVerificationServiceInitOptions, -): Promise { - return factory( - cache, - "userVerificationService", - opts, - async () => - new UserVerificationService( - await stateServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await accountServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await userVerificationApiServiceFactory(cache, opts), - await userDecryptionOptionsServiceFactory(cache, opts), - await pinServiceFactory(cache, opts), - 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/current-account.component.ts b/apps/browser/src/auth/popup/account-switching/current-account.component.ts index 643c37b9aaa..fcb772f0245 100644 --- a/apps/browser/src/auth/popup/account-switching/current-account.component.ts +++ b/apps/browser/src/auth/popup/account-switching/current-account.component.ts @@ -1,13 +1,15 @@ -import { Location } from "@angular/common"; +import { CommonModule, Location } from "@angular/common"; import { Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { Observable, combineLatest, switchMap } from "rxjs"; +import { JslibModule } from "@bitwarden/angular/jslib.module"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { UserId } from "@bitwarden/common/types/guid"; +import { AvatarModule } from "@bitwarden/components"; export type CurrentAccount = { id: UserId; @@ -20,6 +22,8 @@ export type CurrentAccount = { @Component({ selector: "app-current-account", templateUrl: "current-account.component.html", + standalone: true, + imports: [CommonModule, JslibModule, AvatarModule], }) export class CurrentAccountComponent { currentAccount$: Observable; diff --git a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts index be12d249441..6865adca393 100644 --- a/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts +++ b/apps/browser/src/auth/popup/account-switching/services/account-switcher.service.spec.ts @@ -153,7 +153,7 @@ describe("AccountSwitcherService", () => { await selectAccountPromise; - expect(accountService.switchAccount).toBeCalledWith(null); + expect(messagingService.send).toHaveBeenCalledWith("switchAccount", { userId: null }); expect(removeListenerSpy).toBeCalledTimes(1); }); @@ -176,7 +176,7 @@ describe("AccountSwitcherService", () => { await selectAccountPromise; - expect(accountService.switchAccount).toBeCalledWith("1"); + expect(messagingService.send).toHaveBeenCalledWith("switchAccount", { userId: "1" }); expect(messagingService.send).toBeCalledWith( "switchAccount", matches((payload) => { 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 2650c2db4e4..d60b0dfaebc 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 @@ -134,7 +134,6 @@ export class AccountSwitcherService { const switchAccountFinishedPromise = this.listenForSwitchAccountFinish(userId); // Initiate the actions required to make account switching happen - await this.accountService.switchAccount(userId); this.messagingService.send("switchAccount", { userId }); // This message should cause switchAccountFinish to be sent // Wait until we receive the switchAccountFinished message 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 158296058e5..69d3204701e 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 @@ -20,7 +20,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @@ -44,7 +43,6 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { platformUtilsService: PlatformUtilsService, anonymousHubService: AnonymousHubService, validationService: ValidationService, - stateService: StateService, loginEmailService: LoginEmailServiceAbstraction, syncService: SyncService, deviceTrustService: DeviceTrustServiceAbstraction, @@ -67,12 +65,11 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { platformUtilsService, anonymousHubService, validationService, - stateService, + accountService, loginEmailService, deviceTrustService, authRequestService, loginStrategyService, - accountService, ); super.onSuccessfulLogin = async () => { await syncService.fullSync(true); diff --git a/apps/browser/src/autofill/background/overlay.background.spec.ts b/apps/browser/src/autofill/background/overlay.background.spec.ts index e65397a62b1..9f4da8f21f3 100644 --- a/apps/browser/src/autofill/background/overlay.background.spec.ts +++ b/apps/browser/src/autofill/background/overlay.background.spec.ts @@ -1,4 +1,4 @@ -import { mock, mockReset } from "jest-mock-extended"; +import { mock, MockProxy, mockReset } from "jest-mock-extended"; import { BehaviorSubject, of } from "rxjs"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -62,7 +62,8 @@ describe("OverlayBackground", () => { let overlayBackground: OverlayBackground; const cipherService = mock(); const autofillService = mock(); - const authService = mock(); + let activeAccountStatusMock$: BehaviorSubject; + let authService: MockProxy; const environmentService = mock(); environmentService.environment$ = new BehaviorSubject( @@ -94,6 +95,9 @@ describe("OverlayBackground", () => { beforeEach(() => { domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider); + activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked); + authService = mock(); + authService.activeAccountStatus$ = activeAccountStatusMock$; overlayBackground = new OverlayBackground( cipherService, autofillService, @@ -166,11 +170,11 @@ describe("OverlayBackground", () => { }); beforeEach(() => { - overlayBackground["userAuthStatus"] = AuthenticationStatus.Unlocked; + activeAccountStatusMock$.next(AuthenticationStatus.Unlocked); }); it("ignores updating the overlay ciphers if the user's auth status is not unlocked", async () => { - overlayBackground["userAuthStatus"] = AuthenticationStatus.Locked; + activeAccountStatusMock$.next(AuthenticationStatus.Locked); jest.spyOn(BrowserApi, "getTabFromCurrentWindowId"); jest.spyOn(cipherService, "getAllDecryptedForUrl"); diff --git a/apps/browser/src/autofill/background/overlay.background.ts b/apps/browser/src/autofill/background/overlay.background.ts index 551263525e9..0e4abcd82d0 100644 --- a/apps/browser/src/autofill/background/overlay.background.ts +++ b/apps/browser/src/autofill/background/overlay.background.ts @@ -136,7 +136,8 @@ class OverlayBackground implements OverlayBackgroundInterface { * list of ciphers if the extension is not unlocked. */ async updateOverlayCiphers() { - if (this.userAuthStatus !== AuthenticationStatus.Unlocked) { + const authStatus = await firstValueFrom(this.authService.activeAccountStatus$); + if (authStatus !== AuthenticationStatus.Unlocked) { return; } @@ -167,7 +168,7 @@ class OverlayBackground implements OverlayBackgroundInterface { private async getOverlayCipherData(): Promise { const showFavicons = await firstValueFrom(this.domainSettingsService.showFavicons$); const overlayCiphersArray = Array.from(this.overlayLoginCiphers); - const overlayCipherData = []; + const overlayCipherData: OverlayCipherData[] = []; let loginCipherIcon: WebsiteIconData; for (let cipherIndex = 0; cipherIndex < overlayCiphersArray.length; cipherIndex++) { diff --git a/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts b/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts deleted file mode 100644 index bee5da18b5b..00000000000 --- a/apps/browser/src/autofill/background/service_factories/autofill-service.factory.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { - accountServiceFactory, - AccountServiceInitOptions, -} from "../../../auth/background/service-factories/account-service.factory"; -import { - UserVerificationServiceInitOptions, - userVerificationServiceFactory, -} from "../../../auth/background/service-factories/user-verification-service.factory"; -import { - EventCollectionServiceInitOptions, - eventCollectionServiceFactory, -} from "../../../background/service-factories/event-collection-service.factory"; -import { billingAccountProfileStateServiceFactory } from "../../../platform/background/service-factories/billing-account-profile-state-service.factory"; -import { - browserScriptInjectorServiceFactory, - BrowserScriptInjectorServiceInitOptions, -} from "../../../platform/background/service-factories/browser-script-injector-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../../platform/background/service-factories/log-service.factory"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../../vault/background/service_factories/cipher-service.factory"; -import { - TotpServiceInitOptions, - totpServiceFactory, -} from "../../../vault/background/service_factories/totp-service.factory"; -import { AutofillService as AbstractAutoFillService } from "../../services/abstractions/autofill.service"; -import AutofillService from "../../services/autofill.service"; - -import { - AutofillSettingsServiceInitOptions, - autofillSettingsServiceFactory, -} from "./autofill-settings-service.factory"; -import { - DomainSettingsServiceInitOptions, - domainSettingsServiceFactory, -} from "./domain-settings-service.factory"; - -type AutoFillServiceOptions = FactoryOptions; - -export type AutoFillServiceInitOptions = AutoFillServiceOptions & - CipherServiceInitOptions & - AutofillSettingsServiceInitOptions & - TotpServiceInitOptions & - EventCollectionServiceInitOptions & - LogServiceInitOptions & - UserVerificationServiceInitOptions & - DomainSettingsServiceInitOptions & - BrowserScriptInjectorServiceInitOptions & - AccountServiceInitOptions; - -export function autofillServiceFactory( - cache: { autofillService?: AbstractAutoFillService } & CachedServices, - opts: AutoFillServiceInitOptions, -): Promise { - return factory( - cache, - "autofillService", - opts, - async () => - new AutofillService( - await cipherServiceFactory(cache, opts), - await autofillSettingsServiceFactory(cache, opts), - await totpServiceFactory(cache, opts), - await eventCollectionServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await domainSettingsServiceFactory(cache, opts), - await userVerificationServiceFactory(cache, opts), - await billingAccountProfileStateServiceFactory(cache, opts), - await browserScriptInjectorServiceFactory(cache, opts), - await accountServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/autofill/background/service_factories/autofill-settings-service.factory.ts b/apps/browser/src/autofill/background/service_factories/autofill-settings-service.factory.ts deleted file mode 100644 index ef9fdac968c..00000000000 --- a/apps/browser/src/autofill/background/service_factories/autofill-settings-service.factory.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AutofillSettingsService } from "@bitwarden/common/autofill/services/autofill-settings.service"; - -import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -export type AutofillSettingsServiceInitOptions = FactoryOptions & - StateProviderInitOptions & - PolicyServiceInitOptions; - -export function autofillSettingsServiceFactory( - cache: { autofillSettingsService?: AutofillSettingsService } & CachedServices, - opts: AutofillSettingsServiceInitOptions, -): Promise { - return factory( - cache, - "autofillSettingsService", - opts, - async () => - new AutofillSettingsService( - await stateProviderFactory(cache, opts), - await policyServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/autofill/background/service_factories/badge-settings-service.factory.ts b/apps/browser/src/autofill/background/service_factories/badge-settings-service.factory.ts deleted file mode 100644 index c51a9b31b01..00000000000 --- a/apps/browser/src/autofill/background/service_factories/badge-settings-service.factory.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BadgeSettingsService } from "@bitwarden/common/autofill/services/badge-settings.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -export type BadgeSettingsServiceInitOptions = FactoryOptions & StateProviderInitOptions; - -export function badgeSettingsServiceFactory( - cache: { badgeSettingsService?: BadgeSettingsService } & CachedServices, - opts: BadgeSettingsServiceInitOptions, -): Promise { - return factory( - cache, - "badgeSettingsService", - opts, - async () => new BadgeSettingsService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/autofill/background/service_factories/domain-settings-service.factory.ts b/apps/browser/src/autofill/background/service_factories/domain-settings-service.factory.ts deleted file mode 100644 index 1b4127c4ccb..00000000000 --- a/apps/browser/src/autofill/background/service_factories/domain-settings-service.factory.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { DefaultDomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -export type DomainSettingsServiceInitOptions = FactoryOptions & StateProviderInitOptions; - -export function domainSettingsServiceFactory( - cache: { domainSettingsService?: DefaultDomainSettingsService } & CachedServices, - opts: DomainSettingsServiceInitOptions, -): Promise { - return factory( - cache, - "domainSettingsService", - opts, - async () => new DefaultDomainSettingsService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/autofill/background/service_factories/user-notification-settings-service.factory.ts b/apps/browser/src/autofill/background/service_factories/user-notification-settings-service.factory.ts deleted file mode 100644 index 5e19795e0e6..00000000000 --- a/apps/browser/src/autofill/background/service_factories/user-notification-settings-service.factory.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { UserNotificationSettingsService } from "@bitwarden/common/autofill/services/user-notification-settings.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -export type UserNotificationSettingsServiceInitOptions = FactoryOptions & StateProviderInitOptions; - -export function userNotificationSettingsServiceFactory( - cache: { userNotificationSettingsService?: UserNotificationSettingsService } & CachedServices, - opts: UserNotificationSettingsServiceInitOptions, -): Promise { - return factory( - cache, - "userNotificationSettingsService", - opts, - async () => new UserNotificationSettingsService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/autofill/browser/cipher-context-menu-handler.ts b/apps/browser/src/autofill/browser/cipher-context-menu-handler.ts index d66d4361db2..b112ff00efe 100644 --- a/apps/browser/src/autofill/browser/cipher-context-menu-handler.ts +++ b/apps/browser/src/autofill/browser/cipher-context-menu-handler.ts @@ -1,39 +1,14 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { - authServiceFactory, - AuthServiceInitOptions, -} from "../../auth/background/service-factories/auth-service.factory"; -import { Account } from "../../models/account"; -import { CachedServices } from "../../platform/background/service-factories/factory-options"; -import { BrowserApi } from "../../platform/browser/browser-api"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../vault/background/service_factories/cipher-service.factory"; import { AutofillCipherTypeId } from "../types"; import { MainContextMenuHandler } from "./main-context-menu-handler"; -const NOT_IMPLEMENTED = (..._args: unknown[]) => Promise.resolve(); - -const LISTENED_TO_COMMANDS = [ - "loggedIn", - "unlocked", - "syncCompleted", - "bgUpdateContextMenu", - "editedCipher", - "addedCipher", - "deletedCipher", -]; - export class CipherContextMenuHandler { constructor( private mainContextMenuHandler: MainContextMenuHandler, @@ -41,110 +16,6 @@ export class CipherContextMenuHandler { private cipherService: CipherService, ) {} - static async create(cachedServices: CachedServices) { - const stateFactory = new StateFactory(GlobalState, Account); - const serviceOptions: AuthServiceInitOptions & CipherServiceInitOptions = { - apiServiceOptions: { - logoutCallback: NOT_IMPLEMENTED, - }, - cryptoFunctionServiceOptions: { - win: self, - }, - encryptServiceOptions: { - logMacFailures: false, - }, - i18nServiceOptions: { - systemLanguage: chrome.i18n.getUILanguage(), - }, - keyConnectorServiceOptions: { - logoutCallback: NOT_IMPLEMENTED, - }, - logServiceOptions: { - isDev: false, - }, - platformUtilsServiceOptions: { - biometricCallback: () => Promise.resolve(false), - clipboardWriteCallback: NOT_IMPLEMENTED, - win: self, - }, - stateServiceOptions: { - stateFactory: stateFactory, - }, - }; - return new CipherContextMenuHandler( - await MainContextMenuHandler.mv3Create(cachedServices), - await authServiceFactory(cachedServices, serviceOptions), - await cipherServiceFactory(cachedServices, serviceOptions), - ); - } - - static async windowsOnFocusChangedListener(windowId: number, serviceCache: CachedServices) { - const cipherContextMenuHandler = await CipherContextMenuHandler.create(serviceCache); - const tab = await BrowserApi.getTabFromCurrentWindow(); - await cipherContextMenuHandler.update(tab?.url); - } - - static async tabsOnActivatedListener( - activeInfo: chrome.tabs.TabActiveInfo, - serviceCache: CachedServices, - ) { - const cipherContextMenuHandler = await CipherContextMenuHandler.create(serviceCache); - const tab = await BrowserApi.getTab(activeInfo.tabId); - await cipherContextMenuHandler.update(tab.url); - } - - static async tabsOnReplacedListener( - addedTabId: number, - removedTabId: number, - serviceCache: CachedServices, - ) { - const cipherContextMenuHandler = await CipherContextMenuHandler.create(serviceCache); - const tab = await BrowserApi.getTab(addedTabId); - await cipherContextMenuHandler.update(tab.url); - } - - static async tabsOnUpdatedListener( - tabId: number, - changeInfo: chrome.tabs.TabChangeInfo, - tab: chrome.tabs.Tab, - serviceCache: CachedServices, - ) { - if (changeInfo.status !== "complete") { - return; - } - const cipherContextMenuHandler = await CipherContextMenuHandler.create(serviceCache); - await cipherContextMenuHandler.update(tab.url); - } - - static async messageListener( - message: { command: string }, - sender: chrome.runtime.MessageSender, - cachedServices: CachedServices, - ) { - if (!CipherContextMenuHandler.shouldListen(message)) { - return; - } - const cipherContextMenuHandler = await CipherContextMenuHandler.create(cachedServices); - await cipherContextMenuHandler.messageListener(message); - } - - private static shouldListen(message: { command: string }) { - return LISTENED_TO_COMMANDS.includes(message.command); - } - - async messageListener(message: { command: string }, sender?: chrome.runtime.MessageSender) { - if (!CipherContextMenuHandler.shouldListen(message)) { - return; - } - - const activeTabs = await BrowserApi.getActiveTabs(); - if (!activeTabs || activeTabs.length === 0) { - return; - } - - await this.update(activeTabs[0].url); - } - async update(url: string) { if (this.mainContextMenuHandler.initRunning) { return; diff --git a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts index 5ba48a9f278..cb1c59dca59 100644 --- a/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts +++ b/apps/browser/src/autofill/browser/context-menu-clicked-handler.ts @@ -20,41 +20,19 @@ import { NOOP_COMMAND_SUFFIX, } from "@bitwarden/common/autofill/constants"; import { EventType } from "@bitwarden/common/enums"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { accountServiceFactory } from "../../auth/background/service-factories/account-service.factory"; -import { - authServiceFactory, - AuthServiceInitOptions, -} from "../../auth/background/service-factories/auth-service.factory"; -import { KeyConnectorServiceInitOptions } from "../../auth/background/service-factories/key-connector-service.factory"; -import { userVerificationServiceFactory } from "../../auth/background/service-factories/user-verification-service.factory"; import { openUnlockPopout } from "../../auth/popup/utils/auth-popout-window"; -import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory"; -import { eventCollectionServiceFactory } from "../../background/service-factories/event-collection-service.factory"; -import { Account } from "../../models/account"; -import { CachedServices } from "../../platform/background/service-factories/factory-options"; import { BrowserApi } from "../../platform/browser/browser-api"; -import { passwordGenerationServiceFactory } from "../../tools/background/service_factories/password-generation-service.factory"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../vault/background/service_factories/cipher-service.factory"; -import { totpServiceFactory } from "../../vault/background/service_factories/totp-service.factory"; import { openAddEditVaultItemPopout, openVaultItemPasswordRepromptPopout, } from "../../vault/popup/utils/vault-popout-window"; import { LockedVaultPendingNotificationsData } from "../background/abstractions/notification.background"; -import { autofillServiceFactory } from "../background/service_factories/autofill-service.factory"; -import { copyToClipboard, GeneratePasswordToClipboardCommand } from "../clipboard"; -import { AutofillTabCommand } from "../commands/autofill-tab-command"; import { AutofillCipherTypeId } from "../types"; export type CopyToClipboardOptions = { text: string; tab: chrome.tabs.Tab }; @@ -63,9 +41,6 @@ export type AutofillAction = (tab: chrome.tabs.Tab, cipher: CipherView) => Promi export type GeneratePasswordToClipboardAction = (tab: chrome.tabs.Tab) => Promise; -const NOT_IMPLEMENTED = (..._args: unknown[]) => - Promise.reject("This action is not implemented inside of a service worker context."); - export class ContextMenuClickedHandler { constructor( private copyToClipboard: CopyToClipboardAction, @@ -79,92 +54,6 @@ export class ContextMenuClickedHandler { private accountService: AccountService, ) {} - static async mv3Create(cachedServices: CachedServices) { - const stateFactory = new StateFactory(GlobalState, Account); - const serviceOptions: AuthServiceInitOptions & - CipherServiceInitOptions & - KeyConnectorServiceInitOptions = { - apiServiceOptions: { - logoutCallback: NOT_IMPLEMENTED, - }, - cryptoFunctionServiceOptions: { - win: self, - }, - encryptServiceOptions: { - logMacFailures: false, - }, - i18nServiceOptions: { - systemLanguage: chrome.i18n.getUILanguage(), - }, - keyConnectorServiceOptions: { - logoutCallback: NOT_IMPLEMENTED, - }, - logServiceOptions: { - isDev: false, - }, - platformUtilsServiceOptions: { - biometricCallback: NOT_IMPLEMENTED, - clipboardWriteCallback: NOT_IMPLEMENTED, - win: self, - }, - stateServiceOptions: { - stateFactory: stateFactory, - }, - autofillSettingsServiceOptions: { - stateFactory: autofillSettingsServiceFactory, - }, - }; - - const generatePasswordToClipboardCommand = new GeneratePasswordToClipboardCommand( - await passwordGenerationServiceFactory(cachedServices, serviceOptions), - await autofillSettingsServiceFactory(cachedServices, serviceOptions), - ); - - const autofillCommand = new AutofillTabCommand( - await autofillServiceFactory(cachedServices, serviceOptions), - ); - - return new ContextMenuClickedHandler( - (options) => copyToClipboard(options.tab, options.text), - (tab) => generatePasswordToClipboardCommand.generatePasswordToClipboard(tab), - (tab, cipher) => autofillCommand.doAutofillTabWithCipherCommand(tab, cipher), - await authServiceFactory(cachedServices, serviceOptions), - await cipherServiceFactory(cachedServices, serviceOptions), - await totpServiceFactory(cachedServices, serviceOptions), - await eventCollectionServiceFactory(cachedServices, serviceOptions), - await userVerificationServiceFactory(cachedServices, serviceOptions), - await accountServiceFactory(cachedServices, serviceOptions), - ); - } - - static async onClickedListener( - info: chrome.contextMenus.OnClickData, - tab?: chrome.tabs.Tab, - cachedServices: CachedServices = {}, - ) { - const contextMenuClickedHandler = await ContextMenuClickedHandler.mv3Create(cachedServices); - await contextMenuClickedHandler.run(info, tab); - } - - static async messageListener( - message: { command: string; data: LockedVaultPendingNotificationsData }, - sender: chrome.runtime.MessageSender, - cachedServices: CachedServices, - ) { - if ( - message.command !== "unlockCompleted" || - message.data.target !== "contextmenus.background" - ) { - return; - } - - const contextMenuClickedHandler = await ContextMenuClickedHandler.mv3Create(cachedServices); - await contextMenuClickedHandler.run( - message.data.commandToRetry.message.contextMenuOnClickData, - message.data.commandToRetry.sender.tab, - ); - } - async run(info: chrome.contextMenus.OnClickData, tab: chrome.tabs.Tab) { if (!tab) { return; diff --git a/apps/browser/src/autofill/browser/main-context-menu-handler.ts b/apps/browser/src/autofill/browser/main-context-menu-handler.ts index 9422756e07b..a02a3a84d4b 100644 --- a/apps/browser/src/autofill/browser/main-context-menu-handler.ts +++ b/apps/browser/src/autofill/browser/main-context-menu-handler.ts @@ -20,28 +20,10 @@ import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/s import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory"; -import { Account } from "../../models/account"; -import { billingAccountProfileStateServiceFactory } from "../../platform/background/service-factories/billing-account-profile-state-service.factory"; -import { CachedServices } from "../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../platform/background/service-factories/i18n-service.factory"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../platform/background/service-factories/log-service.factory"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../platform/background/service-factories/state-service.factory"; import { BrowserStateService } from "../../platform/services/abstractions/browser-state.service"; import { InitContextMenuItems } from "./abstractions/main-context-menu-handler"; @@ -168,41 +150,6 @@ export class MainContextMenuHandler { private billingAccountProfileStateService: BillingAccountProfileStateService, ) {} - static async mv3Create(cachedServices: CachedServices) { - const stateFactory = new StateFactory(GlobalState, Account); - const serviceOptions: StateServiceInitOptions & I18nServiceInitOptions & LogServiceInitOptions = - { - cryptoFunctionServiceOptions: { - win: self, - }, - encryptServiceOptions: { - logMacFailures: false, - }, - i18nServiceOptions: { - systemLanguage: chrome.i18n.getUILanguage(), - }, - logServiceOptions: { - isDev: false, - }, - stateServiceOptions: { - stateFactory: stateFactory, - }, - platformUtilsServiceOptions: { - clipboardWriteCallback: () => Promise.resolve(), - biometricCallback: () => Promise.resolve(false), - win: self, - }, - }; - - return new MainContextMenuHandler( - await stateServiceFactory(cachedServices, serviceOptions), - await autofillSettingsServiceFactory(cachedServices, serviceOptions), - await i18nServiceFactory(cachedServices, serviceOptions), - await logServiceFactory(cachedServices, serviceOptions), - await billingAccountProfileStateServiceFactory(cachedServices, serviceOptions), - ); - } - /** * * @returns a boolean showing whether or not items were created diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts index dd875054414..80829ee7141 100644 --- a/apps/browser/src/autofill/services/autofill.service.ts +++ b/apps/browser/src/autofill/services/autofill.service.ts @@ -3,6 +3,7 @@ import { firstValueFrom } from "rxjs"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service"; import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types"; @@ -109,9 +110,12 @@ export default class AutofillService implements AutofillServiceInterface { // Autofill user settings loaded from state can await the active account state indefinitely // if not guarded by an active account check (e.g. the user is logged in) const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - + let overlayVisibility: InlineMenuVisibilitySetting = AutofillOverlayVisibility.Off; let autoFillOnPageLoadIsEnabled = false; - const overlayVisibility = await this.getOverlayVisibility(); + + if (activeAccount) { + overlayVisibility = await this.getOverlayVisibility(); + } const mainAutofillScript = overlayVisibility ? "bootstrap-autofill-overlay.js" diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 41f300270eb..90a018a8fe8 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -109,6 +109,7 @@ import { DefaultConfigService } from "@bitwarden/common/platform/services/config import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation"; +import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; import { Fido2AuthenticatorService } from "@bitwarden/common/platform/services/fido2/fido2-authenticator.service"; import { Fido2ClientService } from "@bitwarden/common/platform/services/fido2/fido2-client.service"; import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service"; @@ -143,13 +144,11 @@ import { NotificationsService } from "@bitwarden/common/services/notifications.s import { SearchService } from "@bitwarden/common/services/search.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; import { - PasswordGenerationService, - PasswordGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/password"; -import { - UsernameGenerationService, - UsernameGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/username"; + legacyPasswordGenerationServiceFactory, + legacyUsernameGenerationServiceFactory, +} from "@bitwarden/common/tools/generator"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -220,7 +219,6 @@ import { BrowserCryptoService } from "../platform/services/browser-crypto.servic import { BrowserEnvironmentService } from "../platform/services/browser-environment.service"; import BrowserLocalStorageService from "../platform/services/browser-local-storage.service"; import BrowserMemoryStorageService from "../platform/services/browser-memory-storage.service"; -import { BrowserMultithreadEncryptServiceImplementation } from "../platform/services/browser-multithread-encrypt.service.implementation"; import { BrowserScriptInjectorService } from "../platform/services/browser-script-injector.service"; import { DefaultBrowserStateService } from "../platform/services/default-browser-state.service"; import I18nService from "../platform/services/i18n.service"; @@ -479,14 +477,14 @@ export default class MainBackground { storageServiceProvider, ); - this.encryptService = flagEnabled("multithreadDecryption") - ? new BrowserMultithreadEncryptServiceImplementation( - this.cryptoFunctionService, - this.logService, - true, - this.offscreenDocumentService, - ) - : new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true); + this.encryptService = + flagEnabled("multithreadDecryption") && BrowserApi.isManifestVersion(2) + ? new MultithreadEncryptServiceImplementation( + this.cryptoFunctionService, + this.logService, + true, + ) + : new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, true); this.singleUserStateProvider = new DefaultSingleUserStateProvider( storageServiceProvider, @@ -649,10 +647,12 @@ export default class MainBackground { this.passwordStrengthService = new PasswordStrengthService(); - this.passwordGenerationService = new PasswordGenerationService( + this.passwordGenerationService = legacyPasswordGenerationServiceFactory( + this.encryptService, this.cryptoService, this.policyService, - this.stateService, + this.accountService, + this.stateProvider, ); this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider); @@ -1092,10 +1092,14 @@ export default class MainBackground { this.vaultTimeoutSettingsService, ); - this.usernameGenerationService = new UsernameGenerationService( - this.cryptoService, - this.stateService, + this.usernameGenerationService = legacyUsernameGenerationServiceFactory( this.apiService, + this.i18nService, + this.cryptoService, + this.encryptService, + this.policyService, + this.accountService, + this.stateProvider, ); if (!this.popupOnlyContext) { @@ -1178,7 +1182,7 @@ export default class MainBackground { } async refreshBadge() { - await new UpdateBadge(self).run({ existingServices: this as any }); + await new UpdateBadge(self, this).run(); } async refreshMenu(forLocked = false) { @@ -1214,7 +1218,22 @@ export default class MainBackground { ); // can be removed once password generation history is migrated to state providers await this.stateService.clearDecryptedData(currentlyActiveAccount); + // HACK to ensure account is switched before proceeding + const switchPromise = firstValueFrom( + this.accountService.activeAccount$.pipe( + filter((account) => (account?.id ?? null) === (userId ?? null)), + timeout({ + first: 1_000, + with: () => { + throw new Error( + "The account switch process did not complete in a reasonable amount of time.", + ); + }, + }), + ), + ); await this.accountService.switchAccount(userId); + await switchPromise; // Clear sequentialized caches clearCaches(); diff --git a/apps/browser/src/background/nativeMessaging.background.ts b/apps/browser/src/background/nativeMessaging.background.ts index 51ab301fd1c..534a239a811 100644 --- a/apps/browser/src/background/nativeMessaging.background.ts +++ b/apps/browser/src/background/nativeMessaging.background.ts @@ -321,6 +321,15 @@ export class NativeMessagingBackground { type: "danger", }); break; + } else if (message.response === "not unlocked") { + this.messagingService.send("showDialog", { + title: { key: "biometricsNotUnlockedTitle" }, + content: { key: "biometricsNotUnlockedDesc" }, + acceptButtonText: { key: "ok" }, + cancelButtonText: null, + type: "danger", + }); + break; } else if (message.response === "canceled") { break; } diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index 1db32659d27..5473664e3b0 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -196,8 +196,6 @@ export default class RuntimeBackground { } await this.notificationsService.updateConnection(msg.command === "loggedIn"); - await this.main.refreshBadge(); - await this.main.refreshMenu(false); this.systemService.cancelProcessReload(); if (item) { @@ -209,6 +207,13 @@ export default class RuntimeBackground { item, ); } + + // @TODO these need to happen last to avoid blocking `tabSendMessageData` above + // The underlying cause exists within `cipherService.getAllDecrypted` via + // `getAllDecryptedForUrl` and is anticipated to be refactored + await this.main.refreshBadge(); + await this.main.refreshMenu(false); + break; } case "addToLockedVaultPendingNotifications": diff --git a/apps/browser/src/background/service-factories/cipher-file-upload-service.factory.ts b/apps/browser/src/background/service-factories/cipher-file-upload-service.factory.ts deleted file mode 100644 index 4127ff5acf4..00000000000 --- a/apps/browser/src/background/service-factories/cipher-file-upload-service.factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; -import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - FileUploadServiceInitOptions, - fileUploadServiceFactory, -} from "../../platform/background/service-factories/file-upload-service.factory"; - -type CipherFileUploadServiceFactoyOptions = FactoryOptions; - -export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions & - ApiServiceInitOptions & - FileUploadServiceInitOptions; - -export function cipherFileUploadServiceFactory( - cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices, - opts: CipherFileUploadServiceInitOptions, -): Promise { - return factory( - cache, - "cipherFileUploadService", - opts, - async () => - new CipherFileUploadService( - await apiServiceFactory(cache, opts), - await fileUploadServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/cipher-file-upload.service.factory.ts b/apps/browser/src/background/service-factories/cipher-file-upload.service.factory.ts deleted file mode 100644 index 4127ff5acf4..00000000000 --- a/apps/browser/src/background/service-factories/cipher-file-upload.service.factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service"; -import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - FileUploadServiceInitOptions, - fileUploadServiceFactory, -} from "../../platform/background/service-factories/file-upload-service.factory"; - -type CipherFileUploadServiceFactoyOptions = FactoryOptions; - -export type CipherFileUploadServiceInitOptions = CipherFileUploadServiceFactoyOptions & - ApiServiceInitOptions & - FileUploadServiceInitOptions; - -export function cipherFileUploadServiceFactory( - cache: { cipherFileUploadService?: CipherFileUploadServiceAbstraction } & CachedServices, - opts: CipherFileUploadServiceInitOptions, -): Promise { - return factory( - cache, - "cipherFileUploadService", - opts, - async () => - new CipherFileUploadService( - await apiServiceFactory(cache, opts), - await fileUploadServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/devices-api-service.factory.ts b/apps/browser/src/background/service-factories/devices-api-service.factory.ts deleted file mode 100644 index 117b82777ae..00000000000 --- a/apps/browser/src/background/service-factories/devices-api-service.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction"; -import { DevicesApiServiceImplementation } from "@bitwarden/common/auth/services/devices-api.service.implementation"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; - -type DevicesApiServiceFactoryOptions = FactoryOptions; - -export type DevicesApiServiceInitOptions = DevicesApiServiceFactoryOptions & ApiServiceInitOptions; - -export function devicesApiServiceFactory( - cache: { devicesApiService?: DevicesApiServiceAbstraction } & CachedServices, - opts: DevicesApiServiceInitOptions, -): Promise { - return factory( - cache, - "devicesApiService", - opts, - async () => new DevicesApiServiceImplementation(await apiServiceFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/background/service-factories/event-collection-service.factory.ts b/apps/browser/src/background/service-factories/event-collection-service.factory.ts deleted file mode 100644 index b8f89c90bd2..00000000000 --- a/apps/browser/src/background/service-factories/event-collection-service.factory.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { EventCollectionService as AbstractEventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; -import { EventCollectionService } from "@bitwarden/common/services/event/event-collection.service"; - -import { - organizationServiceFactory, - OrganizationServiceInitOptions, -} from "../../admin-console/background/service-factories/organization-service.factory"; -import { - authServiceFactory, - AuthServiceInitOptions, -} from "../../auth/background/service-factories/auth-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { stateProviderFactory } from "../../platform/background/service-factories/state-provider.factory"; -import { StateServiceInitOptions } from "../../platform/background/service-factories/state-service.factory"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../vault/background/service_factories/cipher-service.factory"; - -import { - eventUploadServiceFactory, - EventUploadServiceInitOptions, -} from "./event-upload-service.factory"; - -type EventCollectionServiceOptions = FactoryOptions; - -export type EventCollectionServiceInitOptions = EventCollectionServiceOptions & - CipherServiceInitOptions & - StateServiceInitOptions & - OrganizationServiceInitOptions & - EventUploadServiceInitOptions & - AuthServiceInitOptions; - -export function eventCollectionServiceFactory( - cache: { eventCollectionService?: AbstractEventCollectionService } & CachedServices, - opts: EventCollectionServiceInitOptions, -): Promise { - return factory( - cache, - "eventCollectionService", - opts, - async () => - new EventCollectionService( - await cipherServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await organizationServiceFactory(cache, opts), - await eventUploadServiceFactory(cache, opts), - await authServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/event-upload-service.factory.ts b/apps/browser/src/background/service-factories/event-upload-service.factory.ts deleted file mode 100644 index b20310e8c9c..00000000000 --- a/apps/browser/src/background/service-factories/event-upload-service.factory.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { EventUploadService as AbstractEventUploadService } from "@bitwarden/common/abstractions/event/event-upload.service"; -import { EventUploadService } from "@bitwarden/common/services/event/event-upload.service"; - -import { - AuthServiceInitOptions, - authServiceFactory, -} from "../../auth/background/service-factories/auth-service.factory"; -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../platform/background/service-factories/log-service.factory"; -import { stateProviderFactory } from "../../platform/background/service-factories/state-provider.factory"; -import { StateServiceInitOptions } from "../../platform/background/service-factories/state-service.factory"; - -type EventUploadServiceOptions = FactoryOptions; - -export type EventUploadServiceInitOptions = EventUploadServiceOptions & - ApiServiceInitOptions & - StateServiceInitOptions & - LogServiceInitOptions & - AuthServiceInitOptions; - -export function eventUploadServiceFactory( - cache: { eventUploadService?: AbstractEventUploadService } & CachedServices, - opts: EventUploadServiceInitOptions, -): Promise { - return factory( - cache, - "eventUploadService", - opts, - async () => - new EventUploadService( - await apiServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await logServiceFactory(cache, opts), - await authServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/password-generation-service.factory.ts b/apps/browser/src/background/service-factories/password-generation-service.factory.ts deleted file mode 100644 index ec7ca50ec46..00000000000 --- a/apps/browser/src/background/service-factories/password-generation-service.factory.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - PasswordGenerationService, - PasswordGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/password"; - -import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../admin-console/background/service-factories/policy-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../platform/background/service-factories/factory-options"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../platform/background/service-factories/state-service.factory"; - -type PasswordGenerationServiceFactoryOptions = FactoryOptions; - -export type PasswordGenerationServiceInitOptions = PasswordGenerationServiceFactoryOptions & - CryptoServiceInitOptions & - PolicyServiceInitOptions & - StateServiceInitOptions; - -export function passwordGenerationServiceFactory( - cache: { passwordGenerationService?: PasswordGenerationServiceAbstraction } & CachedServices, - opts: PasswordGenerationServiceInitOptions, -): Promise { - return factory( - cache, - "passwordGenerationService", - opts, - async () => - new PasswordGenerationService( - await cryptoServiceFactory(cache, opts), - await policyServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/search-service.factory.ts b/apps/browser/src/background/service-factories/search-service.factory.ts deleted file mode 100644 index aa83d2afd29..00000000000 --- a/apps/browser/src/background/service-factories/search-service.factory.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { SearchService as AbstractSearchService } from "@bitwarden/common/abstractions/search.service"; -import { SearchService } from "@bitwarden/common/services/search.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../platform/background/service-factories/i18n-service.factory"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../platform/background/service-factories/log-service.factory"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../platform/background/service-factories/state-provider.factory"; - -type SearchServiceFactoryOptions = FactoryOptions; - -export type SearchServiceInitOptions = SearchServiceFactoryOptions & - LogServiceInitOptions & - I18nServiceInitOptions & - StateProviderInitOptions; - -export function searchServiceFactory( - cache: { searchService?: AbstractSearchService } & CachedServices, - opts: SearchServiceInitOptions, -): Promise { - return factory( - cache, - "searchService", - opts, - async () => - new SearchService( - await logServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/send-service.factory.ts b/apps/browser/src/background/service-factories/send-service.factory.ts deleted file mode 100644 index 942861b9260..00000000000 --- a/apps/browser/src/background/service-factories/send-service.factory.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { SendService } from "@bitwarden/common/tools/send/services/send.service"; -import { InternalSendService } from "@bitwarden/common/tools/send/services/send.service.abstraction"; - -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../platform/background/service-factories/crypto-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../platform/background/service-factories/encrypt-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../platform/background/service-factories/i18n-service.factory"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "../../platform/background/service-factories/key-generation-service.factory"; - -import { - SendStateProviderInitOptions, - sendStateProviderFactory, -} from "./send-state-provider.factory"; - -type SendServiceFactoryOptions = FactoryOptions; - -export type SendServiceInitOptions = SendServiceFactoryOptions & - CryptoServiceInitOptions & - I18nServiceInitOptions & - KeyGenerationServiceInitOptions & - SendStateProviderInitOptions & - EncryptServiceInitOptions; - -export function sendServiceFactory( - cache: { sendService?: InternalSendService } & CachedServices, - opts: SendServiceInitOptions, -): Promise { - return factory( - cache, - "sendService", - opts, - async () => - new SendService( - await cryptoServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - await sendStateProviderFactory(cache, opts), - await encryptServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/background/service-factories/send-state-provider.factory.ts b/apps/browser/src/background/service-factories/send-state-provider.factory.ts deleted file mode 100644 index 01319756e47..00000000000 --- a/apps/browser/src/background/service-factories/send-state-provider.factory.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider"; - -import { - CachedServices, - FactoryOptions, - factory, -} from "../../platform/background/service-factories/factory-options"; -import { - StateProviderInitOptions, - stateProviderFactory, -} from "../../platform/background/service-factories/state-provider.factory"; - -type SendStateProviderFactoryOptions = FactoryOptions; - -export type SendStateProviderInitOptions = SendStateProviderFactoryOptions & - StateProviderInitOptions; - -export function sendStateProviderFactory( - cache: { sendStateProvider?: SendStateProvider } & CachedServices, - opts: SendStateProviderInitOptions, -): Promise { - return factory( - cache, - "sendStateProvider", - opts, - async () => new SendStateProvider(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts b/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts deleted file mode 100644 index 0b176c28f19..00000000000 --- a/apps/browser/src/background/service-factories/vault-timeout-service.factory.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { VaultTimeoutService as AbstractVaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service"; - -import { - accountServiceFactory, - AccountServiceInitOptions, -} from "../../auth/background/service-factories/account-service.factory"; -import { - authServiceFactory, - AuthServiceInitOptions, -} from "../../auth/background/service-factories/auth-service.factory"; -import { - internalMasterPasswordServiceFactory, - MasterPasswordServiceInitOptions, -} from "../../auth/background/service-factories/master-password-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../platform/background/service-factories/factory-options"; -import { - messagingServiceFactory, - MessagingServiceInitOptions, -} from "../../platform/background/service-factories/messaging-service.factory"; -import { - platformUtilsServiceFactory, - PlatformUtilsServiceInitOptions, -} from "../../platform/background/service-factories/platform-utils-service.factory"; -import { - stateEventRunnerServiceFactory, - StateEventRunnerServiceInitOptions, -} from "../../platform/background/service-factories/state-event-runner-service.factory"; -import { - StateServiceInitOptions, - stateServiceFactory, -} from "../../platform/background/service-factories/state-service.factory"; -import VaultTimeoutService from "../../services/vault-timeout/vault-timeout.service"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../vault/background/service_factories/cipher-service.factory"; -import { - collectionServiceFactory, - CollectionServiceInitOptions, -} from "../../vault/background/service_factories/collection-service.factory"; -import { - folderServiceFactory, - FolderServiceInitOptions, -} from "../../vault/background/service_factories/folder-service.factory"; - -import { searchServiceFactory, SearchServiceInitOptions } from "./search-service.factory"; -import { - vaultTimeoutSettingsServiceFactory, - VaultTimeoutSettingsServiceInitOptions, -} from "./vault-timeout-settings-service.factory"; - -type VaultTimeoutServiceFactoryOptions = FactoryOptions & { - vaultTimeoutServiceOptions: { - lockedCallback: (userId?: string) => Promise; - loggedOutCallback: (expired: boolean, userId?: string) => Promise; - }; -}; - -export type VaultTimeoutServiceInitOptions = VaultTimeoutServiceFactoryOptions & - AccountServiceInitOptions & - MasterPasswordServiceInitOptions & - CipherServiceInitOptions & - FolderServiceInitOptions & - CollectionServiceInitOptions & - PlatformUtilsServiceInitOptions & - MessagingServiceInitOptions & - SearchServiceInitOptions & - StateServiceInitOptions & - AuthServiceInitOptions & - VaultTimeoutSettingsServiceInitOptions & - StateEventRunnerServiceInitOptions; - -export function vaultTimeoutServiceFactory( - cache: { vaultTimeoutService?: AbstractVaultTimeoutService } & CachedServices, - opts: VaultTimeoutServiceInitOptions, -): Promise { - return factory( - cache, - "vaultTimeoutService", - opts, - async () => - new VaultTimeoutService( - await accountServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await cipherServiceFactory(cache, opts), - await folderServiceFactory(cache, opts), - await collectionServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await messagingServiceFactory(cache, opts), - await searchServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - await authServiceFactory(cache, opts), - await vaultTimeoutSettingsServiceFactory(cache, opts), - await stateEventRunnerServiceFactory(cache, opts), - opts.vaultTimeoutServiceOptions.lockedCallback, - opts.vaultTimeoutServiceOptions.loggedOutCallback, - ), - ); -} diff --git a/apps/browser/src/background/service-factories/vault-timeout-settings-service.factory.ts b/apps/browser/src/background/service-factories/vault-timeout-settings-service.factory.ts deleted file mode 100644 index 5f98d9764c3..00000000000 --- a/apps/browser/src/background/service-factories/vault-timeout-settings-service.factory.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { VaultTimeoutSettingsService as AbstractVaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; -import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; - -import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../admin-console/background/service-factories/policy-service.factory"; -import { - accountServiceFactory, - AccountServiceInitOptions, -} from "../../auth/background/service-factories/account-service.factory"; -import { - pinServiceFactory, - PinServiceInitOptions, -} from "../../auth/background/service-factories/pin-service.factory"; -import { - tokenServiceFactory, - TokenServiceInitOptions, -} from "../../auth/background/service-factories/token-service.factory"; -import { - userDecryptionOptionsServiceFactory, - UserDecryptionOptionsServiceInitOptions, -} from "../../auth/background/service-factories/user-decryption-options-service.factory"; -import { - biometricStateServiceFactory, - BiometricStateServiceInitOptions, -} from "../../platform/background/service-factories/biometric-state-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../platform/background/service-factories/factory-options"; -import { - logServiceFactory, - LogServiceInitOptions, -} from "../../platform/background/service-factories/log-service.factory"; -import { - StateProviderInitOptions, - stateProviderFactory, -} from "../../platform/background/service-factories/state-provider.factory"; - -type VaultTimeoutSettingsServiceFactoryOptions = FactoryOptions; - -export type VaultTimeoutSettingsServiceInitOptions = VaultTimeoutSettingsServiceFactoryOptions & - AccountServiceInitOptions & - PinServiceInitOptions & - UserDecryptionOptionsServiceInitOptions & - CryptoServiceInitOptions & - TokenServiceInitOptions & - PolicyServiceInitOptions & - BiometricStateServiceInitOptions & - StateProviderInitOptions & - LogServiceInitOptions; - -export function vaultTimeoutSettingsServiceFactory( - cache: { vaultTimeoutSettingsService?: AbstractVaultTimeoutSettingsService } & CachedServices, - opts: VaultTimeoutSettingsServiceInitOptions, -): Promise { - return factory( - cache, - "vaultTimeoutSettingsService", - opts, - async () => - new VaultTimeoutSettingsService( - await accountServiceFactory(cache, opts), - await pinServiceFactory(cache, opts), - await userDecryptionOptionsServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - await policyServiceFactory(cache, opts), - await biometricStateServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await logServiceFactory(cache, opts), - VaultTimeoutStringType.OnRestart, // default vault timeout - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/active-user-state-provider.factory.ts b/apps/browser/src/platform/background/service-factories/active-user-state-provider.factory.ts deleted file mode 100644 index ff46ca84e8c..00000000000 --- a/apps/browser/src/platform/background/service-factories/active-user-state-provider.factory.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ActiveUserStateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed -import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-active-user-state.provider"; - -import { - AccountServiceInitOptions, - accountServiceFactory, -} from "../../../auth/background/service-factories/account-service.factory"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - SingleUserStateProviderInitOptions, - singleUserStateProviderFactory, -} from "./single-user-state-provider.factory"; - -type ActiveUserStateProviderFactory = FactoryOptions; - -export type ActiveUserStateProviderInitOptions = ActiveUserStateProviderFactory & - AccountServiceInitOptions & - SingleUserStateProviderInitOptions; - -export async function activeUserStateProviderFactory( - cache: { activeUserStateProvider?: ActiveUserStateProvider } & CachedServices, - opts: ActiveUserStateProviderInitOptions, -): Promise { - return factory( - cache, - "activeUserStateProvider", - opts, - async () => - new DefaultActiveUserStateProvider( - await accountServiceFactory(cache, opts), - await singleUserStateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/api-service.factory.ts b/apps/browser/src/platform/background/service-factories/api-service.factory.ts deleted file mode 100644 index bfae93f3d8a..00000000000 --- a/apps/browser/src/platform/background/service-factories/api-service.factory.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { ApiService as AbstractApiService } from "@bitwarden/common/abstractions/api.service"; -import { ApiService } from "@bitwarden/common/services/api.service"; - -import { - tokenServiceFactory, - TokenServiceInitOptions, -} from "../../../auth/background/service-factories/token-service.factory"; -import { - vaultTimeoutSettingsServiceFactory, - VaultTimeoutSettingsServiceInitOptions, -} from "../../../background/service-factories/vault-timeout-settings-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../background/service-factories/factory-options"; - -import { AppIdServiceInitOptions, appIdServiceFactory } from "./app-id-service.factory"; -import { - environmentServiceFactory, - EnvironmentServiceInitOptions, -} from "./environment-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "./platform-utils-service.factory"; - -type ApiServiceFactoryOptions = FactoryOptions & { - apiServiceOptions: { - logoutCallback: (expired: boolean) => Promise; - customUserAgent?: string; - }; -}; - -export type ApiServiceInitOptions = ApiServiceFactoryOptions & - TokenServiceInitOptions & - PlatformUtilsServiceInitOptions & - EnvironmentServiceInitOptions & - AppIdServiceInitOptions & - VaultTimeoutSettingsServiceInitOptions; - -export function apiServiceFactory( - cache: { apiService?: AbstractApiService } & CachedServices, - opts: ApiServiceInitOptions, -): Promise { - return factory( - cache, - "apiService", - opts, - async () => - new ApiService( - await tokenServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await environmentServiceFactory(cache, opts), - await appIdServiceFactory(cache, opts), - await vaultTimeoutSettingsServiceFactory(cache, opts), - opts.apiServiceOptions.logoutCallback, - opts.apiServiceOptions.customUserAgent, - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/app-id-service.factory.ts b/apps/browser/src/platform/background/service-factories/app-id-service.factory.ts deleted file mode 100644 index c43584cba72..00000000000 --- a/apps/browser/src/platform/background/service-factories/app-id-service.factory.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { AppIdService as AbstractAppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { AppIdService } from "@bitwarden/common/platform/services/app-id.service"; - -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "./global-state-provider.factory"; - -type AppIdServiceFactoryOptions = FactoryOptions; - -export type AppIdServiceInitOptions = AppIdServiceFactoryOptions & GlobalStateProviderInitOptions; - -export function appIdServiceFactory( - cache: { appIdService?: AbstractAppIdService } & CachedServices, - opts: AppIdServiceInitOptions, -): Promise { - return factory( - cache, - "appIdService", - opts, - async () => new AppIdService(await globalStateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/billing-account-profile-state-service.factory.ts b/apps/browser/src/platform/background/service-factories/billing-account-profile-state-service.factory.ts deleted file mode 100644 index 378707d6be3..00000000000 --- a/apps/browser/src/platform/background/service-factories/billing-account-profile-state-service.factory.ts +++ /dev/null @@ -1,25 +0,0 @@ -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 { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { StateProviderInitOptions, stateProviderFactory } from "./state-provider.factory"; - -type BillingAccountProfileStateServiceFactoryOptions = FactoryOptions; - -export type BillingAccountProfileStateServiceInitOptions = - BillingAccountProfileStateServiceFactoryOptions & StateProviderInitOptions; - -export function billingAccountProfileStateServiceFactory( - cache: { - billingAccountProfileStateService?: BillingAccountProfileStateService; - } & CachedServices, - opts: BillingAccountProfileStateServiceInitOptions, -): Promise { - return factory( - cache, - "billingAccountProfileStateService", - opts, - async () => - new DefaultBillingAccountProfileStateService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/biometric-state-service.factory.ts b/apps/browser/src/platform/background/service-factories/biometric-state-service.factory.ts deleted file mode 100644 index d2d4d4f9835..00000000000 --- a/apps/browser/src/platform/background/service-factories/biometric-state-service.factory.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { - BiometricStateService, - DefaultBiometricStateService, -} from "@bitwarden/common/platform/biometrics/biometric-state.service"; - -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { StateProviderInitOptions, stateProviderFactory } from "./state-provider.factory"; - -type BiometricStateServiceFactoryOptions = FactoryOptions; - -export type BiometricStateServiceInitOptions = BiometricStateServiceFactoryOptions & - StateProviderInitOptions; - -export function biometricStateServiceFactory( - cache: { biometricStateService?: BiometricStateService } & CachedServices, - opts: BiometricStateServiceInitOptions, -): Promise { - return factory( - cache, - "biometricStateService", - opts, - async () => new DefaultBiometricStateService(await stateProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/browser-script-injector-service.factory.ts b/apps/browser/src/platform/background/service-factories/browser-script-injector-service.factory.ts deleted file mode 100644 index e9a8ee379a8..00000000000 --- a/apps/browser/src/platform/background/service-factories/browser-script-injector-service.factory.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../background/service-factories/log-service.factory"; -import { BrowserScriptInjectorService } from "../../services/browser-script-injector.service"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "./platform-utils-service.factory"; - -type BrowserScriptInjectorServiceOptions = FactoryOptions; - -export type BrowserScriptInjectorServiceInitOptions = BrowserScriptInjectorServiceOptions & - PlatformUtilsServiceInitOptions & - LogServiceInitOptions; - -export function browserScriptInjectorServiceFactory( - cache: { browserScriptInjectorService?: BrowserScriptInjectorService } & CachedServices, - opts: BrowserScriptInjectorServiceInitOptions, -): Promise { - return factory( - cache, - "browserScriptInjectorService", - opts, - async () => - new BrowserScriptInjectorService( - await platformUtilsServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/config-api.service.factory.ts b/apps/browser/src/platform/background/service-factories/config-api.service.factory.ts deleted file mode 100644 index 3d7d508832b..00000000000 --- a/apps/browser/src/platform/background/service-factories/config-api.service.factory.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ConfigApiServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config-api.service.abstraction"; -import { ConfigApiService } from "@bitwarden/common/platform/services/config/config-api.service"; - -import { - tokenServiceFactory, - TokenServiceInitOptions, -} from "../../../auth/background/service-factories/token-service.factory"; - -import { apiServiceFactory, ApiServiceInitOptions } from "./api-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; - -type ConfigApiServiceFactoyOptions = FactoryOptions; - -export type ConfigApiServiceInitOptions = ConfigApiServiceFactoyOptions & - ApiServiceInitOptions & - TokenServiceInitOptions; - -export function configApiServiceFactory( - cache: { configApiService?: ConfigApiServiceAbstraction } & CachedServices, - opts: ConfigApiServiceInitOptions, -): Promise { - return factory( - cache, - "configApiService", - opts, - async () => - new ConfigApiService( - await apiServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/config-service.factory.ts b/apps/browser/src/platform/background/service-factories/config-service.factory.ts deleted file mode 100644 index a899f8fd9af..00000000000 --- a/apps/browser/src/platform/background/service-factories/config-service.factory.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; -import { DefaultConfigService } from "@bitwarden/common/platform/services/config/default-config.service"; - -import { configApiServiceFactory, ConfigApiServiceInitOptions } from "./config-api.service.factory"; -import { - environmentServiceFactory, - EnvironmentServiceInitOptions, -} from "./environment-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; -import { stateProviderFactory, StateProviderInitOptions } from "./state-provider.factory"; - -type ConfigServiceFactoryOptions = FactoryOptions; - -export type ConfigServiceInitOptions = ConfigServiceFactoryOptions & - ConfigApiServiceInitOptions & - EnvironmentServiceInitOptions & - LogServiceInitOptions & - StateProviderInitOptions; - -export function configServiceFactory( - cache: { configService?: ConfigService } & CachedServices, - opts: ConfigServiceInitOptions, -): Promise { - return factory( - cache, - "configService", - opts, - async () => - new DefaultConfigService( - await configApiServiceFactory(cache, opts), - await environmentServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/crypto-function-service.factory.ts b/apps/browser/src/platform/background/service-factories/crypto-function-service.factory.ts deleted file mode 100644 index b9a9cc66483..00000000000 --- a/apps/browser/src/platform/background/service-factories/crypto-function-service.factory.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; - -import { CachedServices, factory, FactoryOptions } from "./factory-options"; - -type CryptoFunctionServiceFactoryOptions = FactoryOptions & { - cryptoFunctionServiceOptions: { - win: Window | typeof globalThis; - }; -}; - -export type CryptoFunctionServiceInitOptions = CryptoFunctionServiceFactoryOptions; - -export function cryptoFunctionServiceFactory( - cache: { cryptoFunctionService?: CryptoFunctionService } & CachedServices, - opts: CryptoFunctionServiceFactoryOptions, -): Promise { - return factory( - cache, - "cryptoFunctionService", - opts, - () => new WebCryptoFunctionService(opts.cryptoFunctionServiceOptions.win), - ); -} 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 deleted file mode 100644 index 35466a1988d..00000000000 --- a/apps/browser/src/platform/background/service-factories/crypto-service.factory.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { CryptoService as AbstractCryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; - -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, -} from "../../../auth/background/service-factories/master-password-service.factory"; -import { - PinServiceInitOptions, - pinServiceFactory, -} from "../../../auth/background/service-factories/pin-service.factory"; -import { - StateServiceInitOptions, - stateServiceFactory, -} from "../../../platform/background/service-factories/state-service.factory"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../background/service-factories/log-service.factory"; -import { BrowserCryptoService } from "../../services/browser-crypto.service"; - -import { - BiometricStateServiceInitOptions, - biometricStateServiceFactory, -} from "./biometric-state-service.factory"; -import { - cryptoFunctionServiceFactory, - CryptoFunctionServiceInitOptions, -} from "./crypto-function-service.factory"; -import { encryptServiceFactory, EncryptServiceInitOptions } from "./encrypt-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "./key-generation-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "./platform-utils-service.factory"; -import { StateProviderInitOptions, stateProviderFactory } from "./state-provider.factory"; - -type CryptoServiceFactoryOptions = FactoryOptions; - -export type CryptoServiceInitOptions = CryptoServiceFactoryOptions & - PinServiceInitOptions & - MasterPasswordServiceInitOptions & - KeyGenerationServiceInitOptions & - CryptoFunctionServiceInitOptions & - EncryptServiceInitOptions & - PlatformUtilsServiceInitOptions & - LogServiceInitOptions & - StateServiceInitOptions & - AccountServiceInitOptions & - StateProviderInitOptions & - BiometricStateServiceInitOptions & - KdfConfigServiceInitOptions; - -export function cryptoServiceFactory( - cache: { cryptoService?: AbstractCryptoService } & CachedServices, - opts: CryptoServiceInitOptions, -): Promise { - return factory( - cache, - "cryptoService", - opts, - async () => - new BrowserCryptoService( - await pinServiceFactory(cache, opts), - await internalMasterPasswordServiceFactory(cache, opts), - await keyGenerationServiceFactory(cache, opts), - await cryptoFunctionServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - 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 deleted file mode 100644 index 2c5f8f24194..00000000000 --- a/apps/browser/src/platform/background/service-factories/derived-state-provider.factory.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { DerivedStateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- For dependency creation -import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; - -type DerivedStateProviderFactoryOptions = FactoryOptions; - -export type DerivedStateProviderInitOptions = DerivedStateProviderFactoryOptions; - -export async function derivedStateProviderFactory( - cache: { derivedStateProvider?: DerivedStateProvider } & CachedServices, - opts: DerivedStateProviderInitOptions, -): Promise { - return factory(cache, "derivedStateProvider", opts, async () => new InlineDerivedStateProvider()); -} diff --git a/apps/browser/src/platform/background/service-factories/encrypt-service.factory.ts b/apps/browser/src/platform/background/service-factories/encrypt-service.factory.ts deleted file mode 100644 index 055e5235914..00000000000 --- a/apps/browser/src/platform/background/service-factories/encrypt-service.factory.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation"; - -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../background/service-factories/log-service.factory"; - -import { - cryptoFunctionServiceFactory, - CryptoFunctionServiceInitOptions, -} from "./crypto-function-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; - -type EncryptServiceFactoryOptions = FactoryOptions & { - encryptServiceOptions: { - logMacFailures: boolean; - }; -}; - -export type EncryptServiceInitOptions = EncryptServiceFactoryOptions & - CryptoFunctionServiceInitOptions & - LogServiceInitOptions; - -export function encryptServiceFactory( - cache: { encryptService?: EncryptServiceImplementation } & CachedServices, - opts: EncryptServiceInitOptions, -): Promise { - return factory( - cache, - "encryptService", - opts, - async () => - new EncryptServiceImplementation( - await cryptoFunctionServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - opts.encryptServiceOptions.logMacFailures, - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/environment-service.factory.ts b/apps/browser/src/platform/background/service-factories/environment-service.factory.ts deleted file mode 100644 index 38ab62de482..00000000000 --- a/apps/browser/src/platform/background/service-factories/environment-service.factory.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { - accountServiceFactory, - AccountServiceInitOptions, -} from "../../../auth/background/service-factories/account-service.factory"; -import { BrowserEnvironmentService } from "../../services/browser-environment.service"; - -import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; -import { stateProviderFactory, StateProviderInitOptions } from "./state-provider.factory"; - -type EnvironmentServiceFactoryOptions = FactoryOptions; - -export type EnvironmentServiceInitOptions = EnvironmentServiceFactoryOptions & - StateProviderInitOptions & - AccountServiceInitOptions & - LogServiceInitOptions; - -export function environmentServiceFactory( - cache: { environmentService?: BrowserEnvironmentService } & CachedServices, - opts: EnvironmentServiceInitOptions, -): Promise { - return factory( - cache, - "environmentService", - opts, - async () => - new BrowserEnvironmentService( - await logServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - await accountServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/factory-options.ts b/apps/browser/src/platform/background/service-factories/factory-options.ts deleted file mode 100644 index 4219a67181e..00000000000 --- a/apps/browser/src/platform/background/service-factories/factory-options.ts +++ /dev/null @@ -1,30 +0,0 @@ -export type CachedServices = Record; - -export type FactoryOptions = { - alwaysInitializeNewService?: boolean; - doNotStoreInitializedService?: boolean; - [optionsKey: string]: unknown; -}; - -export async function factory< - TCache extends CachedServices, - TName extends keyof TCache, - TOpts extends FactoryOptions, ->( - cachedServices: TCache, - name: TName, - opts: TOpts, - factory: () => TCache[TName] | Promise, -): Promise { - let instance = cachedServices[name]; - if (opts.alwaysInitializeNewService || !instance) { - const instanceOrPromise = factory(); - instance = instanceOrPromise instanceof Promise ? await instanceOrPromise : instanceOrPromise; - } - - if (!opts.doNotStoreInitializedService) { - cachedServices[name] = instance; - } - - return instance as TCache[TName]; -} diff --git a/apps/browser/src/platform/background/service-factories/file-upload-service.factory.ts b/apps/browser/src/platform/background/service-factories/file-upload-service.factory.ts deleted file mode 100644 index 77b5703619b..00000000000 --- a/apps/browser/src/platform/background/service-factories/file-upload-service.factory.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/platform/abstractions/file-upload/file-upload.service"; -import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../background/service-factories/factory-options"; - -import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; - -type FileUploadServiceFactoryOptions = FactoryOptions; - -export type FileUploadServiceInitOptions = FileUploadServiceFactoryOptions & LogServiceInitOptions; - -export function fileUploadServiceFactory( - cache: { fileUploadService?: FileUploadServiceAbstraction } & CachedServices, - opts: FileUploadServiceInitOptions, -): Promise { - return factory( - cache, - "fileUploadService", - opts, - async () => new FileUploadService(await logServiceFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/global-state-provider.factory.ts b/apps/browser/src/platform/background/service-factories/global-state-provider.factory.ts deleted file mode 100644 index 154c212f046..00000000000 --- a/apps/browser/src/platform/background/service-factories/global-state-provider.factory.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { GlobalStateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed -import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - StorageServiceProviderInitOptions, - storageServiceProviderFactory, -} from "./storage-service-provider.factory"; - -type GlobalStateProviderFactoryOptions = FactoryOptions; - -export type GlobalStateProviderInitOptions = GlobalStateProviderFactoryOptions & - StorageServiceProviderInitOptions; - -export async function globalStateProviderFactory( - cache: { globalStateProvider?: GlobalStateProvider } & CachedServices, - opts: GlobalStateProviderInitOptions, -): Promise { - return factory( - cache, - "globalStateProvider", - opts, - async () => new DefaultGlobalStateProvider(await storageServiceProviderFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/i18n-service.factory.ts b/apps/browser/src/platform/background/service-factories/i18n-service.factory.ts deleted file mode 100644 index 9f9580df843..00000000000 --- a/apps/browser/src/platform/background/service-factories/i18n-service.factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { I18nService as AbstractI18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { I18nService as BaseI18nService } from "@bitwarden/common/platform/services/i18n.service"; - -import I18nService from "../../services/i18n.service"; - -import { FactoryOptions, CachedServices, factory } from "./factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "./global-state-provider.factory"; - -type I18nServiceFactoryOptions = FactoryOptions & { - i18nServiceOptions: { - systemLanguage: string; - }; -}; - -export type I18nServiceInitOptions = I18nServiceFactoryOptions & GlobalStateProviderInitOptions; - -export async function i18nServiceFactory( - cache: { i18nService?: AbstractI18nService } & CachedServices, - opts: I18nServiceInitOptions, -): Promise { - const service = await factory( - cache, - "i18nService", - opts, - async () => - new I18nService( - opts.i18nServiceOptions.systemLanguage, - await globalStateProviderFactory(cache, opts), - ), - ); - if (!(service as BaseI18nService as any).inited) { - await (service as BaseI18nService).init(); - } - return service; -} diff --git a/apps/browser/src/platform/background/service-factories/key-generation-service.factory.ts b/apps/browser/src/platform/background/service-factories/key-generation-service.factory.ts deleted file mode 100644 index accba0023aa..00000000000 --- a/apps/browser/src/platform/background/service-factories/key-generation-service.factory.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service"; -import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service"; - -import { - cryptoFunctionServiceFactory, - CryptoFunctionServiceInitOptions, -} from "./crypto-function-service.factory"; -import { FactoryOptions, CachedServices, factory } from "./factory-options"; - -type KeyGenerationServiceFactoryOptions = FactoryOptions; - -export type KeyGenerationServiceInitOptions = KeyGenerationServiceFactoryOptions & - CryptoFunctionServiceInitOptions; - -export function keyGenerationServiceFactory( - cache: { keyGenerationService?: KeyGenerationServiceAbstraction } & CachedServices, - opts: KeyGenerationServiceInitOptions, -): Promise { - return factory( - cache, - "keyGenerationService", - opts, - async () => new KeyGenerationService(await cryptoFunctionServiceFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/log-service.factory.ts b/apps/browser/src/platform/background/service-factories/log-service.factory.ts deleted file mode 100644 index 7e171ee3104..00000000000 --- a/apps/browser/src/platform/background/service-factories/log-service.factory.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { LogLevelType } from "@bitwarden/common/platform/enums/log-level-type.enum"; -import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; - -import { FactoryOptions, CachedServices, factory } from "./factory-options"; - -type LogServiceFactoryOptions = FactoryOptions & { - logServiceOptions: { - isDev: boolean; - filter?: (level: LogLevelType) => boolean; - }; -}; - -export type LogServiceInitOptions = LogServiceFactoryOptions; - -export function logServiceFactory( - cache: { logService?: LogService } & CachedServices, - opts: LogServiceInitOptions, -): Promise { - return factory( - cache, - "logService", - opts, - () => new ConsoleLogService(opts.logServiceOptions.isDev, opts.logServiceOptions.filter), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/message-sender.factory.ts b/apps/browser/src/platform/background/service-factories/message-sender.factory.ts deleted file mode 100644 index 6f50b4b8f57..00000000000 --- a/apps/browser/src/platform/background/service-factories/message-sender.factory.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { MessageSender } from "@bitwarden/common/platform/messaging"; - -import { CachedServices, factory, FactoryOptions } from "./factory-options"; - -type MessagingServiceFactoryOptions = FactoryOptions; - -export type MessageSenderInitOptions = MessagingServiceFactoryOptions; - -export function messageSenderFactory( - cache: { messagingService?: MessageSender } & CachedServices, - opts: MessageSenderInitOptions, -): Promise { - // NOTE: Name needs to match that of MainBackground property until we delete these. - return factory(cache, "messagingService", opts, () => { - throw new Error("Not implemented, not expected to be used."); - }); -} diff --git a/apps/browser/src/platform/background/service-factories/messaging-service.factory.ts b/apps/browser/src/platform/background/service-factories/messaging-service.factory.ts deleted file mode 100644 index 20c6e3f424b..00000000000 --- a/apps/browser/src/platform/background/service-factories/messaging-service.factory.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Export old messaging service stuff to minimize changes -export { - messageSenderFactory as messagingServiceFactory, - MessageSenderInitOptions as MessagingServiceInitOptions, -} from "./message-sender.factory"; 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 deleted file mode 100644 index 090531f7cfc..00000000000 --- a/apps/browser/src/platform/background/service-factories/migration-runner.factory.ts +++ /dev/null @@ -1,34 +0,0 @@ -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"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { LogServiceInitOptions, logServiceFactory } from "./log-service.factory"; -import { - DiskStorageServiceInitOptions, - diskStorageServiceFactory, -} from "./storage-service.factory"; - -type MigrationRunnerFactory = FactoryOptions; - -export type MigrationRunnerInitOptions = MigrationRunnerFactory & - DiskStorageServiceInitOptions & - LogServiceInitOptions; - -export async function migrationRunnerFactory( - cache: { migrationRunner?: MigrationRunner } & CachedServices, - opts: MigrationRunnerInitOptions, -): Promise { - return factory( - cache, - "migrationRunner", - opts, - async () => - new MigrationRunner( - await diskStorageServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - new MigrationBuilderService(), - ClientType.Browser, - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/platform-utils-service.factory.ts b/apps/browser/src/platform/background/service-factories/platform-utils-service.factory.ts deleted file mode 100644 index 2cd34ba412b..00000000000 --- a/apps/browser/src/platform/background/service-factories/platform-utils-service.factory.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; - -import { BackgroundPlatformUtilsService } from "../../services/platform-utils/background-platform-utils.service"; - -import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { MessagingServiceInitOptions, messagingServiceFactory } from "./messaging-service.factory"; - -type PlatformUtilsServiceFactoryOptions = FactoryOptions & { - platformUtilsServiceOptions: { - clipboardWriteCallback: (clipboardValue: string, clearMs: number) => Promise; - biometricCallback: () => Promise; - win: Window & typeof globalThis; - }; -}; - -export type PlatformUtilsServiceInitOptions = PlatformUtilsServiceFactoryOptions & - MessagingServiceInitOptions; - -export function platformUtilsServiceFactory( - cache: { platformUtilsService?: PlatformUtilsService } & CachedServices, - opts: PlatformUtilsServiceInitOptions, -): Promise { - return factory( - cache, - "platformUtilsService", - opts, - async () => - new BackgroundPlatformUtilsService( - await messagingServiceFactory(cache, opts), - opts.platformUtilsServiceOptions.clipboardWriteCallback, - opts.platformUtilsServiceOptions.biometricCallback, - opts.platformUtilsServiceOptions.win, - null, - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/single-user-state-provider.factory.ts b/apps/browser/src/platform/background/service-factories/single-user-state-provider.factory.ts deleted file mode 100644 index 87eaa8e95a5..00000000000 --- a/apps/browser/src/platform/background/service-factories/single-user-state-provider.factory.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { SingleUserStateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed -import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - StateEventRegistrarServiceInitOptions, - stateEventRegistrarServiceFactory, -} from "./state-event-registrar-service.factory"; -import { - StorageServiceProviderInitOptions, - storageServiceProviderFactory, -} from "./storage-service-provider.factory"; - -type SingleUserStateProviderFactoryOptions = FactoryOptions; - -export type SingleUserStateProviderInitOptions = SingleUserStateProviderFactoryOptions & - StorageServiceProviderInitOptions & - StateEventRegistrarServiceInitOptions; - -export async function singleUserStateProviderFactory( - cache: { singleUserStateProvider?: SingleUserStateProvider } & CachedServices, - opts: SingleUserStateProviderInitOptions, -): Promise { - return factory( - cache, - "singleUserStateProvider", - opts, - async () => - new DefaultSingleUserStateProvider( - await storageServiceProviderFactory(cache, opts), - await stateEventRegistrarServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/state-event-registrar-service.factory.ts b/apps/browser/src/platform/background/service-factories/state-event-registrar-service.factory.ts deleted file mode 100644 index ca203a810b8..00000000000 --- a/apps/browser/src/platform/background/service-factories/state-event-registrar-service.factory.ts +++ /dev/null @@ -1,36 +0,0 @@ -// eslint-disable-next-line import/no-restricted-paths -import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "./global-state-provider.factory"; -import { - StorageServiceProviderInitOptions, - storageServiceProviderFactory, -} from "./storage-service-provider.factory"; - -type StateEventRegistrarServiceFactoryOptions = FactoryOptions; - -export type StateEventRegistrarServiceInitOptions = StateEventRegistrarServiceFactoryOptions & - GlobalStateProviderInitOptions & - StorageServiceProviderInitOptions; - -export async function stateEventRegistrarServiceFactory( - cache: { - stateEventRegistrarService?: StateEventRegistrarService; - } & CachedServices, - opts: StateEventRegistrarServiceInitOptions, -): Promise { - return factory( - cache, - "stateEventRegistrarService", - opts, - async () => - new StateEventRegistrarService( - await globalStateProviderFactory(cache, opts), - await storageServiceProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/state-event-runner-service.factory.ts b/apps/browser/src/platform/background/service-factories/state-event-runner-service.factory.ts deleted file mode 100644 index c81384cd4ac..00000000000 --- a/apps/browser/src/platform/background/service-factories/state-event-runner-service.factory.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { StateEventRunnerService } from "@bitwarden/common/platform/state"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "./global-state-provider.factory"; -import { - StorageServiceProviderInitOptions, - storageServiceProviderFactory, -} from "./storage-service-provider.factory"; - -type StateEventRunnerServiceFactoryOptions = FactoryOptions; - -export type StateEventRunnerServiceInitOptions = StateEventRunnerServiceFactoryOptions & - GlobalStateProviderInitOptions & - StorageServiceProviderInitOptions; - -export function stateEventRunnerServiceFactory( - cache: { stateEventRunnerService?: StateEventRunnerService } & CachedServices, - opts: StateEventRunnerServiceInitOptions, -): Promise { - return factory( - cache, - "stateEventRunnerService", - opts, - async () => - new StateEventRunnerService( - await globalStateProviderFactory(cache, opts), - await storageServiceProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/state-provider.factory.ts b/apps/browser/src/platform/background/service-factories/state-provider.factory.ts deleted file mode 100644 index b5ae9c709f9..00000000000 --- a/apps/browser/src/platform/background/service-factories/state-provider.factory.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { StateProvider } from "@bitwarden/common/platform/state"; -// eslint-disable-next-line import/no-restricted-paths -- We need the implementation to inject, but generally this should not be accessed -import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider"; - -import { - ActiveUserStateProviderInitOptions, - activeUserStateProviderFactory, -} from "./active-user-state-provider.factory"; -import { - DerivedStateProviderInitOptions, - derivedStateProviderFactory, -} from "./derived-state-provider.factory"; -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - GlobalStateProviderInitOptions, - globalStateProviderFactory, -} from "./global-state-provider.factory"; -import { - SingleUserStateProviderInitOptions, - singleUserStateProviderFactory, -} from "./single-user-state-provider.factory"; - -type StateProviderFactoryOptions = FactoryOptions; - -export type StateProviderInitOptions = StateProviderFactoryOptions & - GlobalStateProviderInitOptions & - ActiveUserStateProviderInitOptions & - SingleUserStateProviderInitOptions & - DerivedStateProviderInitOptions; - -export async function stateProviderFactory( - cache: { stateProvider?: StateProvider } & CachedServices, - opts: StateProviderInitOptions, -): Promise { - return factory( - cache, - "stateProvider", - opts, - async () => - new DefaultStateProvider( - await activeUserStateProviderFactory(cache, opts), - await singleUserStateProviderFactory(cache, opts), - await globalStateProviderFactory(cache, opts), - await derivedStateProviderFactory(cache, opts), - ), - ); -} 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 deleted file mode 100644 index 026a29668eb..00000000000 --- a/apps/browser/src/platform/background/service-factories/state-service.factory.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; - -import { - accountServiceFactory, - AccountServiceInitOptions, -} from "../../../auth/background/service-factories/account-service.factory"; -import { - tokenServiceFactory, - TokenServiceInitOptions, -} from "../../../auth/background/service-factories/token-service.factory"; -import { Account } from "../../../models/account"; -import { DefaultBrowserStateService } from "../../services/default-browser-state.service"; - -import { - environmentServiceFactory, - EnvironmentServiceInitOptions, -} from "./environment-service.factory"; -import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { logServiceFactory, LogServiceInitOptions } from "./log-service.factory"; -import { migrationRunnerFactory, MigrationRunnerInitOptions } from "./migration-runner.factory"; -import { - diskStorageServiceFactory, - secureStorageServiceFactory, - memoryStorageServiceFactory, - DiskStorageServiceInitOptions, - SecureStorageServiceInitOptions, - MemoryStorageServiceInitOptions, -} from "./storage-service.factory"; - -type StateServiceFactoryOptions = FactoryOptions & { - stateServiceOptions: { - stateFactory: StateFactory; - }; -}; - -export type StateServiceInitOptions = StateServiceFactoryOptions & - DiskStorageServiceInitOptions & - SecureStorageServiceInitOptions & - MemoryStorageServiceInitOptions & - LogServiceInitOptions & - AccountServiceInitOptions & - EnvironmentServiceInitOptions & - TokenServiceInitOptions & - MigrationRunnerInitOptions; - -export async function stateServiceFactory( - cache: { stateService?: DefaultBrowserStateService } & CachedServices, - opts: StateServiceInitOptions, -): Promise { - const service = await factory( - cache, - "stateService", - opts, - async () => - new DefaultBrowserStateService( - await diskStorageServiceFactory(cache, opts), - await secureStorageServiceFactory(cache, opts), - await memoryStorageServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - opts.stateServiceOptions.stateFactory, - await accountServiceFactory(cache, opts), - await environmentServiceFactory(cache, opts), - await tokenServiceFactory(cache, opts), - await migrationRunnerFactory(cache, opts), - ), - ); - // TODO: If we run migration through a chrome installed/updated event we can turn off running migrations - await service.init(); - return service; -} diff --git a/apps/browser/src/platform/background/service-factories/storage-service-provider.factory.ts b/apps/browser/src/platform/background/service-factories/storage-service-provider.factory.ts deleted file mode 100644 index 8a2ddeb9e82..00000000000 --- a/apps/browser/src/platform/background/service-factories/storage-service-provider.factory.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { StorageServiceProvider } from "@bitwarden/common/platform/services/storage-service.provider"; - -import { CachedServices, FactoryOptions, factory } from "./factory-options"; -import { - DiskStorageServiceInitOptions, - MemoryStorageServiceInitOptions, - observableDiskStorageServiceFactory, - observableMemoryStorageServiceFactory, -} from "./storage-service.factory"; - -type StorageServiceProviderFactoryOptions = FactoryOptions; - -export type StorageServiceProviderInitOptions = StorageServiceProviderFactoryOptions & - MemoryStorageServiceInitOptions & - DiskStorageServiceInitOptions; - -export async function storageServiceProviderFactory( - cache: { - storageServiceProvider?: StorageServiceProvider; - } & CachedServices, - opts: StorageServiceProviderInitOptions, -): Promise { - return factory( - cache, - "storageServiceProvider", - opts, - async () => - new StorageServiceProvider( - await observableDiskStorageServiceFactory(cache, opts), - await observableMemoryStorageServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/platform/background/service-factories/storage-service.factory.ts b/apps/browser/src/platform/background/service-factories/storage-service.factory.ts deleted file mode 100644 index 764842d7516..00000000000 --- a/apps/browser/src/platform/background/service-factories/storage-service.factory.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - AbstractStorageService, - ObservableStorageService, -} from "@bitwarden/common/platform/abstractions/storage.service"; -import { Lazy } from "@bitwarden/common/platform/misc/lazy"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { MemoryStorageService } from "@bitwarden/common/platform/services/memory-storage.service"; - -import { BrowserApi } from "../../browser/browser-api"; -import BrowserLocalStorageService from "../../services/browser-local-storage.service"; -import BrowserMemoryStorageService from "../../services/browser-memory-storage.service"; -import { LocalBackedSessionStorageService } from "../../services/local-backed-session-storage.service"; -import { BackgroundMemoryStorageService } from "../../storage/background-memory-storage.service"; - -import { EncryptServiceInitOptions, encryptServiceFactory } from "./encrypt-service.factory"; -import { CachedServices, factory, FactoryOptions } from "./factory-options"; -import { - KeyGenerationServiceInitOptions, - keyGenerationServiceFactory, -} from "./key-generation-service.factory"; -import { LogServiceInitOptions, logServiceFactory } from "./log-service.factory"; -import { - PlatformUtilsServiceInitOptions, - platformUtilsServiceFactory, -} from "./platform-utils-service.factory"; - -export type DiskStorageServiceInitOptions = FactoryOptions; -export type SecureStorageServiceInitOptions = FactoryOptions; -export type SessionStorageServiceInitOptions = FactoryOptions; -export type MemoryStorageServiceInitOptions = FactoryOptions & - EncryptServiceInitOptions & - KeyGenerationServiceInitOptions & - DiskStorageServiceInitOptions & - SessionStorageServiceInitOptions & - LogServiceInitOptions & - PlatformUtilsServiceInitOptions; - -export function diskStorageServiceFactory( - cache: { diskStorageService?: AbstractStorageService } & CachedServices, - opts: DiskStorageServiceInitOptions, -): Promise { - return factory(cache, "diskStorageService", opts, () => new BrowserLocalStorageService()); -} -export function observableDiskStorageServiceFactory( - cache: { - diskStorageService?: AbstractStorageService & ObservableStorageService; - } & CachedServices, - opts: DiskStorageServiceInitOptions, -): Promise { - return factory(cache, "diskStorageService", opts, () => new BrowserLocalStorageService()); -} - -export function secureStorageServiceFactory( - cache: { secureStorageService?: AbstractStorageService } & CachedServices, - opts: SecureStorageServiceInitOptions, -): Promise { - return factory(cache, "secureStorageService", opts, () => new BrowserLocalStorageService()); -} - -export function sessionStorageServiceFactory( - cache: { sessionStorageService?: AbstractStorageService } & CachedServices, - opts: SessionStorageServiceInitOptions, -): Promise { - return factory(cache, "sessionStorageService", opts, () => new BrowserMemoryStorageService()); -} - -export function memoryStorageServiceFactory( - cache: { memoryStorageService?: AbstractStorageService } & CachedServices, - opts: MemoryStorageServiceInitOptions, -): Promise { - return factory(cache, "memoryStorageService", opts, async () => { - if (BrowserApi.isManifestVersion(3)) { - return new LocalBackedSessionStorageService( - new Lazy(async () => { - const existingKey = await ( - await sessionStorageServiceFactory(cache, opts) - ).get("session-key"); - if (existingKey) { - return existingKey; - } - const { derivedKey } = await ( - await keyGenerationServiceFactory(cache, opts) - ).createKeyWithPurpose(128, "ephemeral", "bitwarden-ephemeral"); - await (await sessionStorageServiceFactory(cache, opts)).save("session-key", derivedKey); - return derivedKey; - }), - await diskStorageServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await platformUtilsServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - ); - } - return new MemoryStorageService(); - }); -} - -export function observableMemoryStorageServiceFactory( - cache: { - memoryStorageService?: AbstractStorageService & ObservableStorageService; - } & CachedServices, - opts: MemoryStorageServiceInitOptions, -): Promise { - return factory(cache, "memoryStorageService", opts, async () => { - return new BackgroundMemoryStorageService(); - }); -} diff --git a/apps/browser/src/platform/listeners/combine.spec.ts b/apps/browser/src/platform/listeners/combine.spec.ts deleted file mode 100644 index 10a0fd30d1d..00000000000 --- a/apps/browser/src/platform/listeners/combine.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { combine } from "./combine"; - -describe("combine", () => { - it("runs", async () => { - const combined = combine([ - (arg: Record, serviceCache: Record) => { - arg["one"] = true; - serviceCache["one"] = true; - return Promise.resolve(); - }, - (arg: Record, serviceCache: Record) => { - if (serviceCache["one"] !== true) { - throw new Error("One should have ran."); - } - arg["two"] = true; - return Promise.resolve(); - }, - ]); - - const arg: Record = {}; - await combined(arg); - - expect(arg["one"]).toBeTruthy(); - - expect(arg["two"]).toBeTruthy(); - }); -}); diff --git a/apps/browser/src/platform/listeners/combine.ts b/apps/browser/src/platform/listeners/combine.ts deleted file mode 100644 index 4737da2cbf7..00000000000 --- a/apps/browser/src/platform/listeners/combine.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CachedServices } from "../background/service-factories/factory-options"; - -type Listener = (...args: [...T, CachedServices]) => Promise; - -export const combine = ( - listeners: Listener[], - startingServices: CachedServices = {}, -) => { - return async (...args: T) => { - const cachedServices = { ...startingServices }; - for (const listener of listeners) { - await listener(...[...args, cachedServices]); - } - }; -}; diff --git a/apps/browser/src/platform/listeners/index.ts b/apps/browser/src/platform/listeners/index.ts deleted file mode 100644 index 60e304402aa..00000000000 --- a/apps/browser/src/platform/listeners/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { CipherContextMenuHandler } from "../../autofill/browser/cipher-context-menu-handler"; -import { ContextMenuClickedHandler } from "../../autofill/browser/context-menu-clicked-handler"; - -import { combine } from "./combine"; -import { onCommandListener } from "./on-command-listener"; -import { onInstallListener } from "./on-install-listener"; -import { UpdateBadge } from "./update-badge"; - -const windowsOnFocusChangedListener = combine([ - UpdateBadge.windowsOnFocusChangedListener, - CipherContextMenuHandler.windowsOnFocusChangedListener, -]); - -const tabsOnActivatedListener = combine([ - UpdateBadge.tabsOnActivatedListener, - CipherContextMenuHandler.tabsOnActivatedListener, -]); - -const tabsOnReplacedListener = combine([ - UpdateBadge.tabsOnReplacedListener, - CipherContextMenuHandler.tabsOnReplacedListener, -]); - -const tabsOnUpdatedListener = combine([ - UpdateBadge.tabsOnUpdatedListener, - CipherContextMenuHandler.tabsOnUpdatedListener, -]); - -const contextMenusClickedListener = ContextMenuClickedHandler.onClickedListener; - -// TODO: All message listeners should be RuntimeMessage in Notifications follow up then this type annotation can be inferred -const runtimeMessageListener = combine< - [message: { command: string }, sender: chrome.runtime.MessageSender] ->([ - UpdateBadge.messageListener, - CipherContextMenuHandler.messageListener, - ContextMenuClickedHandler.messageListener, -]); - -export { - windowsOnFocusChangedListener, - tabsOnActivatedListener, - tabsOnReplacedListener, - tabsOnUpdatedListener, - contextMenusClickedListener, - runtimeMessageListener, - onCommandListener, - onInstallListener, -}; diff --git a/apps/browser/src/platform/listeners/on-command-listener.ts b/apps/browser/src/platform/listeners/on-command-listener.ts deleted file mode 100644 index fc2939dce82..00000000000 --- a/apps/browser/src/platform/listeners/on-command-listener.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; - -import { authServiceFactory } from "../../auth/background/service-factories/auth-service.factory"; -import { autofillServiceFactory } from "../../autofill/background/service_factories/autofill-service.factory"; -import { autofillSettingsServiceFactory } from "../../autofill/background/service_factories/autofill-settings-service.factory"; -import { GeneratePasswordToClipboardCommand } from "../../autofill/clipboard"; -import { AutofillTabCommand } from "../../autofill/commands/autofill-tab-command"; -import { Account } from "../../models/account"; -import { - passwordGenerationServiceFactory, - PasswordGenerationServiceInitOptions, -} from "../../tools/background/service_factories/password-generation-service.factory"; -import { CachedServices } from "../background/service-factories/factory-options"; -import { logServiceFactory } from "../background/service-factories/log-service.factory"; -import { BrowserApi } from "../browser/browser-api"; - -export const onCommandListener = async (command: string, tab: chrome.tabs.Tab) => { - switch (command) { - case "autofill_login": - await doAutoFillLogin(tab); - break; - case "generate_password": - await doGeneratePasswordToClipboard(tab); - break; - } -}; - -const doAutoFillLogin = async (tab: chrome.tabs.Tab): Promise => { - const cachedServices: CachedServices = {}; - const opts = { - cryptoFunctionServiceOptions: { - win: self, - }, - encryptServiceOptions: { - logMacFailures: true, - }, - logServiceOptions: { - isDev: false, - }, - platformUtilsServiceOptions: { - clipboardWriteCallback: () => Promise.resolve(), - biometricCallback: () => Promise.resolve(false), - win: self, - }, - stateServiceOptions: { - stateFactory: new StateFactory(GlobalState, Account), - }, - apiServiceOptions: { - logoutCallback: () => Promise.resolve(), - }, - keyConnectorServiceOptions: { - logoutCallback: () => Promise.resolve(), - }, - i18nServiceOptions: { - systemLanguage: BrowserApi.getUILanguage(), - }, - }; - const logService = await logServiceFactory(cachedServices, opts); - const authService = await authServiceFactory(cachedServices, opts); - const autofillService = await autofillServiceFactory(cachedServices, opts); - - const authStatus = await authService.getAuthStatus(); - if (authStatus < AuthenticationStatus.Unlocked) { - // TODO: Add back in unlock on autofill - logService.info("Currently not unlocked, MV3 does not support unlock on autofill currently."); - return; - } - - const command = new AutofillTabCommand(autofillService); - await command.doAutofillTabCommand(tab); -}; - -const doGeneratePasswordToClipboard = async (tab: chrome.tabs.Tab): Promise => { - const stateFactory = new StateFactory(GlobalState, Account); - - const cache = {}; - const options: PasswordGenerationServiceInitOptions = { - cryptoFunctionServiceOptions: { - win: self, - }, - encryptServiceOptions: { - logMacFailures: false, - }, - logServiceOptions: { - isDev: false, - }, - platformUtilsServiceOptions: { - biometricCallback: () => Promise.resolve(true), - clipboardWriteCallback: () => Promise.resolve(), - win: self, - }, - stateServiceOptions: { - stateFactory: stateFactory, - }, - autofillSettingsServiceOptions: { - stateFactory: autofillSettingsServiceFactory, - }, - }; - - const command = new GeneratePasswordToClipboardCommand( - await passwordGenerationServiceFactory(cache, options), - await autofillSettingsServiceFactory(cache, options), - ); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - command.generatePasswordToClipboard(tab); -}; diff --git a/apps/browser/src/platform/listeners/on-install-listener.ts b/apps/browser/src/platform/listeners/on-install-listener.ts deleted file mode 100644 index adf575a17a9..00000000000 --- a/apps/browser/src/platform/listeners/on-install-listener.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; - -import { Account } from "../../models/account"; -import { - EnvironmentServiceInitOptions, - environmentServiceFactory, -} from "../background/service-factories/environment-service.factory"; -import { BrowserApi } from "../browser/browser-api"; - -export async function onInstallListener(details: chrome.runtime.InstalledDetails) { - const cache = {}; - const opts: EnvironmentServiceInitOptions = { - encryptServiceOptions: { - logMacFailures: false, - }, - cryptoFunctionServiceOptions: { - win: self, - }, - logServiceOptions: { - isDev: false, - }, - stateServiceOptions: { - stateFactory: new StateFactory(GlobalState, Account), - }, - platformUtilsServiceOptions: { - win: self, - biometricCallback: async () => false, - clipboardWriteCallback: async () => {}, - }, - }; - const environmentService = await environmentServiceFactory(cache, opts); - - setTimeout(async () => { - if (details.reason != null && details.reason === chrome.runtime.OnInstalledReason.INSTALL) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - BrowserApi.createNewTab("https://bitwarden.com/browser-start/"); - - if (await environmentService.hasManagedEnvironment()) { - await environmentService.setUrlsToManagedEnvironment(); - } - } - }, 100); -} diff --git a/apps/browser/src/platform/listeners/update-badge.ts b/apps/browser/src/platform/listeners/update-badge.ts index c39cb8c8945..9256c27f37b 100644 --- a/apps/browser/src/platform/listeners/update-badge.ts +++ b/apps/browser/src/platform/listeners/update-badge.ts @@ -2,20 +2,12 @@ import { firstValueFrom } from "rxjs"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; -import { BadgeSettingsService } from "@bitwarden/common/autofill/services/badge-settings.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service"; -import { StateFactory } from "@bitwarden/common/platform/factories/state-factory"; +import { BadgeSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/badge-settings.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state"; -import { ContainerService } from "@bitwarden/common/platform/services/container.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { authServiceFactory } from "../../auth/background/service-factories/auth-service.factory"; -import { badgeSettingsServiceFactory } from "../../autofill/background/service_factories/badge-settings-service.factory"; -import { Account } from "../../models/account"; +import MainBackground from "../../background/main.background"; import IconDetails from "../../vault/background/models/icon-details"; -import { cipherServiceFactory } from "../../vault/background/service_factories/cipher-service.factory"; import { BrowserApi } from "../browser/browser-api"; import { BrowserPlatformUtilsService } from "../services/platform-utils/browser-platform-utils.service"; @@ -26,87 +18,23 @@ export type BadgeOptions = { export class UpdateBadge { private authService: AuthService; - private badgeSettingsService: BadgeSettingsService; + private badgeSettingsService: BadgeSettingsServiceAbstraction; private cipherService: CipherService; private badgeAction: typeof chrome.action | typeof chrome.browserAction; private sidebarAction: OperaSidebarAction | FirefoxSidebarAction; - private inited = false; private win: Window & typeof globalThis; - private static readonly listenedToCommands = [ - "updateBadge", - "loggedIn", - "unlocked", - "syncCompleted", - "bgUpdateContextMenu", - "editedCipher", - "addedCipher", - "deletedCipher", - ]; - - static async windowsOnFocusChangedListener( - windowId: number, - serviceCache: Record, - ) { - await new UpdateBadge(self).run({ windowId, existingServices: serviceCache }); - } - - static async tabsOnActivatedListener( - activeInfo: chrome.tabs.TabActiveInfo, - serviceCache: Record, - ) { - await new UpdateBadge(self).run({ - tabId: activeInfo.tabId, - existingServices: serviceCache, - windowId: activeInfo.windowId, - }); - } - - static async tabsOnReplacedListener( - addedTabId: number, - removedTabId: number, - serviceCache: Record, - ) { - await new UpdateBadge(self).run({ tabId: addedTabId, existingServices: serviceCache }); - } - - static async tabsOnUpdatedListener( - tabId: number, - changeInfo: chrome.tabs.TabChangeInfo, - tab: chrome.tabs.Tab, - serviceCache: Record, - ) { - await new UpdateBadge(self).run({ - tabId, - existingServices: serviceCache, - windowId: tab.windowId, - }); - } - - static async messageListener( - message: { command: string; tabId: number }, - serviceCache: Record, - ) { - if (!UpdateBadge.listenedToCommands.includes(message.command)) { - return; - } - - await new UpdateBadge(self).run({ existingServices: serviceCache }); - } - - constructor(win: Window & typeof globalThis) { + constructor(win: Window & typeof globalThis, services: MainBackground) { this.badgeAction = BrowserApi.getBrowserAction(); this.sidebarAction = BrowserApi.getSidebarAction(self); this.win = win; + + this.badgeSettingsService = services.badgeSettingsService; + this.authService = services.authService; + this.cipherService = services.cipherService; } - async run(opts?: { - tabId?: number; - windowId?: number; - existingServices?: Record; - }): Promise { - await this.initServices(opts?.existingServices); - + async run(opts?: { tabId?: number; windowId?: number }): Promise { const authStatus = await this.authService.getAuthStatus(); await this.setBadgeBackgroundColor(); @@ -150,8 +78,6 @@ export class UpdateBadge { } async setUnlocked(opts: BadgeOptions) { - await this.initServices(); - await this.setBadgeIcon(""); const enableBadgeCounter = await firstValueFrom(this.badgeSettingsService.enableBadgeCounter$); @@ -263,52 +189,6 @@ export class UpdateBadge { ); } - private async initServices(existingServiceCache?: Record): Promise { - if (this.inited) { - return this; - } - - const serviceCache: Record = existingServiceCache || {}; - const opts = { - cryptoFunctionServiceOptions: { win: self }, - encryptServiceOptions: { logMacFailures: false }, - logServiceOptions: { isDev: false }, - platformUtilsServiceOptions: { - clipboardWriteCallback: (clipboardValue: string, clearMs: number) => - Promise.reject("not implemented"), - biometricCallback: () => Promise.reject("not implemented"), - win: self, - }, - stateServiceOptions: { - stateFactory: new StateFactory(GlobalState, Account), - }, - apiServiceOptions: { - logoutCallback: () => Promise.reject("not implemented"), - }, - keyConnectorServiceOptions: { - logoutCallback: () => Promise.reject("not implemented"), - }, - i18nServiceOptions: { - systemLanguage: BrowserApi.getUILanguage(), - }, - }; - this.badgeSettingsService = await badgeSettingsServiceFactory(serviceCache, opts); - this.authService = await authServiceFactory(serviceCache, opts); - this.cipherService = await cipherServiceFactory(serviceCache, opts); - - // Needed for cipher decryption - if (!self.bitwardenContainerService) { - new ContainerService( - serviceCache.cryptoService as CryptoService, - serviceCache.encryptService as EncryptService, - ).attachToGlobal(self); - } - - this.inited = true; - - return this; - } - private isOperaSidebar( action: OperaSidebarAction | FirefoxSidebarAction, ): action is OperaSidebarAction { diff --git a/apps/browser/src/platform/offscreen-document/abstractions/offscreen-document.ts b/apps/browser/src/platform/offscreen-document/abstractions/offscreen-document.ts index 2a67d55c962..012f908f784 100644 --- a/apps/browser/src/platform/offscreen-document/abstractions/offscreen-document.ts +++ b/apps/browser/src/platform/offscreen-document/abstractions/offscreen-document.ts @@ -2,7 +2,6 @@ export type OffscreenDocumentExtensionMessage = { [key: string]: any; command: string; text?: string; - decryptRequest?: string; }; type OffscreenExtensionMessageEventParams = { @@ -14,7 +13,6 @@ export type OffscreenDocumentExtensionMessageHandlers = { [key: string]: ({ message, sender }: OffscreenExtensionMessageEventParams) => any; offscreenCopyToClipboard: ({ message }: OffscreenExtensionMessageEventParams) => any; offscreenReadFromClipboard: () => any; - offscreenDecryptItems: ({ message }: OffscreenExtensionMessageEventParams) => Promise; }; export interface OffscreenDocument { @@ -22,6 +20,7 @@ export interface OffscreenDocument { } export abstract class OffscreenDocumentService { + abstract offscreenApiSupported(): boolean; abstract withDocument( reasons: chrome.offscreen.Reason[], justification: string, diff --git a/apps/browser/src/platform/offscreen-document/offscreen-document.service.spec.ts b/apps/browser/src/platform/offscreen-document/offscreen-document.service.spec.ts index c9bdd823a52..da541403967 100644 --- a/apps/browser/src/platform/offscreen-document/offscreen-document.service.spec.ts +++ b/apps/browser/src/platform/offscreen-document/offscreen-document.service.spec.ts @@ -49,6 +49,12 @@ describe.each([ jest.resetAllMocks(); }); + describe("offscreenApiSupported", () => { + it("indicates whether the offscreen API is supported", () => { + expect(sut.offscreenApiSupported()).toBe(true); + }); + }); + describe("withDocument", () => { it("creates a document when none exists", async () => { await sut.withDocument(reasons, justification, () => {}); diff --git a/apps/browser/src/platform/offscreen-document/offscreen-document.service.ts b/apps/browser/src/platform/offscreen-document/offscreen-document.service.ts index a260e3ca6c8..3a1227ea5e2 100644 --- a/apps/browser/src/platform/offscreen-document/offscreen-document.service.ts +++ b/apps/browser/src/platform/offscreen-document/offscreen-document.service.ts @@ -1,10 +1,16 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -export class DefaultOffscreenDocumentService implements DefaultOffscreenDocumentService { +import { OffscreenDocumentService } from "./abstractions/offscreen-document"; + +export class DefaultOffscreenDocumentService implements OffscreenDocumentService { private workerCount = 0; constructor(private logService: LogService) {} + offscreenApiSupported(): boolean { + return typeof chrome.offscreen !== "undefined"; + } + async withDocument( reasons: chrome.offscreen.Reason[], justification: string, diff --git a/apps/browser/src/platform/offscreen-document/offscreen-document.spec.ts b/apps/browser/src/platform/offscreen-document/offscreen-document.spec.ts index 9d3cadbba85..933cd08c2ea 100644 --- a/apps/browser/src/platform/offscreen-document/offscreen-document.spec.ts +++ b/apps/browser/src/platform/offscreen-document/offscreen-document.spec.ts @@ -1,25 +1,7 @@ -import { mock } from "jest-mock-extended"; - -import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; -import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; - import { flushPromises, sendExtensionRuntimeMessage } from "../../autofill/spec/testing-utils"; import { BrowserApi } from "../browser/browser-api"; import BrowserClipboardService from "../services/browser-clipboard.service"; -jest.mock( - "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation", - () => ({ - MultithreadEncryptServiceImplementation: class MultithreadEncryptServiceImplementation { - getDecryptedItemsFromWorker = async ( - items: Decryptable[], - _key: SymmetricCryptoKey, - ): Promise => JSON.stringify(items); - }, - }), -); - describe("OffscreenDocument", () => { const browserApiMessageListenerSpy = jest.spyOn(BrowserApi, "messageListener"); const browserClipboardServiceCopySpy = jest.spyOn(BrowserClipboardService, "copy"); @@ -78,37 +60,5 @@ describe("OffscreenDocument", () => { expect(browserClipboardServiceReadSpy).toHaveBeenCalledWith(window); }); }); - - describe("handleOffscreenDecryptItems", () => { - it("returns an empty array as a string if the decrypt request is not present in the message", async () => { - let response: string | undefined; - sendExtensionRuntimeMessage( - { command: "offscreenDecryptItems" }, - mock(), - (res: string) => (response = res), - ); - await flushPromises(); - - expect(response).toBe("[]"); - }); - - it("decrypts the items and sends back the response as a string", async () => { - const items = [{ id: "test" }]; - const key = { id: "test" }; - const decryptRequest = JSON.stringify({ items, key }); - let response: string | undefined; - - sendExtensionRuntimeMessage( - { command: "offscreenDecryptItems", decryptRequest }, - mock(), - (res: string) => { - response = res; - }, - ); - await flushPromises(); - - expect(response).toBe(JSON.stringify(items)); - }); - }); }); }); diff --git a/apps/browser/src/platform/offscreen-document/offscreen-document.ts b/apps/browser/src/platform/offscreen-document/offscreen-document.ts index 509193d5ee0..4994a6e9ba8 100644 --- a/apps/browser/src/platform/offscreen-document/offscreen-document.ts +++ b/apps/browser/src/platform/offscreen-document/offscreen-document.ts @@ -1,35 +1,21 @@ import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; -import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; -import { WebCryptoFunctionService } from "@bitwarden/common/platform/services/web-crypto-function.service"; import { BrowserApi } from "../browser/browser-api"; import BrowserClipboardService from "../services/browser-clipboard.service"; import { - OffscreenDocument as OffscreenDocumentInterface, OffscreenDocumentExtensionMessage, OffscreenDocumentExtensionMessageHandlers, + OffscreenDocument as OffscreenDocumentInterface, } from "./abstractions/offscreen-document"; class OffscreenDocument implements OffscreenDocumentInterface { - private readonly consoleLogService: ConsoleLogService; - private encryptService: MultithreadEncryptServiceImplementation; + private consoleLogService: ConsoleLogService = new ConsoleLogService(false); private readonly extensionMessageHandlers: OffscreenDocumentExtensionMessageHandlers = { offscreenCopyToClipboard: ({ message }) => this.handleOffscreenCopyToClipboard(message), offscreenReadFromClipboard: () => this.handleOffscreenReadFromClipboard(), - offscreenDecryptItems: ({ message }) => this.handleOffscreenDecryptItems(message), }; - constructor() { - const cryptoFunctionService = new WebCryptoFunctionService(self); - this.consoleLogService = new ConsoleLogService(false); - this.encryptService = new MultithreadEncryptServiceImplementation( - cryptoFunctionService, - this.consoleLogService, - true, - ); - } - /** * Initializes the offscreen document extension. */ @@ -53,23 +39,6 @@ class OffscreenDocument implements OffscreenDocumentInterface { return await BrowserClipboardService.read(self); } - /** - * Decrypts the items in the message using the encrypt service. - * - * @param message - The extension message containing the items to decrypt - */ - private async handleOffscreenDecryptItems( - message: OffscreenDocumentExtensionMessage, - ): Promise { - const { decryptRequest } = message; - if (!decryptRequest) { - return "[]"; - } - - const request = JSON.parse(decryptRequest); - return await this.encryptService.getDecryptedItemsFromWorker(request.items, request.key); - } - /** * Sets up the listener for extension messages. */ diff --git a/apps/browser/src/platform/popup/components/pop-out.component.html b/apps/browser/src/platform/popup/components/pop-out.component.html index 73bf76941dc..c3f1f8ca150 100644 --- a/apps/browser/src/platform/popup/components/pop-out.component.html +++ b/apps/browser/src/platform/popup/components/pop-out.component.html @@ -1,5 +1,15 @@ - + + + + diff --git a/apps/browser/src/platform/popup/components/pop-out.component.ts b/apps/browser/src/platform/popup/components/pop-out.component.ts index 154bb55a0c9..54bed7aa348 100644 --- a/apps/browser/src/platform/popup/components/pop-out.component.ts +++ b/apps/browser/src/platform/popup/components/pop-out.component.ts @@ -2,7 +2,10 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { IconButtonModule } from "@bitwarden/components"; import BrowserPopupUtils from "../browser-popup-utils"; @@ -10,14 +13,20 @@ import BrowserPopupUtils from "../browser-popup-utils"; selector: "app-pop-out", templateUrl: "pop-out.component.html", standalone: true, - imports: [CommonModule, JslibModule], + imports: [CommonModule, JslibModule, IconButtonModule], }) export class PopOutComponent implements OnInit { @Input() show = true; + useRefreshVariant = false; - constructor(private platformUtilsService: PlatformUtilsService) {} + constructor( + private platformUtilsService: PlatformUtilsService, + private configService: ConfigService, + ) {} + + async ngOnInit() { + this.useRefreshVariant = await this.configService.getFeatureFlag(FeatureFlag.ExtensionRefresh); - ngOnInit() { if (this.show) { if ( (BrowserPopupUtils.inSidebar(window) && this.platformUtilsService.isFirefox()) || diff --git a/apps/browser/src/platform/popup/layout/popup-header.component.html b/apps/browser/src/platform/popup/layout/popup-header.component.html index c0894f8168b..55caf1b91e7 100644 --- a/apps/browser/src/platform/popup/layout/popup-header.component.html +++ b/apps/browser/src/platform/popup/layout/popup-header.component.html @@ -9,6 +9,7 @@ *ngIf="showBackButton" [title]="'back' | i18n" [ariaLabel]="'back' | i18n" + (click)="back()" >

{{ pageTitle }}

diff --git a/apps/browser/src/platform/popup/layout/popup-layout.mdx b/apps/browser/src/platform/popup/layout/popup-layout.mdx index 91f7dab277e..6f72f325bf1 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.mdx +++ b/apps/browser/src/platform/popup/layout/popup-layout.mdx @@ -136,3 +136,9 @@ When the browser extension is popped out, the "popout" button should not be pass + +## Centered Content + + + + diff --git a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts index 28692c79e1c..cc7758d9680 100644 --- a/apps/browser/src/platform/popup/layout/popup-layout.stories.ts +++ b/apps/browser/src/platform/popup/layout/popup-layout.stories.ts @@ -11,6 +11,7 @@ import { I18nMockService, IconButtonModule, ItemModule, + NoItemsModule, } from "@bitwarden/components"; import { PopupFooterComponent } from "./popup-footer.component"; @@ -289,6 +290,9 @@ export default { moduleMetadata({ imports: [ PopupTabNavigationComponent, + PopupHeaderComponent, + PopupPageComponent, + PopupFooterComponent, CommonModule, RouterModule, ExtensionContainerComponent, @@ -298,6 +302,7 @@ export default { MockGeneratorPageComponent, MockSettingsPageComponent, MockVaultPagePoppedComponent, + NoItemsModule, ], providers: [ { @@ -378,3 +383,24 @@ export const PoppedOut: Story = { `, }), }; + +export const CenteredContent: Story = { + render: (args) => ({ + props: args, + template: /* HTML */ ` + + + + +
+ + Before centering a div + One must first center oneself + +
+
+
+
+ `, + }), +}; diff --git a/apps/browser/src/platform/popup/layout/popup-page.component.html b/apps/browser/src/platform/popup/layout/popup-page.component.html index ba871d6319e..ece6be4c63e 100644 --- a/apps/browser/src/platform/popup/layout/popup-page.component.html +++ b/apps/browser/src/platform/popup/layout/popup-page.component.html @@ -1,6 +1,6 @@ -
-
+
+
diff --git a/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.spec.ts b/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.spec.ts deleted file mode 100644 index db5b3df7a36..00000000000 --- a/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.spec.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { mock, MockProxy } from "jest-mock-extended"; - -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { EncryptionType } from "@bitwarden/common/platform/enums"; -import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; -import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { InitializerKey } from "@bitwarden/common/platform/services/cryptography/initializer-key"; -import { makeStaticByteArray } from "@bitwarden/common/spec"; - -import { BrowserApi } from "../browser/browser-api"; -import { OffscreenDocumentService } from "../offscreen-document/abstractions/offscreen-document"; - -import { BrowserMultithreadEncryptServiceImplementation } from "./browser-multithread-encrypt.service.implementation"; - -describe("BrowserMultithreadEncryptServiceImplementation", () => { - let cryptoFunctionServiceMock: MockProxy; - let logServiceMock: MockProxy; - let offscreenDocumentServiceMock: MockProxy; - let encryptService: BrowserMultithreadEncryptServiceImplementation; - const manifestVersionSpy = jest.spyOn(BrowserApi, "manifestVersion", "get"); - const sendMessageWithResponseSpy = jest.spyOn(BrowserApi, "sendMessageWithResponse"); - const encType = EncryptionType.AesCbc256_HmacSha256_B64; - const key = new SymmetricCryptoKey(makeStaticByteArray(64, 100), encType); - const items: Decryptable[] = [ - { - decrypt: jest.fn(), - initializerKey: InitializerKey.Cipher, - }, - ]; - - beforeEach(() => { - cryptoFunctionServiceMock = mock(); - logServiceMock = mock(); - offscreenDocumentServiceMock = mock({ - withDocument: jest.fn((_, __, callback) => callback() as any), - }); - encryptService = new BrowserMultithreadEncryptServiceImplementation( - cryptoFunctionServiceMock, - logServiceMock, - false, - offscreenDocumentServiceMock, - ); - manifestVersionSpy.mockReturnValue(3); - sendMessageWithResponseSpy.mockResolvedValue(JSON.stringify([])); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it("decrypts items using web workers if the chrome.offscreen API is not supported", async () => { - manifestVersionSpy.mockReturnValue(2); - - await encryptService.decryptItems([], key); - - expect(offscreenDocumentServiceMock.withDocument).not.toHaveBeenCalled(); - }); - - it("decrypts items using the chrome.offscreen API if it is supported", async () => { - sendMessageWithResponseSpy.mockResolvedValue(JSON.stringify(items)); - - await encryptService.decryptItems(items, key); - - expect(offscreenDocumentServiceMock.withDocument).toHaveBeenCalledWith( - [chrome.offscreen.Reason.WORKERS], - "Use web worker to decrypt items.", - expect.any(Function), - ); - expect(BrowserApi.sendMessageWithResponse).toHaveBeenCalledWith("offscreenDecryptItems", { - decryptRequest: expect.any(String), - }); - }); - - it("returns an empty array if the passed items are not defined", async () => { - const result = await encryptService.decryptItems(null, key); - - expect(result).toEqual([]); - }); - - it("returns an empty array if the offscreen document message returns an empty value", async () => { - sendMessageWithResponseSpy.mockResolvedValue(""); - - const result = await encryptService.decryptItems(items, key); - - expect(result).toEqual([]); - }); - - it("returns an empty array if the offscreen document message returns an empty array", async () => { - sendMessageWithResponseSpy.mockResolvedValue("[]"); - - const result = await encryptService.decryptItems(items, key); - - expect(result).toEqual([]); - }); -}); diff --git a/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.ts b/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.ts deleted file mode 100644 index ace5015c8eb..00000000000 --- a/apps/browser/src/platform/services/browser-multithread-encrypt.service.implementation.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { Decryptable } from "@bitwarden/common/platform/interfaces/decryptable.interface"; -import { InitializerMetadata } from "@bitwarden/common/platform/interfaces/initializer-metadata.interface"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { MultithreadEncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/multithread-encrypt.service.implementation"; - -import { BrowserApi } from "../browser/browser-api"; -import { OffscreenDocumentService } from "../offscreen-document/abstractions/offscreen-document"; - -export class BrowserMultithreadEncryptServiceImplementation extends MultithreadEncryptServiceImplementation { - constructor( - cryptoFunctionService: CryptoFunctionService, - logService: LogService, - logMacFailures: boolean, - private offscreenDocumentService: OffscreenDocumentService, - ) { - super(cryptoFunctionService, logService, logMacFailures); - } - - /** - * Handles decryption of items, will use the offscreen document if supported. - * - * @param items - The items to decrypt. - * @param key - The key to use for decryption. - */ - async decryptItems( - items: Decryptable[], - key: SymmetricCryptoKey, - ): Promise { - if (!this.isOffscreenDocumentSupported()) { - return await super.decryptItems(items, key); - } - - return await this.decryptItemsInOffscreenDocument(items, key); - } - - /** - * Decrypts items using the offscreen document api. - * - * @param items - The items to decrypt. - * @param key - The key to use for decryption. - */ - private async decryptItemsInOffscreenDocument( - items: Decryptable[], - key: SymmetricCryptoKey, - ): Promise { - if (items == null || items.length < 1) { - return []; - } - - const request = { - id: Utils.newGuid(), - items: items, - key: key, - }; - - const response = await this.offscreenDocumentService.withDocument( - [chrome.offscreen.Reason.WORKERS], - "Use web worker to decrypt items.", - async () => { - return (await BrowserApi.sendMessageWithResponse("offscreenDecryptItems", { - decryptRequest: JSON.stringify(request), - })) as string; - }, - ); - - if (!response) { - return []; - } - - const responseItems = JSON.parse(response); - if (responseItems?.length < 1) { - return []; - } - - return this.initializeItems(responseItems); - } - - /** - * Checks if the offscreen document api is supported. - */ - private isOffscreenDocumentSupported() { - return ( - BrowserApi.isManifestVersion(3) && - typeof chrome !== "undefined" && - typeof chrome.offscreen !== "undefined" - ); - } -} diff --git a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts index 02c10b62cc4..c86c9158019 100644 --- a/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts +++ b/apps/browser/src/platform/services/platform-utils/browser-platform-utils.service.spec.ts @@ -229,9 +229,7 @@ describe("Browser Utils Service", () => { it("copies the passed text using the offscreen document if the extension is using manifest v3", async () => { const text = "test"; - jest - .spyOn(browserPlatformUtilsService, "getDevice") - .mockReturnValue(DeviceType.ChromeExtension); + offscreenDocumentService.offscreenApiSupported.mockReturnValue(true); getManifestVersionSpy.mockReturnValue(3); browserPlatformUtilsService.copyToClipboard(text); @@ -304,9 +302,7 @@ describe("Browser Utils Service", () => { }); it("reads the clipboard text using the offscreen document", async () => { - jest - .spyOn(browserPlatformUtilsService, "getDevice") - .mockReturnValue(DeviceType.ChromeExtension); + offscreenDocumentService.offscreenApiSupported.mockReturnValue(true); getManifestVersionSpy.mockReturnValue(3); offscreenDocumentService.withDocument.mockImplementationOnce((_, __, callback) => Promise.resolve("test"), 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 4163ca93107..26108e60b7e 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 @@ -243,7 +243,7 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic text = "\u0000"; } - if (this.isChrome() && BrowserApi.isManifestVersion(3)) { + if (BrowserApi.isManifestVersion(3) && this.offscreenDocumentService.offscreenApiSupported()) { void this.triggerOffscreenCopyToClipboard(text).then(handleClipboardWriteCallback); return; @@ -268,7 +268,7 @@ export abstract class BrowserPlatformUtilsService implements PlatformUtilsServic return await SafariApp.sendMessageToApp("readFromClipboard"); } - if (this.isChrome() && BrowserApi.isManifestVersion(3)) { + if (BrowserApi.isManifestVersion(3) && this.offscreenDocumentService.offscreenApiSupported()) { return await this.triggerOffscreenReadFromClipboard(); } diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts index 74e24433b2c..2f69d8253f9 100644 --- a/apps/browser/src/popup/app.module.ts +++ b/apps/browser/src/popup/app.module.ts @@ -126,6 +126,7 @@ import "../platform/popup/locales"; PopupHeaderComponent, UserVerificationDialogComponent, PopupSectionHeaderComponent, + CurrentAccountComponent, ], declarations: [ ActionButtonsComponent, @@ -188,7 +189,6 @@ import "../platform/popup/locales"; HelpAndFeedbackComponent, AutofillComponent, EnvironmentSelectorComponent, - CurrentAccountComponent, AccountSwitcherComponent, VaultV2Component, ], diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts index 32d4adae4a1..a4f5c8a4c67 100644 --- a/apps/browser/src/popup/services/services.module.ts +++ b/apps/browser/src/popup/services/services.module.ts @@ -81,8 +81,6 @@ import { } from "@bitwarden/common/platform/state"; // eslint-disable-next-line import/no-restricted-paths -- Used for dependency injection import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state"; -import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; -import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @@ -317,11 +315,6 @@ const safeProviders: SafeProvider[] = [ }, deps: [ToastService, OffscreenDocumentService], }), - safeProvider({ - provide: PasswordGenerationServiceAbstraction, - useFactory: getBgService("passwordGenerationService"), - deps: [], - }), safeProvider({ provide: SyncService, useFactory: getBgService("syncService"), @@ -482,11 +475,6 @@ const safeProviders: SafeProvider[] = [ MigrationRunner, ], }), - safeProvider({ - provide: UsernameGenerationServiceAbstraction, - useFactory: getBgService("usernameGenerationService"), - deps: [], - }), safeProvider({ provide: BaseStateServiceAbstraction, useExisting: StateServiceAbstraction, diff --git a/apps/browser/src/tools/background/service_factories/import-api-service.factory.ts b/apps/browser/src/tools/background/service_factories/import-api-service.factory.ts deleted file mode 100644 index 37d0b9000c2..00000000000 --- a/apps/browser/src/tools/background/service_factories/import-api-service.factory.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ImportApiService, ImportApiServiceAbstraction } from "@bitwarden/importer/core"; - -import { - ApiServiceInitOptions, - apiServiceFactory, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; - -export type ImportApiServiceInitOptions = FactoryOptions & ApiServiceInitOptions; -type ServiceCache = { importApiService?: ImportApiServiceAbstraction } & CachedServices; - -export function importApiServiceFactory( - cache: ServiceCache, - opts: ImportApiServiceInitOptions, -): Promise { - return factory( - cache, - "importApiService", - opts, - async () => new ImportApiService(await apiServiceFactory(cache, opts)), - ); -} diff --git a/apps/browser/src/tools/background/service_factories/import-service.factory.ts b/apps/browser/src/tools/background/service_factories/import-service.factory.ts deleted file mode 100644 index 5b73b475061..00000000000 --- a/apps/browser/src/tools/background/service_factories/import-service.factory.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ImportService, ImportServiceAbstraction } from "@bitwarden/importer/core"; - -import { - pinServiceFactory, - PinServiceInitOptions, -} from "../../../auth/background/service-factories/pin-service.factory"; -import { - cryptoServiceFactory, - CryptoServiceInitOptions, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - cipherServiceFactory, - CipherServiceInitOptions, -} from "../../../vault/background/service_factories/cipher-service.factory"; -import { - collectionServiceFactory, - CollectionServiceInitOptions, -} from "../../../vault/background/service_factories/collection-service.factory"; -import { - folderServiceFactory, - FolderServiceInitOptions, -} from "../../../vault/background/service_factories/folder-service.factory"; - -import { importApiServiceFactory, ImportApiServiceInitOptions } from "./import-api-service.factory"; - -type ImportServiceFactoryOptions = FactoryOptions; - -export type ImportServiceInitOptions = ImportServiceFactoryOptions & - CipherServiceInitOptions & - FolderServiceInitOptions & - ImportApiServiceInitOptions & - I18nServiceInitOptions & - CollectionServiceInitOptions & - CryptoServiceInitOptions & - PinServiceInitOptions; - -export function importServiceFactory( - cache: { - importService?: ImportServiceAbstraction; - } & CachedServices, - opts: ImportServiceInitOptions, -): Promise { - return factory( - cache, - "importService", - opts, - async () => - new ImportService( - await cipherServiceFactory(cache, opts), - await folderServiceFactory(cache, opts), - await importApiServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await collectionServiceFactory(cache, opts), - await cryptoServiceFactory(cache, opts), - await pinServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts deleted file mode 100644 index 4b4d80e76d4..00000000000 --- a/apps/browser/src/tools/background/service_factories/password-generation-service.factory.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - PasswordGenerationService, - PasswordGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/password"; - -import { - policyServiceFactory, - PolicyServiceInitOptions, -} from "../../../admin-console/background/service-factories/policy-service.factory"; -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../../platform/background/service-factories/state-service.factory"; - -type PasswordGenerationServiceFactoryOptions = FactoryOptions; - -export type PasswordGenerationServiceInitOptions = PasswordGenerationServiceFactoryOptions & - CryptoServiceInitOptions & - PolicyServiceInitOptions & - StateServiceInitOptions; - -export function passwordGenerationServiceFactory( - cache: { passwordGenerationService?: PasswordGenerationServiceAbstraction } & CachedServices, - opts: PasswordGenerationServiceInitOptions, -): Promise { - return factory( - cache, - "passwordGenerationService", - opts, - async () => - new PasswordGenerationService( - await cryptoServiceFactory(cache, opts), - await policyServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts b/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts deleted file mode 100644 index c1e5b71ee32..00000000000 --- a/apps/browser/src/tools/background/service_factories/password-strength-service.factory.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { - PasswordStrengthService, - PasswordStrengthServiceAbstraction, -} from "@bitwarden/common/tools/password-strength"; - -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; - -type PasswordStrengthServiceFactoryOptions = FactoryOptions; - -export type PasswordStrengthServiceInitOptions = PasswordStrengthServiceFactoryOptions; - -export function passwordStrengthServiceFactory( - cache: { - passwordStrengthService?: PasswordStrengthServiceAbstraction; - } & CachedServices, - opts: PasswordStrengthServiceInitOptions, -): Promise { - return factory(cache, "passwordStrengthService", opts, async () => new PasswordStrengthService()); -} diff --git a/apps/browser/src/tools/popup/generator/generator.component.ts b/apps/browser/src/tools/popup/generator/generator.component.ts index 0c11c28f278..1afe696576f 100644 --- a/apps/browser/src/tools/popup/generator/generator.component.ts +++ b/apps/browser/src/tools/popup/generator/generator.component.ts @@ -1,13 +1,13 @@ import { Location } from "@angular/common"; -import { Component } from "@angular/core"; +import { Component, NgZone } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { firstValueFrom } from "rxjs"; import { GeneratorComponent as BaseGeneratorComponent } from "@bitwarden/angular/tools/generator/components/generator.component"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -28,20 +28,22 @@ export class GeneratorComponent extends BaseGeneratorComponent { usernameGenerationService: UsernameGenerationServiceAbstraction, platformUtilsService: PlatformUtilsService, i18nService: I18nService, - stateService: StateService, + accountService: AccountService, cipherService: CipherService, route: ActivatedRoute, logService: LogService, + ngZone: NgZone, private location: Location, ) { super( passwordGenerationService, usernameGenerationService, platformUtilsService, - stateService, + accountService, i18nService, logService, route, + ngZone, window, ); this.cipherService = cipherService; diff --git a/apps/browser/src/tools/popup/settings/export.component.html b/apps/browser/src/tools/popup/settings/export.component.html index 1b2ea1eb1d5..ef031b7979a 100644 --- a/apps/browser/src/tools/popup/settings/export.component.html +++ b/apps/browser/src/tools/popup/settings/export.component.html @@ -29,11 +29,6 @@
- - - -
diff --git a/apps/browser/src/tools/popup/settings/export.component.ts b/apps/browser/src/tools/popup/settings/export.component.ts index b62ed4c517f..9f3f054d2ac 100644 --- a/apps/browser/src/tools/popup/settings/export.component.ts +++ b/apps/browser/src/tools/popup/settings/export.component.ts @@ -5,7 +5,6 @@ import { Router } from "@angular/router"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -27,7 +26,6 @@ export class ExportComponent extends BaseExportComponent { policyService: PolicyService, private router: Router, logService: LogService, - userVerificationService: UserVerificationService, formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, @@ -40,7 +38,6 @@ export class ExportComponent extends BaseExportComponent { eventCollectionService, policyService, logService, - userVerificationService, formBuilder, fileDownloadService, dialogService, diff --git a/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts b/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts deleted file mode 100644 index 57366ea8c05..00000000000 --- a/apps/browser/src/vault/background/service_factories/cipher-service.factory.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { CipherService as AbstractCipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { CipherService } from "@bitwarden/common/vault/services/cipher.service"; - -import { - AutofillSettingsServiceInitOptions, - autofillSettingsServiceFactory, -} from "../../../autofill/background/service_factories/autofill-settings-service.factory"; -import { - DomainSettingsServiceInitOptions, - domainSettingsServiceFactory, -} from "../../../autofill/background/service_factories/domain-settings-service.factory"; -import { - CipherFileUploadServiceInitOptions, - cipherFileUploadServiceFactory, -} from "../../../background/service-factories/cipher-file-upload-service.factory"; -import { - searchServiceFactory, - SearchServiceInitOptions, -} from "../../../background/service-factories/search-service.factory"; -import { - apiServiceFactory, - ApiServiceInitOptions, -} from "../../../platform/background/service-factories/api-service.factory"; -import { - configServiceFactory, - ConfigServiceInitOptions, -} from "../../../platform/background/service-factories/config-service.factory"; -import { - cryptoServiceFactory, - CryptoServiceInitOptions, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - EncryptServiceInitOptions, - encryptServiceFactory, -} from "../../../platform/background/service-factories/encrypt-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory"; -import { - stateServiceFactory, - StateServiceInitOptions, -} from "../../../platform/background/service-factories/state-service.factory"; - -type CipherServiceFactoryOptions = FactoryOptions; - -export type CipherServiceInitOptions = CipherServiceFactoryOptions & - CryptoServiceInitOptions & - ApiServiceInitOptions & - CipherFileUploadServiceInitOptions & - I18nServiceInitOptions & - SearchServiceInitOptions & - StateServiceInitOptions & - AutofillSettingsServiceInitOptions & - DomainSettingsServiceInitOptions & - EncryptServiceInitOptions & - ConfigServiceInitOptions; - -export function cipherServiceFactory( - cache: { cipherService?: AbstractCipherService } & CachedServices, - opts: CipherServiceInitOptions, -): Promise { - return factory( - cache, - "cipherService", - opts, - async () => - new CipherService( - await cryptoServiceFactory(cache, opts), - await domainSettingsServiceFactory(cache, opts), - await apiServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await searchServiceFactory(cache, opts), - await stateServiceFactory(cache, opts), - await autofillSettingsServiceFactory(cache, opts), - await encryptServiceFactory(cache, opts), - await cipherFileUploadServiceFactory(cache, opts), - await configServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/vault/background/service_factories/collection-service.factory.ts b/apps/browser/src/vault/background/service_factories/collection-service.factory.ts deleted file mode 100644 index 69d5cd6f22f..00000000000 --- a/apps/browser/src/vault/background/service_factories/collection-service.factory.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { CollectionService as AbstractCollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; -import { CollectionService } from "@bitwarden/common/vault/services/collection.service"; - -import { - cryptoServiceFactory, - CryptoServiceInitOptions, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { stateProviderFactory } from "../../../platform/background/service-factories/state-provider.factory"; -import { StateServiceInitOptions } from "../../../platform/background/service-factories/state-service.factory"; - -type CollectionServiceFactoryOptions = FactoryOptions; - -export type CollectionServiceInitOptions = CollectionServiceFactoryOptions & - CryptoServiceInitOptions & - I18nServiceInitOptions & - StateServiceInitOptions; - -export function collectionServiceFactory( - cache: { collectionService?: AbstractCollectionService } & CachedServices, - opts: CollectionServiceInitOptions, -): Promise { - return factory( - cache, - "collectionService", - opts, - async () => - new CollectionService( - await cryptoServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/vault/background/service_factories/folder-service.factory.ts b/apps/browser/src/vault/background/service_factories/folder-service.factory.ts deleted file mode 100644 index 0593dc904c3..00000000000 --- a/apps/browser/src/vault/background/service_factories/folder-service.factory.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { FolderService as AbstractFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; -import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service"; - -import { - CryptoServiceInitOptions, - cryptoServiceFactory, -} from "../../../platform/background/service-factories/crypto-service.factory"; -import { - CachedServices, - factory, - FactoryOptions, -} from "../../../platform/background/service-factories/factory-options"; -import { - i18nServiceFactory, - I18nServiceInitOptions, -} from "../../../platform/background/service-factories/i18n-service.factory"; -import { - stateProviderFactory, - StateProviderInitOptions, -} from "../../../platform/background/service-factories/state-provider.factory"; - -import { cipherServiceFactory, CipherServiceInitOptions } from "./cipher-service.factory"; - -type FolderServiceFactoryOptions = FactoryOptions; - -export type FolderServiceInitOptions = FolderServiceFactoryOptions & - CryptoServiceInitOptions & - CipherServiceInitOptions & - I18nServiceInitOptions & - StateProviderInitOptions; - -export function folderServiceFactory( - cache: { folderService?: AbstractFolderService } & CachedServices, - opts: FolderServiceInitOptions, -): Promise { - return factory( - cache, - "folderService", - opts, - async () => - new FolderService( - await cryptoServiceFactory(cache, opts), - await i18nServiceFactory(cache, opts), - await cipherServiceFactory(cache, opts), - await stateProviderFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/vault/background/service_factories/sync-notifier-service.factory.ts b/apps/browser/src/vault/background/service_factories/sync-notifier-service.factory.ts deleted file mode 100644 index 715d0f2c860..00000000000 --- a/apps/browser/src/vault/background/service_factories/sync-notifier-service.factory.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { SyncNotifierService as AbstractSyncNotifierService } from "@bitwarden/common/vault/abstractions/sync/sync-notifier.service.abstraction"; -import { SyncNotifierService } from "@bitwarden/common/vault/services/sync/sync-notifier.service"; - -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; - -type SyncNotifierServiceFactoryOptions = FactoryOptions; - -export type SyncNotifierServiceInitOptions = SyncNotifierServiceFactoryOptions; - -export function syncNotifierServiceFactory( - cache: { syncNotifierService?: AbstractSyncNotifierService } & CachedServices, - opts: SyncNotifierServiceInitOptions, -): Promise { - return factory(cache, "syncNotifierService", opts, () => - Promise.resolve(new SyncNotifierService()), - ); -} diff --git a/apps/browser/src/vault/background/service_factories/totp-service.factory.ts b/apps/browser/src/vault/background/service_factories/totp-service.factory.ts deleted file mode 100644 index c8f5a270b48..00000000000 --- a/apps/browser/src/vault/background/service_factories/totp-service.factory.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { TotpService as AbstractTotpService } from "@bitwarden/common/vault/abstractions/totp.service"; -import { TotpService } from "@bitwarden/common/vault/services/totp.service"; - -import { - CryptoFunctionServiceInitOptions, - cryptoFunctionServiceFactory, -} from "../../../platform/background/service-factories/crypto-function-service.factory"; -import { - FactoryOptions, - CachedServices, - factory, -} from "../../../platform/background/service-factories/factory-options"; -import { - LogServiceInitOptions, - logServiceFactory, -} from "../../../platform/background/service-factories/log-service.factory"; - -type TotpServiceOptions = FactoryOptions; - -export type TotpServiceInitOptions = TotpServiceOptions & - CryptoFunctionServiceInitOptions & - LogServiceInitOptions; - -export function totpServiceFactory( - cache: { totpService?: AbstractTotpService } & CachedServices, - opts: TotpServiceInitOptions, -): Promise { - return factory( - cache, - "totpService", - opts, - async () => - new TotpService( - await cryptoFunctionServiceFactory(cache, opts), - await logServiceFactory(cache, opts), - ), - ); -} diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts index 05255a3c011..62f2737be2f 100644 --- a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts +++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts @@ -10,13 +10,13 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @@ -53,7 +53,7 @@ export class AddEditComponent extends BaseAddEditComponent { i18nService: I18nService, platformUtilsService: PlatformUtilsService, auditService: AuditService, - stateService: StateService, + accountService: AccountService, private autofillSettingsService: AutofillSettingsServiceAbstraction, collectionService: CollectionService, messagingService: MessagingService, @@ -78,7 +78,7 @@ export class AddEditComponent extends BaseAddEditComponent { i18nService, platformUtilsService, auditService, - stateService, + accountService, collectionService, messagingService, eventCollectionService, diff --git a/apps/browser/src/vault/popup/components/vault/vault-v2.component.html b/apps/browser/src/vault/popup/components/vault/vault-v2.component.html index a653f463320..c36d2d2db99 100644 --- a/apps/browser/src/vault/popup/components/vault/vault-v2.component.html +++ b/apps/browser/src/vault/popup/components/vault/vault-v2.component.html @@ -1 +1,13 @@ -

Vault V2 Extension Refresh

+ + + + + + + {{ "new" | i18n }} + + + + + + diff --git a/apps/browser/store/locales/es/copy.resx b/apps/browser/store/locales/es/copy.resx index 019006422a9..a17440a0d6b 100644 --- a/apps/browser/store/locales/es/copy.resx +++ b/apps/browser/store/locales/es/copy.resx @@ -124,48 +124,47 @@ En casa, en el trabajo o en el viaje, Bitwarden asegura fácilmente todas sus contraseñas, claves de acceso e información confidencial. - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + ¡Reconocido como el mejor administrador de contraseñas por PCMag, WIRED, The Verge, CNET, G2 y más! -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. +ASEGURA TU VIDA DIGITAL +Asegura tu vida digital y protéjete contra las filtraciones de datos generando y guardando contraseñas únicas y seguras para cada cuenta. Mantén todo en una caja fuerte de contraseñas cifrada de extremo a extremo a la que solo tú puedes acceder. -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +ACCEDE A TUS DATOS, EN CUALQUIER LUGAR, EN CUALQUIER MOMENTO Y EN CUALQUIER DISPOSITIVO +Administra, almacena, proteje y comparte fácilmente contraseñas ilimitadas en dispositivos ilimitados sin restricciones. -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. +TODO EL MUNDO DEBERÍA TENER LAS HERRAMIENTAS PARA MANTENERSE SEGURO EN LÍNEA +Utiliza Bitwarden de forma gratuita sin anuncios ni vendiendo tus datos. Bitwarden cree que todo el mundo debería tener la capacidad de mantenerse seguro en línea. Los planes premium ofrecen acceso a funciones avanzadas. -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. +EMPODERA A TUS EQUIPOS CON BITWARDEN +Los planes para Equipos y Empresa vienen con características empresariales profesionales. Algunos ejemplos incluyen integración de SSO, autoalojamiento, integración de directorios y aprovisionamiento de SCIM, políticas globales, acceso a la API, registros de eventos y más. -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +Utiliza Bitwarden para proteger a tu personal y compartir información confidencial con tus colegas. +Más razones para elegir Bitwarden: -More reasons to choose Bitwarden: +Encriptación de clase mundial +Las contraseñas están protegidas con cifrado avanzado de extremo a extremo (AES-256 bits, hashtag salado y PBKDF2 SHA-256) para que tus datos permanezcan seguros y privados. -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. +Auditorías de terceros +Bitwarden realiza regularmente auditorías integrales de seguridad de terceros con empresas de seguridad notables. Estas auditorías anuales incluyen evaluaciones de código fuente y pruebas de penetración en las direcciones IP, los servidores y las aplicaciones web de Bitwarden. -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. +2FA avanzado +Proteje tu inicio de sesión con un autenticador de terceros, códigos enviados por correo electrónico o credenciales FIDO2 WebAuthn, como una clave de seguridad de hardware o una clave de acceso. Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +Transmite datos directamente a otros mientras mantienes la seguridad cifrada de extremo a extremo y limitas la exposición. -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. +Generador incorporado +Crea contraseñas largas, complejas y distintas y nombres de usuario únicos para cada sitio que visites. Integra proveedores de alias de correo electrónico para mayor privacidad. -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +Traducciones Globales +Existen traducciones de Bitwarden para más de 60 idiomas, traducidas por la comunidad global a través de Crowdin. -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +Aplicaciones multiplataforma +Proteje y comparte datos confidenciales dentro de tu Caja fuerte de Bitwarden desde cualquier navegador, dispositivo móvil o sistema operativo de escritorio, y más. -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 protege más que solo contraseñas +Las soluciones de gestión de credenciales cifradas de extremo a extremo de Bitwarden permiten a las organizaciones proteger todo, incluidos los secretos de los desarrolladores y las experiencias de clave de acceso. ¡Visita Bitwarden.com para obtener más información sobre Bitwarden Secrets Manager y Bitwarden Passwordless.dev! diff --git a/apps/browser/store/locales/fi/copy.resx b/apps/browser/store/locales/fi/copy.resx index a50cedbdacd..076a724bdf8 100644 --- a/apps/browser/store/locales/fi/copy.resx +++ b/apps/browser/store/locales/fi/copy.resx @@ -124,48 +124,48 @@ Kotona, töissä tai reissussa, Bitwarden suojaa helposti salasanasi, suojausavaimesi ja arkaluonteiset tietosi. - Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more! + Muun muassa PCMag, WIRED, The Verge, CNET sekä G2 ovat nimenneet Bitwardenin parhaaksi salasanahallinnaksi! -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. +SUOJAA DIGITAALINEN ELÄMÄSI +Varjele digielämääsi varautumalla tietovuotoihin luomalla kaikille tileillesi yksilölliset, vahvat salasanat ja säilyttämällä ne turvallisesti. Hallitse kaikkea päästä päähän salatussa salasanaholvissa, johon vain sinulla on käyttöoikeus. -ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE -Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions. +TAVOITA TIETOSI MISTÄ, MILLOIN JA MILLÄ LAITTEELLA TAHANSA +Hallitse, säilytä, suojaa ja jaa salasanoja niin paljon kuin haluat, niin monella laitteella kuin haluat. -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. +KAIKILLA TULISI OLLA TYÖKALUT VERKOSSA SUOJAUTUMISEEN +Hyödynnä Bitwardenia ilmaiseksi ilman mainoksia tai käyttäjätietojen myyntiä. Bitwardenin mielestä kaikkien tulee voida suojautua verkossa. Premium-tilaukset tarjoavat lisäominaisuuksia. -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. +TEHOSTA TIIMIESI TYÖSKENTELYÄ BITWARDENILLA +Teams- ja Enterprise-tilaukset tarjoavat esimerkiksi SSO- ja hakemistointegraatioiden, SCIM-hallinnan, oman palvelinympäristön, laajan käytäntöhallinnan, rajapinnan sekä käyttölokien kaltaisia ammattitason yritysominaisuuksia. -Use Bitwarden to secure your workforce and share sensitive information with colleagues. +Suojaa henkilökuntasi Bitwardenilla ja jaa arkaluonteisia tietoja kollegoidesi kanssa. -More reasons to choose Bitwarden: +Lisää syitä valita 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. +Maailmanluoka salaus: +Salasanat on suojattu edistyneellä päästä päähän salauksella (AES-256 bit, suolattu hajautus sekä PBKDF2 SHA-256), joten tietosi pysyvät turvassa ja yksityisinä. -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. +Riippumattomat auditoinnit +Bitwarden teetättää säännöllisesti tunnettujen tietoturvayritysten suorittamia kattavia riippumattomia tietoturva-arviointeja. Näissä vuotuisissa auditoinneissa arvioidaan lähdekoodia ja suoritetaan murtotestausta Bitwardenin IP-osoittelle, palvelimille ja verkkosovelluksille. -Advanced 2FA -Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey. +Edistynyt kaksivaiheinen tunnistautuminen +Suojaa kirjautumistietosi riippumattomalla todennussovelluksella, sähköpostikoodeilla tai FIDO2 WEBAuthn -standardin mukaisilla fyysisillä tai ohjelmallisilla suojausavaimilla. Bitwarden Send -Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure. +Välitä tietoja muille suoraan, päästä päähän salausta menettämättä ja rajoitaen niiden näkyvyyttä. -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. +Sisäänrakennettu generaattori +Luo pitkät, monimutkaiset ja yksilölliset salasanat sekä ainutlaatuiset käyttäjätunnukset kaikille käyttämillesi verkkosivustoille. Sähköpostialiaksia toimittavien palveluiden liitäntämahdollisuus tehostaa yksityisyyttä. -Global Translations -Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin. +Maailmanlaajuinen kielituki +Bitwarden on maailmanlaajuisen Crowdin-yhteisön toimesta yli 60 kielelle. -Cross-Platform Applications -Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. +Sovellukset eri alustoille +Suojaa ja jaa Bitwarden-holvisi arkaluonteisia tietoja mm. mistä tahansa selaimesta, mobiililaitteesta tai pöytätietokoneesta. -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 suojaa muutakin kuin salasanoja +Bitwardenin päästä päähän salatut käyttäjätietojen hallintaratkaisut tarjoavat organisaatiolle mahdollisuuden suojata paljon muutakin, kuten kehityssalaisuuksia ja suojausavaintoteutuksia. Vieraile osoitteessa Bitwaren.com ja tutustu Bitwarden Salaisuushallinta ja Bitwarden Passwordless.dev -palveluihin! diff --git a/apps/browser/store/locales/ja/copy.resx b/apps/browser/store/locales/ja/copy.resx index 67c479fcde6..910c8d7cab5 100644 --- a/apps/browser/store/locales/ja/copy.resx +++ b/apps/browser/store/locales/ja/copy.resx @@ -118,10 +118,10 @@ 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! @@ -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/lv/copy.resx b/apps/browser/store/locales/lv/copy.resx index e64cc2eb3a4..6d75e8ff0ef 100644 --- a/apps/browser/store/locales/lv/copy.resx +++ b/apps/browser/store/locales/lv/copy.resx @@ -118,10 +118,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Bitwarden Password Manager + Bitwarden paroļu pārvaldnieks - At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information. + Bitwarden viegli aizsargā visas paroles, paroļu atslēgas un jutīgu informāciju mājās, darbā vai ceļā. 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 viegli aizsargā visas paroles, paroļu atslēgas un jutīgu informāciju mājās, darbā vai ceļā. Sinhronizē un piekļūsti savai glabātavai no vairākām ierīcēm diff --git a/apps/browser/store/locales/pt_BR/copy.resx b/apps/browser/store/locales/pt_BR/copy.resx index 067f9357b23..0f4f00340d5 100644 --- a/apps/browser/store/locales/pt_BR/copy.resx +++ b/apps/browser/store/locales/pt_BR/copy.resx @@ -121,7 +121,7 @@ Gerenciador de Senhas Bitwarden - Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais. + Em qualquer lugar que esteja, 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 - Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais. + Em qualquer lugar que esteja, 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/cli/src/auth/commands/login.command.ts b/apps/cli/src/auth/commands/login.command.ts index bd61727a6c7..5e80f6faf40 100644 --- a/apps/cli/src/auth/commands/login.command.ts +++ b/apps/cli/src/auth/commands/login.command.ts @@ -3,7 +3,7 @@ import * as http from "http"; import { OptionValues } from "commander"; import * as inquirer from "inquirer"; import Separator from "inquirer/lib/objects/separator"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { LoginStrategyServiceAbstraction, @@ -15,6 +15,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; 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"; @@ -31,7 +32,6 @@ import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/c import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; @@ -60,7 +60,7 @@ export class LoginCommand { protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected passwordStrengthService: PasswordStrengthServiceAbstraction, protected platformUtilsService: PlatformUtilsService, - protected stateService: StateService, + protected accountService: AccountService, protected cryptoService: CryptoService, protected policyService: PolicyService, protected twoFactorService: TwoFactorService, @@ -491,7 +491,9 @@ export class LoginCommand { hint?: string; }> { if (this.email == null || this.email === "undefined") { - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); } // Get New Master Password diff --git a/apps/cli/src/auth/commands/unlock.command.ts b/apps/cli/src/auth/commands/unlock.command.ts index ca42be5ac5c..e3bb9257fac 100644 --- a/apps/cli/src/auth/commands/unlock.command.ts +++ b/apps/cli/src/auth/commands/unlock.command.ts @@ -1,4 +1,4 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; @@ -49,10 +49,11 @@ export class UnlockCommand { } await this.setNewSessionKey(); - const email = await this.stateService.getEmail(); + const [userId, email] = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])), + ); 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/commands/serve.command.ts b/apps/cli/src/commands/serve.command.ts index aad205998fb..2b1e21f8abb 100644 --- a/apps/cli/src/commands/serve.command.ts +++ b/apps/cli/src/commands/serve.command.ts @@ -103,7 +103,7 @@ export class ServeCommand { this.statusCommand = new StatusCommand( this.serviceContainer.environmentService, this.serviceContainer.syncService, - this.serviceContainer.stateService, + this.serviceContainer.accountService, this.serviceContainer.authService, ); this.deleteCommand = new DeleteCommand( diff --git a/apps/cli/src/commands/status.command.ts b/apps/cli/src/commands/status.command.ts index 32b93a7e40b..3fe8be620c2 100644 --- a/apps/cli/src/commands/status.command.ts +++ b/apps/cli/src/commands/status.command.ts @@ -1,9 +1,9 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { Response } from "../models/response"; @@ -13,7 +13,7 @@ export class StatusCommand { constructor( private envService: EnvironmentService, private syncService: SyncService, - private stateService: StateService, + private accountService: AccountService, private authService: AuthService, ) {} @@ -22,8 +22,9 @@ export class StatusCommand { const baseUrl = await this.baseUrl(); const status = await this.status(); const lastSync = await this.syncService.getLastSync(); - const userId = await this.stateService.getUserId(); - const email = await this.stateService.getEmail(); + const [userId, email] = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])), + ); return Response.success( new TemplateResponse({ diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index 3a2858aa817..667e0f683fd 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -1,6 +1,6 @@ import * as chalk from "chalk"; import { program, Command, OptionValues } from "commander"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; @@ -161,7 +161,7 @@ export class Program { this.serviceContainer.passwordGenerationService, this.serviceContainer.passwordStrengthService, this.serviceContainer.platformUtilsService, - this.serviceContainer.stateService, + this.serviceContainer.accountService, this.serviceContainer.cryptoService, this.serviceContainer.policyService, this.serviceContainer.twoFactorService, @@ -481,7 +481,7 @@ export class Program { const command = new StatusCommand( this.serviceContainer.environmentService, this.serviceContainer.syncService, - this.serviceContainer.stateService, + this.serviceContainer.accountService, this.serviceContainer.authService, ); const response = await command.run(); @@ -603,9 +603,15 @@ export class Program { } private async exitIfAuthed() { - const authed = await this.serviceContainer.stateService.getIsAuthenticated(); + const authed = await firstValueFrom( + this.serviceContainer.authService.activeAccountStatus$.pipe( + map((status) => status > AuthenticationStatus.LoggedOut), + ), + ); if (authed) { - const email = await this.serviceContainer.stateService.getEmail(); + const email = await firstValueFrom( + this.serviceContainer.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.processResponse(Response.error("You are already logged in as " + email + "."), true); } } diff --git a/apps/cli/src/service-container.ts b/apps/cli/src/service-container.ts index cffdc53444e..a47a943724f 100644 --- a/apps/cli/src/service-container.ts +++ b/apps/cli/src/service-container.ts @@ -103,10 +103,8 @@ import { EventUploadService } from "@bitwarden/common/services/event/event-uploa import { SearchService } from "@bitwarden/common/services/search.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; -import { - PasswordGenerationService, - PasswordGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/password"; +import { legacyPasswordGenerationServiceFactory } from "@bitwarden/common/tools/generator"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -499,10 +497,12 @@ export class ServiceContainer { this.passwordStrengthService = new PasswordStrengthService(); - this.passwordGenerationService = new PasswordGenerationService( + this.passwordGenerationService = legacyPasswordGenerationServiceFactory( + this.encryptService, this.cryptoService, this.policyService, - this.stateService, + this.accountService, + this.stateProvider, ); this.devicesApiService = new DevicesApiServiceImplementation(this.apiService); diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index ade019b9fba..6984e2da890 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -224,7 +224,9 @@ export class SettingsComponent implements OnInit { if ((await this.stateService.getUserId()) == null) { return; } - this.currentUserEmail = await this.stateService.getEmail(); + this.currentUserEmail = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.currentUserId = (await this.stateService.getUserId()) as UserId; this.availableVaultTimeoutActions$ = this.refreshTimeoutSettings$.pipe( @@ -697,13 +699,6 @@ export class SettingsComponent implements OnInit { ); if (errorResult !== null) { this.logService.error("Error in DDG browser integration: " + errorResult); - await this.dialogService.openSimpleDialog({ - title: { key: "browserIntegrationUnsupportedTitle" }, - content: errorResult.message, - acceptButtonText: { key: "ok" }, - cancelButtonText: null, - type: "warning", - }); } } diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts index e77ef8d3f07..901d7a9c5cc 100644 --- a/apps/desktop/src/app/app.component.ts +++ b/apps/desktop/src/app/app.component.ts @@ -411,7 +411,8 @@ export class AppComponent implements OnInit, OnDestroy { this.masterPasswordService.forceSetPasswordReason$(message.userId), )) != ForceSetPasswordReason.None; if (locked) { - this.messagingService.send("locked", { userId: message.userId }); + this.modalService.closeAll(); + await this.router.navigate(["lock"]); } else if (forcedPasswordReset) { // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // eslint-disable-next-line @typescript-eslint/no-floating-promises diff --git a/apps/desktop/src/app/tools/export/export.component.html b/apps/desktop/src/app/tools/export/export.component.html index 0058a0925c2..3792713e61e 100644 --- a/apps/desktop/src/app/tools/export/export.component.html +++ b/apps/desktop/src/app/tools/export/export.component.html @@ -21,11 +21,6 @@ - - - - diff --git a/apps/desktop/src/app/tools/export/export.component.ts b/apps/desktop/src/app/tools/export/export.component.ts index 80ae3c80f96..6cf5760a1cb 100644 --- a/apps/desktop/src/app/tools/export/export.component.ts +++ b/apps/desktop/src/app/tools/export/export.component.ts @@ -4,7 +4,6 @@ import { UntypedFormBuilder } from "@angular/forms"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -24,7 +23,6 @@ export class ExportComponent extends BaseExportComponent implements OnInit { exportService: VaultExportServiceAbstraction, eventCollectionService: EventCollectionService, policyService: PolicyService, - userVerificationService: UserVerificationService, formBuilder: UntypedFormBuilder, logService: LogService, fileDownloadService: FileDownloadService, @@ -38,7 +36,6 @@ export class ExportComponent extends BaseExportComponent implements OnInit { eventCollectionService, policyService, logService, - userVerificationService, formBuilder, fileDownloadService, dialogService, diff --git a/apps/desktop/src/app/tools/generator.component.spec.ts b/apps/desktop/src/app/tools/generator.component.spec.ts index d908de8ef77..dff7da96004 100644 --- a/apps/desktop/src/app/tools/generator.component.spec.ts +++ b/apps/desktop/src/app/tools/generator.component.spec.ts @@ -8,7 +8,6 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -36,10 +35,6 @@ describe("GeneratorComponent", () => { provide: UsernameGenerationServiceAbstraction, useValue: mock(), }, - { - provide: StateService, - useValue: mock(), - }, { provide: PlatformUtilsService, useValue: platformUtilsServiceMock, diff --git a/apps/desktop/src/app/tools/generator.component.ts b/apps/desktop/src/app/tools/generator.component.ts index a36bffa0e5f..a5c3d393877 100644 --- a/apps/desktop/src/app/tools/generator.component.ts +++ b/apps/desktop/src/app/tools/generator.component.ts @@ -1,11 +1,11 @@ -import { Component } from "@angular/core"; +import { Component, NgZone } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { GeneratorComponent as BaseGeneratorComponent } from "@bitwarden/angular/tools/generator/components/generator.component"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; @@ -17,20 +17,22 @@ export class GeneratorComponent extends BaseGeneratorComponent { constructor( passwordGenerationService: PasswordGenerationServiceAbstraction, usernameGenerationService: UsernameGenerationServiceAbstraction, - stateService: StateService, + accountService: AccountService, platformUtilsService: PlatformUtilsService, i18nService: I18nService, route: ActivatedRoute, + ngZone: NgZone, logService: LogService, ) { super( passwordGenerationService, usernameGenerationService, platformUtilsService, - stateService, + accountService, i18nService, logService, route, + ngZone, window, ); } diff --git a/apps/desktop/src/auth/login/login-approval.component.ts b/apps/desktop/src/auth/login/login-approval.component.ts index 048d294f4aa..296efb50e4a 100644 --- a/apps/desktop/src/auth/login/login-approval.component.ts +++ b/apps/desktop/src/auth/login/login-approval.component.ts @@ -1,17 +1,17 @@ import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog"; import { CommonModule } from "@angular/common"; import { Component, OnInit, OnDestroy, Inject } from "@angular/core"; -import { Subject, firstValueFrom } from "rxjs"; +import { Subject, firstValueFrom, map } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { AuthRequestServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { AsyncActionsModule, @@ -47,7 +47,7 @@ export class LoginApprovalComponent implements OnInit, OnDestroy { constructor( @Inject(DIALOG_DATA) private params: LoginApprovalDialogParams, protected authRequestService: AuthRequestServiceAbstraction, - protected stateService: StateService, + protected accountService: AccountService, protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, protected apiService: ApiService, @@ -74,7 +74,9 @@ export class LoginApprovalComponent implements OnInit, OnDestroy { if (this.notificationId != null) { this.authRequestResponse = await this.apiService.getAuthRequest(this.notificationId); const publicKey = Utils.fromB64ToArray(this.authRequestResponse.publicKey); - this.email = await this.stateService.getEmail(); + this.email = await await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.fingerprintPhrase = ( await this.cryptoService.getFingerprint(this.email, publicKey) ).join("-"); 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 2d0f560205b..40d41f22361 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 @@ -21,7 +21,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; @@ -53,7 +52,6 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { validationService: ValidationService, private modalService: ModalService, syncService: SyncService, - stateService: StateService, loginEmailService: LoginEmailServiceAbstraction, deviceTrustService: DeviceTrustServiceAbstraction, authRequestService: AuthRequestServiceAbstraction, @@ -75,12 +73,11 @@ export class LoginViaAuthRequestComponent extends BaseLoginWithDeviceComponent { platformUtilsService, anonymousHubService, validationService, - stateService, + accountService, loginEmailService, deviceTrustService, authRequestService, loginStrategyService, - accountService, ); super.onSuccessfulLogin = () => { diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 97067b788a5..4b7033d7179 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Wek ’n e-posalias op met ’n eksterne aanstuurdiens." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Gasheernaam", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 74c3d63e332..43679661833 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "إنشاء بريد إلكتروني مستعار مع خدمة إعادة توجيه خارجية." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "اسم المضيف", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 1ecd18eee75..d5efd39e310 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Xarici yönləndirmə xidməti ilə e-poçt ləqəbi yaradın." }, + "forwarderError": { + "message": "$SERVICENAME$ xətası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Veb sayt: $WEBSITE$. Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Yararsız $SERVICENAME$ API jetonu", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Yararsız $SERVICENAME$ API jetonu: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ maskalı e-poçt hesab kimliyi alına bilmir.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Yararsız $SERVICENAME$ domeni.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Yararsız $SERVICENAME$ url-si.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Bilinməyən $SERVICENAME$ xətası baş verdi.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Bilinməyən yönləndirici: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Host adı", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index e0133e5a742..e338e021d25 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Генерыраваць псеўданім электроннай пошты са знешнім сэрвісам перасылкі." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Назва вузла", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index 0728178b7b8..04c5c280076 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Създайте псевдоним на е-поща с външна услуга за препращане." }, + "forwarderError": { + "message": "Грешка от $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Уебсайт: $WEBSITE$. Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не може да бъде получен идентификатор на маскиран чрез е-поща акаунт от $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Неправилен домейн за $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Неправилен адрес на $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Възникна неочаквана грешка свързана с $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестна пренасочваща услуга: „$SERVICENAME$“.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име на сървъра", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 626734ebffc..8c475a0fbb3 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 9d5685cca90..2848fce4995 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index d7100af7648..707cc20e550 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Genera un àlies de correu electrònic amb un servei de reenviament extern." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom de l'amfitrió", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index e68fe8fffc4..6ad51e8f262 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Vygeneruje alias e-mailu pomocí externí přeposílací služby." }, + "forwarderError": { + "message": "Chyba $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webová stránka: $WEBSITE$. Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Neplatný token API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Neplatný token API $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nelze získat maskované ID e-mailového účtu $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Neplatná doména $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Neplatné URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Došlo k neznámé chybě $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Neznámý přeposílatel: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Název hostitele", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index 62f2e608bbf..4deeb36aeea 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 0e578a6f66e..2ba2c7b5d0a 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generér et e-mail alias med en ekstern viderestillingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$-fejl: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Websted: $WEBSITE$. Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Ugyldigt $SERVICENAME$ API-token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Ugyldigt $SERVICENAME$ API-token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Kan ikke få $SERVICENAME$ maskeret e-mailkonto-ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ugyldigt $SERVICENAME$-domæne.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ugyldig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ukendt $SERVICENAME$-fejl opstod.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ukendt videresender: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Værtsnavn", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index d04c2795f33..99f02f01ff8 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Erzeuge ein E-Mail-Alias mit einem externen Weiterleitungsdienst." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 87360c33ce0..61fa2f8d373 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Δημιουργήστε ένα alias email με μια εξωτερική υπηρεσία προώθησης." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 5572d2fd352..61e89c80fa7 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 79f2de8f63c..a3391c64361 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 427f08f8052..be3d33cb6e8 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index d509a91d957..e1936f918fc 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -1508,7 +1508,7 @@ "message": "Cerrar sesión en la caja fuerte requiere que vuelvas a autenticarte para acceder nuevamente a ella." }, "unlockMethodNeededToChangeTimeoutActionDesc": { - "message": "Set up an unlock method to change your vault timeout action." + "message": "Configura un método de desbloqueo para cambiar el tiempo de espera de tu caja fuerte." }, "lock": { "message": "Bloquear", @@ -1549,7 +1549,7 @@ "message": "Establecer contraseña maestra" }, "orgPermissionsUpdatedMustSetPassword": { - "message": "Your organization permissions were updated, requiring you to set a master password.", + "message": "Los permisos de tu organización han sido actualizados, requiriendo que establezcas una contraseña maestra.", "description": "Used as a card title description on the set password page to explain why the user is there" }, "orgRequiresYouToSetPassword": { @@ -1657,7 +1657,7 @@ "message": "Utilizar aceleración de hardware" }, "enableHardwareAccelerationDesc": { - "message": "By default this setting is ON. Turn OFF only if you experience graphical issues. Restart is required." + "message": "Por defecto esta opción está activada. Desactívala solo si experimentas problemas gráficos. Es necesario reiniciar." }, "approve": { "message": "Aprobar" @@ -1699,7 +1699,7 @@ "message": "Una política de organización está afectando a sus opciones de propiedad." }, "personalOwnershipPolicyInEffectImports": { - "message": "An organization policy has blocked importing items into your individual vault." + "message": "Una política organizacional ha bloqueado la importación de elementos a su caja fuerte personal." }, "allSends": { "message": "Todos los Send", @@ -1901,7 +1901,7 @@ "message": "Intentar de nuevo" }, "verificationRequiredForActionSetPinToContinue": { - "message": "Verification required for this action. Set a PIN to continue." + "message": "Se requiere verificación para esta acción. Establece un PIN para continuar." }, "setPin": { "message": "Establecer PIN" @@ -1910,28 +1910,28 @@ "message": "Verificar biométricamente" }, "awaitingConfirmation": { - "message": "Awaiting confirmation" + "message": "Esperando confirmación" }, "couldNotCompleteBiometrics": { - "message": "Could not complete biometrics." + "message": "No se pudieron completar los datos biométricos." }, "needADifferentMethod": { - "message": "Need a different method?" + "message": "¿Necesitas un método diferente?" }, "useMasterPassword": { - "message": "Use master password" + "message": "Utilizar la contraseña maestra" }, "usePin": { - "message": "Use PIN" + "message": "Usar PIN" }, "useBiometrics": { - "message": "Use biometrics" + "message": "Usar datos biométricos" }, "enterVerificationCodeSentToEmail": { - "message": "Enter the verification code that was sent to your email." + "message": "Introduce el código de verificación que ha sido enviado a tu correo electrónico." }, "resendCode": { - "message": "Resend code" + "message": "Reenviar código" }, "hours": { "message": "Horas" @@ -2060,7 +2060,7 @@ "message": "Exportando caja fuerte personal" }, "exportingIndividualVaultDescription": { - "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.", + "message": "Solo los elementos individuales de la caja fuerte asociados con $EMAIL$ serán exportados. No se incluirán los elementos de la caja fuerte de la organización. Solo la información de los elementos de la caja fuerte será exportada y no se incluirán los archivos adjuntos asociados.", "placeholders": { "email": { "content": "$1", @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generar un alias de correo electrónico con un servicio de reenvío externo." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generado por Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Sitio web: $WEBSITE$. Generado por Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token de API $SERVICENAME$ no válido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token de API $SERVICENAME$ no válido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "No se puede obtener el ID de la cuenta de correo electrónico enmascarado de $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Dominio $SERVICENAME$ no válido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ no válida.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Se ha producido un error desconocido de $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Redirigidor desconocido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nombre del host", "description": "Part of a URL." @@ -2185,7 +2287,7 @@ "message": "Iniciar sesión con otro dispositivo" }, "loginInitiated": { - "message": "Login initiated" + "message": "Inicio de sesión iniciado" }, "notificationSentDevice": { "message": "Se ha enviado una notificación a tu dispositivo." @@ -2325,77 +2427,77 @@ "message": "Actualización de ajustes recomendados" }, "deviceApprovalRequired": { - "message": "Device approval required. Select an approval option below:" + "message": "Se requiere aprobación del dispositivo. Selecciona una opción de aprobación a continuación:" }, "rememberThisDevice": { "message": "Recordar este dispositivo" }, "uncheckIfPublicDevice": { - "message": "Uncheck if using a public device" + "message": "Desmarca si estás usando un dispositivo público" }, "approveFromYourOtherDevice": { - "message": "Approve from your other device" + "message": "Aprobar desde tu otro dispositivo" }, "requestAdminApproval": { - "message": "Request admin approval" + "message": "Solicitar aprobación del administrador" }, "approveWithMasterPassword": { - "message": "Approve with master password" + "message": "Aprobar con contraseña maestra" }, "region": { - "message": "Region" + "message": "Región" }, "ssoIdentifierRequired": { - "message": "Organization SSO identifier is required." + "message": "Se requiere un identificador único de inicio de sesión de la organización." }, "eu": { - "message": "EU", + "message": "Unión Europea", "description": "European Union" }, "loggingInOn": { - "message": "Logging in on" + "message": "Iniciando sesión en" }, "selfHostedServer": { - "message": "self-hosted" + "message": "autoalojado" }, "accessDenied": { "message": "Acceso denegado. No tiene permiso para ver esta página." }, "accountSuccessfullyCreated": { - "message": "Account successfully created!" + "message": "¡Cuenta creada con éxito!" }, "adminApprovalRequested": { - "message": "Admin approval requested" + "message": "Aprobación del administrador solicitada" }, "adminApprovalRequestSentToAdmins": { - "message": "Your request has been sent to your admin." + "message": "Tu solicitud ha sido enviada a tu administrador." }, "youWillBeNotifiedOnceApproved": { - "message": "You will be notified once approved." + "message": "Se te notificará una vez aprobado." }, "troubleLoggingIn": { - "message": "Trouble logging in?" + "message": "¿Tienes problemas para iniciar sesión?" }, "loginApproved": { - "message": "Login approved" + "message": "Inicio de sesión aprobado" }, "userEmailMissing": { - "message": "User email missing" + "message": "Falta el correo electrónico del usuario" }, "deviceTrusted": { - "message": "Device trusted" + "message": "Dispositivo de confianza" }, "inputRequired": { - "message": "Input is required." + "message": "La entrada requerida." }, "required": { - "message": "required" + "message": "requerido" }, "search": { "message": "Buscar" }, "inputMinLength": { - "message": "Input must be at least $COUNT$ characters long.", + "message": "La entrada debe tener al menos $COUNT$ caracteres.", "placeholders": { "count": { "content": "$1", @@ -2404,7 +2506,7 @@ } }, "inputMaxLength": { - "message": "Input must not exceed $COUNT$ characters in length.", + "message": "La entrada no debe exceder los $COUNT$ caracteres de longitud.", "placeholders": { "count": { "content": "$1", @@ -2413,7 +2515,7 @@ } }, "inputForbiddenCharacters": { - "message": "The following characters are not allowed: $CHARACTERS$", + "message": "Los siguientes caracteres no están permitidos: $CHARACTERS$", "placeholders": { "characters": { "content": "$1", @@ -2422,7 +2524,7 @@ } }, "inputMinValue": { - "message": "Input value must be at least $MIN$.", + "message": "El valor de entrada debe ser de al lo menos $MIN$.", "placeholders": { "min": { "content": "$1", @@ -2431,7 +2533,7 @@ } }, "inputMaxValue": { - "message": "Input value must not exceed $MAX$.", + "message": "El valor de entrada no debe exceder $MAX$.", "placeholders": { "max": { "content": "$1", @@ -2440,17 +2542,17 @@ } }, "multipleInputEmails": { - "message": "1 or more emails are invalid" + "message": "Una o más direcciones de correo electrónico no son válidas" }, "inputTrimValidator": { - "message": "Input must not contain only whitespace.", + "message": "La entrada no debe contener únicamente espacios en blanco.", "description": "Notification to inform the user that a form's input can't contain only whitespace." }, "inputEmail": { - "message": "Input is not an email address." + "message": "La entrada no es una dirección de correo electrónico." }, "fieldsNeedAttention": { - "message": "$COUNT$ field(s) above need your attention.", + "message": "$COUNT$ campo(s) anterior(es) necesitan su atención.", "placeholders": { "count": { "content": "$1", @@ -2459,22 +2561,22 @@ } }, "selectPlaceholder": { - "message": "-- Select --" + "message": "-- Selecciona --" }, "multiSelectPlaceholder": { - "message": "-- Type to filter --" + "message": "-- Escribe para filtrar --" }, "multiSelectLoading": { - "message": "Retrieving options..." + "message": "Recuperando opciones..." }, "multiSelectNotFound": { - "message": "No items found" + "message": "No se encontraron elementos" }, "multiSelectClearAll": { - "message": "Clear all" + "message": "Limpiar todo" }, "plusNMore": { - "message": "+ $QUANTITY$ more", + "message": "+ $QUANTITY$ más", "placeholders": { "quantity": { "content": "$1", @@ -2483,44 +2585,44 @@ } }, "submenu": { - "message": "Submenu" + "message": "Submenú" }, "skipToContent": { - "message": "Skip to content" + "message": "Saltar al contenido" }, "typePasskey": { - "message": "Passkey" + "message": "Clave de acceso" }, "passkeyNotCopied": { - "message": "Passkey will not be copied" + "message": "La clave de acceso no se copiará" }, "passkeyNotCopiedAlert": { - "message": "The passkey will not be copied to the cloned item. Do you want to continue cloning this item?" + "message": "La clave de acceso no se copiará al elemento clonado. ¿Quieres continuar clonando este elemento?" }, "aliasDomain": { - "message": "Alias domain" + "message": "Alias de dominio" }, "importData": { - "message": "Import data", + "message": "Importar datos", "description": "Used for the desktop menu item and the header of the import dialog" }, "importError": { - "message": "Import error" + "message": "Error de importación" }, "importErrorDesc": { - "message": "There was a problem with the data you tried to import. Please resolve the errors listed below in your source file and try again." + "message": "Hubo un problema con los datos que intentaste importar. Por favor, resuelve los errores listados a continuación en tu archivo de origen e inténtalo de nuevo." }, "resolveTheErrorsBelowAndTryAgain": { - "message": "Resolve the errors below and try again." + "message": "Resuelve los errores que aparecen a continuación e inténtalo de nuevo." }, "description": { - "message": "Description" + "message": "Descripción" }, "importSuccess": { - "message": "Data successfully imported" + "message": "Datos importados correctamente" }, "importSuccessNumberOfItems": { - "message": "A total of $AMOUNT$ items were imported.", + "message": "Se importaron un total de $AMOUNT$ elementos.", "placeholders": { "amount": { "content": "$1", @@ -2532,7 +2634,7 @@ "message": "Total" }, "importWarning": { - "message": "You are importing data to $ORGANIZATION$. Your data may be shared with members of this organization. Do you want to proceed?", + "message": "Estás importando datos a $ORGANIZATION$. Tus datos pueden ser compartidos con miembros de esta organización. ¿Quieres continuar?", "placeholders": { "organization": { "content": "$1", @@ -2541,40 +2643,40 @@ } }, "launchDuoAndFollowStepsToFinishLoggingIn": { - "message": "Launch Duo and follow the steps to finish logging in." + "message": "Inicia Duo y sigue los pasos para terminar de iniciar sesión." }, "duoRequiredByOrgForAccount": { - "message": "Duo two-step login is required for your account." + "message": "Se requiere el inicio de sesión en dos pasos de Duo para tu cuenta." }, "launchDuo": { - "message": "Launch Duo in Browser" + "message": "Inicia Duo en el navegador" }, "importFormatError": { - "message": "Data is not formatted correctly. Please check your import file and try again." + "message": "Los datos no están formateados correctamente. Por favor, comprueba tu archivo de importación e inténtalo de nuevo." }, "importNothingError": { - "message": "Nothing was imported." + "message": "No se ha importado nada." }, "importEncKeyError": { - "message": "Error decrypting the exported file. Your encryption key does not match the encryption key used export the data." + "message": "Error al descifrar el archivo exportado. Tu clave de cifrado no coincide con la clave de cifrado utilizada para exportar los datos." }, "invalidFilePassword": { - "message": "Invalid file password, please use the password you entered when you created the export file." + "message": "Contraseña de archivo no válida, por favor utiliza la contraseña que introdujiste cuando creaste el archivo de exportación." }, "importDestination": { - "message": "Import destination" + "message": "Destino de importación" }, "learnAboutImportOptions": { - "message": "Learn about your import options" + "message": "Aprende acerca de tus opciones de importación" }, "selectImportFolder": { - "message": "Select a folder" + "message": "Escoge una carpeta" }, "selectImportCollection": { - "message": "Select a collection" + "message": "Escoge una colección" }, "importTargetHint": { - "message": "Select this option if you want the imported file contents moved to a $DESTINATION$", + "message": "Selecciona esta opción si quieres que el contenido del archivo importado se mueva a un $DESTINATION$", "description": "Located as a hint under the import target. Will be appended by either folder or collection, depending if the user is importing into an individual or an organizational vault.", "placeholders": { "destination": { @@ -2584,25 +2686,25 @@ } }, "importUnassignedItemsError": { - "message": "File contains unassigned items." + "message": "El archivo contiene elementos no asignados." }, "selectFormat": { - "message": "Select the format of the import file" + "message": "Selecciona el formato del archivo de importación" }, "selectImportFile": { - "message": "Select the import file" + "message": "Selecciona el archivo de importación" }, "chooseFile": { - "message": "Choose File" + "message": "Escoge el archivo" }, "noFileChosen": { - "message": "No file chosen" + "message": "No se ha elegido nungún archivo" }, "orCopyPasteFileContents": { - "message": "or copy/paste the import file contents" + "message": "o copia/pega el contenido del archivo de importación" }, "instructionsFor": { - "message": "$NAME$ Instructions", + "message": "Instrucciones para $NAME$", "description": "The title for the import tool instructions.", "placeholders": { "name": { @@ -2612,113 +2714,113 @@ } }, "confirmVaultImport": { - "message": "Confirm vault import" + "message": "Confirma la importación de la caja fuerte" }, "confirmVaultImportDesc": { - "message": "This file is password-protected. Please enter the file password to import data." + "message": "Este archivo está protegido por contraseña. Por favor, introduce la contraseña del archivo para importar los datos." }, "confirmFilePassword": { - "message": "Confirm file password" + "message": "Confirma la contraseña del archivo" }, "multifactorAuthenticationCancelled": { - "message": "Multifactor authentication cancelled" + "message": "Autenticación multifactor cancelada" }, "noLastPassDataFound": { - "message": "No LastPass data found" + "message": "No se encontraron datos de LastPass" }, "incorrectUsernameOrPassword": { - "message": "Incorrect username or password" + "message": "Nombre de usuario o contraseña incorrectos" }, "incorrectPassword": { - "message": "Incorrect password" + "message": "Contraseña incorrecta" }, "incorrectCode": { - "message": "Incorrect code" + "message": "Código incorrecto" }, "incorrectPin": { - "message": "Incorrect PIN" + "message": "PIN incorrecto" }, "multifactorAuthenticationFailed": { - "message": "Multifactor authentication failed" + "message": "Falló la autenticación multifactor" }, "includeSharedFolders": { - "message": "Include shared folders" + "message": "Incluir carpetas compartidas" }, "lastPassEmail": { - "message": "LastPass Email" + "message": "Correo electrónico de LastPass" }, "importingYourAccount": { - "message": "Importing your account..." + "message": "Importando tu cuenta..." }, "lastPassMFARequired": { - "message": "LastPass multifactor authentication required" + "message": "Se requiere autenticación multifactor de LastPass" }, "lastPassMFADesc": { - "message": "Enter your one-time passcode from your authentication app" + "message": "Introduce el código de acceso de un solo uso desde la aplicación de autenticación" }, "lastPassOOBDesc": { - "message": "Approve the login request in your authentication app or enter a one-time passcode." + "message": "Aprueba la solicitud de inicio de sesión en tu aplicación de autenticación o introduce un código de acceso de una sola vez." }, "passcode": { - "message": "Passcode" + "message": "Código de acceso" }, "lastPassMasterPassword": { - "message": "LastPass master password" + "message": "Contraseña maestra de LastPass" }, "lastPassAuthRequired": { - "message": "LastPass authentication required" + "message": "Se requiere autenticación de LastPass" }, "awaitingSSO": { - "message": "Awaiting SSO authentication" + "message": "Esperando autenticación SSO" }, "awaitingSSODesc": { - "message": "Please continue to log in using your company credentials." + "message": "Por favor, continua para iniciar sesión usando las credenciales de tu empresa." }, "seeDetailedInstructions": { - "message": "See detailed instructions on our help site at", + "message": "Consulte las instrucciones detalladas en nuestro sitio de ayuda en", "description": "This is followed a by a hyperlink to the help website." }, "importDirectlyFromLastPass": { - "message": "Import directly from LastPass" + "message": "Importar directamente desde LastPass" }, "importFromCSV": { - "message": "Import from CSV" + "message": "Importar desde CSV" }, "lastPassTryAgainCheckEmail": { - "message": "Try again or look for an email from LastPass to verify it's you." + "message": "Inténtalo de nuevo o busca un correo electrónico de LastPass para verificar que eres tú." }, "collection": { - "message": "Collection" + "message": "Colección" }, "lastPassYubikeyDesc": { - "message": "Insert the YubiKey associated with your LastPass account into your computer's USB port, then touch its button." + "message": "Inserta la YubiKey asociada a tu cuenta de LastPass en el puerto USB de tu ordenador y, pulsa su botón." }, "commonImportFormats": { - "message": "Common formats", + "message": "Formatos comunes", "description": "Label indicating the most common import formats" }, "success": { - "message": "Success" + "message": "Éxito" }, "troubleshooting": { - "message": "Troubleshooting" + "message": "Resolución de problemas" }, "disableHardwareAccelerationRestart": { - "message": "Disable hardware acceleration and restart" + "message": "Desactivar la aceleración de hardware y reiniciar" }, "enableHardwareAccelerationRestart": { - "message": "Enable hardware acceleration and restart" + "message": "Activar la aceleración de hardware y reiniciar" }, "removePasskey": { - "message": "Remove passkey" + "message": "Eliminar clave de acceso" }, "passkeyRemoved": { - "message": "Passkey removed" + "message": "Clave de acceso eliminada" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Error al asignar la colección de destino." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Error al asignar la carpeta de destino." } } diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 02cd737baac..2a44cdef5c1 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Genereeri e-posti alias, kasutades selleks välist teenuspakkujat." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hosti nimi", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 2067b2dcc2e..871339207e4 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Emaileko ezizen bat sortu kanpoko bidalketa zerbitzu batekin." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ostalariaren izena", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index ef34f8222ae..d034ebecaf6 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "یک نام مستعار ایمیل با یک سرویس ارسال خارجی ایجاد کنید." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "نام میزبان", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 517b437d030..f67e8416865 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -2127,11 +2127,113 @@ "message": "Etsi omasta holvista" }, "forwardedEmail": { - "message": "Sähköpostialias välitykseen" + "message": "Sähköpostialias ohjaukseen" }, "forwardedEmailDesc": { "message": "Luo sähköpostialias ulkoisella ohjauspalvelulla." }, + "forwarderError": { + "message": "$SERVICENAME$ -virhe: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Verkkosivusto: $WEBSITE$. Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ -palvelun peittämän sähköpostitilin tunnistetta ei saatu.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Virheellinen $SERVICENAME$ -verkkotunnus.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Virheellinen $SERVICENAME$ -URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Tapahtui tuntematon $SERVICENAME$ -virhe.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Tuntematon ohjaaja: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Isäntä", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index d28a4b568c3..dac2ad8b051 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Bumuo ng isang email alias na may isang panlabas na serbisyo sa pagpapasa." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Pangalan ng Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index 8298544d2e8..977f5c2efdd 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -705,7 +705,7 @@ "message": "URL du serveur" }, "apiUrl": { - "message": "URL du serveur de l'IPA" + "message": "URL du serveur de l'API" }, "webVaultUrl": { "message": "URL du serveur du coffre web" @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Générer un alias de courriel avec un service de transfert externe." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom d'hôte", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 889a2beeee0..f237df0e7e5 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 3b155ffdf3e..53ad9ce5e8e 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "צור כינוי דוא\"ל באמצעות שירות שליחת דוא\"ל חיצוני." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "שם מארח", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index af28c666813..a77a2ceb75a 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 01983d5891e..986c79ad4ce 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generiraj pseudonim e-pošte s vanjskom uslugom prosljeđivanja." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Naziv poslužitelja", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 838b3fc7c8e..b9b020af9ea 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Email álnév generálása külső továbbító szolgáltatással." }, + "forwarderError": { + "message": "$SERVICENAME$ hiba: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webhely: $WEBSITE$. Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "$SERVICENAME$ API vezérjel érvénytelen.", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "$SERVICENAME$ API vezérjel érvénytelen: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nem lehet beolvasni $SERVICENAME$ maszkolt email fiók azonosítót.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "$SERVICENAME$ domain érvénytelen.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "$SERVICENAME$ webcím érvénytelen.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ismeretlen $SERVICENAME$ hiba történt.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ismeretlen továbbító: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Kiszolglónév", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 2173224f541..2bdb790cbb4 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 93882cf6985..e2860736efb 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Genera un alias email con un servizio di inoltro esterno." }, + "forwarderError": { + "message": "Errore $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Sito web: $WEBSITE$. Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token API $SERVICENAME$ non valido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token API $SERVICENAME$ non valido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Impossibile ottenere l'ID dell'account email mascherato di $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Dominio $SERVICENAME$ non valido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ non valido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Errore di $SERVICENAME$ sconosciuto.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Mittente sconosciuto: \"$SERVICENAME$\".", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome host", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index ab6c0be95f7..003e0debdf6 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "外部転送サービスを使用してメールエイリアスを生成します。" }, + "forwarderError": { + "message": "$SERVICENAME$ エラー: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "ウェブサイト: $WEBSITE$ Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "不正な$SERVICENAME$ API トークン", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "不正な$SERVICENAME$ API トークン: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ マスク済みメールアカウント ID を取得できませんでした。", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "不正な $SERVICENAME$ ドメインです。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "不正な $SERVICENAME$ URL です。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "不明な $SERVICENAME$ エラーが起きました。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "不明な転送先: '$SERVICENAME$'", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "ホスト名", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 889a2beeee0..f237df0e7e5 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 889a2beeee0..f237df0e7e5 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index eb0cbcf6be7..f6203c5077b 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 8e50ade96cd..dbddb6fc2b9 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "외부 포워딩 서비스를 사용해서 이메일 주소 별칭을 만들어보세요." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "호스트 이름", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index e9de6970054..499a461607c 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Sugeneruoti el. pašto slapyvardį su išorine persiuntimo paslauga." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Pagrindinio kompiuterio vardas", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index e2e068362e3..0c30801aaca 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Izveidot e-pastu aizstājvārdu ar ārēju pārvirzīšanas pakalpojumu." }, + "forwarderError": { + "message": "$SERVICENAME$ kļūda: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Tīmekļvietne: $WEBSITE$. Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nederīga $SERVICENAME$ API pilnvara", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nederīga $SERVICENAME$ API pilnvara: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Neizdevās iegūt $SERVICENAME$ aizsegta e-pasta konta Id.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nederīgs $SERVICENAME$ domēna vārds.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nederīgs $SERVICENAME$ URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Atgadījās nezināma $SERVICENAME$ kļūda.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Nezināms pārsūtītājs: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Resursdatora nosaukums", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 1f49961b469..f391691852a 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 96811b9dba8..b6fa303c944 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 889a2beeee0..f237df0e7e5 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index 0ee0db69ef2..61444fbf828 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 7bf132bdac1..37d1a67f480 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generer et e-postalias med en ekstern videresendingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Vertsnavn", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index 13e14668054..529c8967dd8 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index f56572259ba..c7e22825eab 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Genereer een e-mailalias met een externe doorstuurservice." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostnaam", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 35e7173d74a..5f51fd52d6e 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index cd83d2ea698..1099bf1abfd 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index 250c557309c..46900c171a6 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Wygeneruj alias adresu e-mail z zewnętrznej usługi przekazywania." }, + "forwarderError": { + "message": "Błąd $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Wygenerowane przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Strona internetowa: $WEBSITE$. Wygenerowano przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nieprawidłowy token API dla $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nieprawidłowy token API dla $SERVICENAME$, błąd: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nie można uzyskać ID maskowanego konta e-mail dla $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nieprawidłowa domena $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nieprawidłowy adres URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Wystąpił nieznany błąd w $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nazwa hosta", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 12db01d8cd1..52d85822fb7 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Gere um alias de e-mail com um serviço externo de encaminhamento." }, + "forwarderError": { + "message": "Erro $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token de API $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token de API $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter a máscara do ID da conta de email $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ inválida.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro $SERVICENAME$ desconhecido.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Encaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome do host", "description": "Part of a URL." @@ -2698,7 +2800,7 @@ "description": "Label indicating the most common import formats" }, "success": { - "message": "Success" + "message": "Sucesso" }, "troubleshooting": { "message": "Solução de problemas" diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 2535f5d8605..e04857976bd 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Gerar um alias de e-mail com um serviço de reencaminhamento externo." }, + "forwarderError": { + "message": "Erro no $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token da API de $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token da API de $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter o ID da conta de e-mail mascarada de $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio de $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL de $SERVICENAME$ inválido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro desconhecido de $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Reencaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome de domínio", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 978f57eb9b7..185bc111ee1 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generați un alias de e-mail cu un serviciu de redirecționare extern." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nume gazdă", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index c9b3b95b39c..d52af566de0 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Создать псевдоним электронной почты для внешней службы пересылки." }, + "forwarderError": { + "message": "Ошибка $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Сайт: $WEBSITE$. Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неверный токен API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неверный токен $SERVICENAME$ API: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не удалось получить скрытый идентификатор email аккаунта $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Недопустимый домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Некорректный URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Произошла неизвестная ошибка $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестный форвардер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Имя хоста", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 3d439971442..9a298a0ff50 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 6499486b9d5..d2dcbb5e196 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Vytvoriť e-mailový alias pomocou externej služby preposielania." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Názov hostiteľa", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 8cb06dcf0ca..385a6856b19 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -1414,10 +1414,10 @@ "message": "Preverite za Bitwarden." }, "unlockWithTouchId": { - "message": "Unlock with Touch ID" + "message": "Odkleni z biometriko" }, "additionalTouchIdSettings": { - "message": "Additional Touch ID settings" + "message": "Dodatne nastavitve za Touch ID" }, "touchIdConsentMessage": { "message": "odklenite vaš trezor" @@ -1426,10 +1426,10 @@ "message": "Ask for Windows Hello on app start" }, "autoPromptTouchId": { - "message": "Ask for Touch ID on app start" + "message": "Biometrično preverjanje ob zagonu aplikacije" }, "requirePasswordOnStart": { - "message": "Require password or PIN on app start" + "message": "Ob zagonu zahteva geslo ali PIN" }, "recommendedForSecurity": { "message": "Recommended for security." @@ -1499,7 +1499,7 @@ "message": "One or more organization policies are affecting your generator settings." }, "vaultTimeoutAction": { - "message": "Vault timeout action" + "message": "Dejanje po časovni omejitvi trezorja" }, "vaultTimeoutActionLockDesc": { "message": "Master password or other unlock method is required to access your vault again." @@ -1618,7 +1618,7 @@ "message": "Terms of Service and Privacy Policy have not been acknowledged." }, "enableBrowserIntegration": { - "message": "Allow browser integration" + "message": "Dovoli integracijo z brskalnikom" }, "enableBrowserIntegrationDesc": { "message": "Used for biometrics in browser." @@ -1630,7 +1630,7 @@ "message": "Use your Bitwarden vault when browsing with DuckDuckGo." }, "browserIntegrationUnsupportedTitle": { - "message": "Browser integration not supported" + "message": "Integracija z brskalnikom ni podprta" }, "browserIntegrationErrorTitle": { "message": "Error enabling browser integration" @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -2237,7 +2339,7 @@ "message": "Deny login" }, "approveLoginRequests": { - "message": "Approve login requests" + "message": "Odobri zahtevke za prijavo" }, "logInConfirmedForEmailOnDevice": { "message": "Login confirmed for $EMAIL$ on $DEVICE$", @@ -2274,7 +2376,7 @@ "message": "This request is no longer valid." }, "approveLoginRequestDesc": { - "message": "Use this device to approve login requests made from other devices." + "message": "S to napravo odobri zahtevke za prijavo, ki pridejo z drugih naprav." }, "confirmLoginAtemptForMail": { "message": "Confirm login attempt for $EMAIL$", diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index f947d7dae7c..5f32c322f99 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Генеришите псеудоним е-поште помоћу екстерне услуге прослеђивања." }, + "forwarderError": { + "message": "$SERVICENAME$ грешка: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Вебсајт: $WEBSITE$. Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Погрешан АПИ токен $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Погрешан АПИ токен $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Није могуће добити ИД налога маскираног имејла $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Погрешан домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Погрешан УРЛ $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Непозната грешка $SERVICENAME$-а.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Непознати шпедитер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име домаћина", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index bd21c0f328a..4b6f50e1f07 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Skapa ett e-postalias med en extern vidarebefordranstjänst." }, + "forwarderError": { + "message": "$SERVICENAME$-fel: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ogiltig $SERVICENAME$-domän.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ogiltig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Värdnamn", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 889a2beeee0..f237df0e7e5 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index f1cd5351f7f..3e98b49e174 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index adeb293ccf1..476303869e9 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Harici bir yönlendirme servisiyle e-posta maskesi oluştur." }, + "forwarderError": { + "message": "$SERVICENAME$ hatası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Web sitesi: $WEBSITE$. Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Sunucu", "description": "Part of a URL." @@ -2716,9 +2818,9 @@ "message": "Geçiş anahtarı kaldırıldı" }, "errorAssigningTargetCollection": { - "message": "Error assigning target collection." + "message": "Hedef koleksiyon atama hatası." }, "errorAssigningTargetFolder": { - "message": "Error assigning target folder." + "message": "Hedef klasör atama hatası." } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 9ee76520933..ebbf89738f9 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Згенеруйте псевдонім е-пошти зі стороннім сервісом пересилання." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ім'я вузла", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 0c0e6f6df73..4a6d3e960af 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index aad13e06ef1..bdd3e23ab44 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -1916,7 +1916,7 @@ "message": "无法完成生物识别。" }, "needADifferentMethod": { - "message": "使用其他方式?" + "message": "尝试其他方式吗?" }, "useMasterPassword": { "message": "使用主密码" @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "使用外部转发服务生成一个电子邮件别名。" }, + "forwarderError": { + "message": "$SERVICENAME$ 错误:$ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "网站:$WEBSITE$。由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "无效的 $SERVICENAME$ API 令牌", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "无效的 $SERVICENAME$ API 令牌:$ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "无效的 $SERVICENAME$ 域名。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "无效的 $SERVICENAME$ URL。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "发生未知的 $SERVICENAME$ 错误。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "未知的转发服务:$SERVICENAME$。", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主机名", "description": "Part of a URL." diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 5f768b0a43e..96f60bc3114 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -2132,6 +2132,108 @@ "forwardedEmailDesc": { "message": "使用外部轉寄服務產生一個電子郵件別名。" }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主機名稱", "description": "Part of a URL." diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index d11fceeacc9..63d6e062a1e 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -119,9 +119,6 @@ export class Main { this.logService = new ElectronLogMainService(null, app.getPath("userData")); const storageDefaults: any = {}; - // Default vault timeout to "on restart", and action to "lock" - storageDefaults["global.vaultTimeout"] = -1; - storageDefaults["global.vaultTimeoutAction"] = "lock"; this.storageService = new ElectronStorageService(app.getPath("userData"), storageDefaults); this.memoryStorageService = new MemoryStorageService(); this.memoryStorageForStateProviders = new MemoryStorageServiceForStateProviders(); diff --git a/apps/desktop/src/services/native-message-handler.service.ts b/apps/desktop/src/services/native-message-handler.service.ts index ebe1ee62484..c50593768d0 100644 --- a/apps/desktop/src/services/native-message-handler.service.ts +++ b/apps/desktop/src/services/native-message-handler.service.ts @@ -24,6 +24,7 @@ import { EncryptedMessageHandlerService } from "./encrypted-message-handler.serv const EncryptionAlgorithm = "sha1"; +// This service handles messages using the protocol created for the DuckDuckGo integration. @Injectable() export class NativeMessageHandlerService { private ddgSharedSecret: SymmetricCryptoKey; diff --git a/apps/desktop/src/services/native-messaging.service.ts b/apps/desktop/src/services/native-messaging.service.ts index 48bdc600476..9abd3b635ad 100644 --- a/apps/desktop/src/services/native-messaging.service.ts +++ b/apps/desktop/src/services/native-messaging.service.ts @@ -1,8 +1,10 @@ import { Injectable, NgZone } from "@angular/core"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; +import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; +import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoFunctionService } from "@bitwarden/common/platform/abstractions/crypto-function.service"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -43,6 +45,7 @@ export class NativeMessagingService { private nativeMessageHandler: NativeMessageHandlerService, private dialogService: DialogService, private accountService: AccountService, + private authService: AuthService, private ngZone: NgZone, ) {} @@ -53,6 +56,7 @@ export class NativeMessagingService { private async messageHandler(msg: LegacyMessageWrapper | Message) { const outerMessage = msg as Message; if (outerMessage.version) { + // If there is a version, it is a using the protocol created for the DuckDuckGo integration await this.nativeMessageHandler.handleMessage(outerMessage); return; } @@ -137,6 +141,19 @@ export class NativeMessagingService { return this.send({ command: "biometricUnlock", response: "not supported" }, appId); } + const userId = + (message.userId as UserId) ?? + (await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)))); + + if (userId == null) { + return this.send({ command: "biometricUnlock", response: "not unlocked" }, appId); + } + + const authStatus = await firstValueFrom(this.authService.authStatusFor$(userId)); + if (authStatus !== AuthenticationStatus.Unlocked) { + return this.send({ command: "biometricUnlock", response: "not unlocked" }, appId); + } + const biometricUnlockPromise = message.userId == null ? firstValueFrom(this.biometricStateService.biometricUnlockEnabled$) diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.ts b/apps/desktop/src/vault/app/vault/add-edit.component.ts index 86e0b881eef..d7fd3947953 100644 --- a/apps/desktop/src/vault/app/vault/add-edit.component.ts +++ b/apps/desktop/src/vault/app/vault/add-edit.component.ts @@ -7,13 +7,13 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @@ -36,7 +36,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnChanges, i18nService: I18nService, platformUtilsService: PlatformUtilsService, auditService: AuditService, - stateService: StateService, + accountService: AccountService, collectionService: CollectionService, messagingService: MessagingService, eventCollectionService: EventCollectionService, @@ -57,7 +57,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnChanges, i18nService, platformUtilsService, auditService, - stateService, + accountService, collectionService, messagingService, eventCollectionService, diff --git a/apps/web/src/app/admin-console/organizations/guards/is-paid-org.guard.ts b/apps/web/src/app/admin-console/organizations/guards/is-paid-org.guard.ts index f6968daca9f..aaf24e48346 100644 --- a/apps/web/src/app/admin-console/organizations/guards/is-paid-org.guard.ts +++ b/apps/web/src/app/admin-console/organizations/guards/is-paid-org.guard.ts @@ -27,15 +27,26 @@ export class IsPaidOrgGuard implements CanActivate { // Users without billing permission can't access billing if (!org.canEditSubscription) { await this.dialogService.openSimpleDialog({ - title: { key: "upgradeOrganization" }, - content: { key: "notAvailableForFreeOrganization" }, + title: { key: "upgradeOrganizationCloseSecurityGaps" }, + content: { key: "upgradeOrganizationCloseSecurityGapsDesc" }, acceptButtonText: { key: "ok" }, cancelButtonText: null, type: "info", }); return false; } else { - this.messagingService.send("upgradeOrganization", { organizationId: org.id }); + const upgradeConfirmed = await this.dialogService.openSimpleDialog({ + title: { key: "upgradeOrganizationCloseSecurityGaps" }, + content: { key: "upgradeOrganizationCloseSecurityGapsDesc" }, + acceptButtonText: { key: "upgradeOrganization" }, + type: "info", + icon: "bwi-arrow-circle-up", + }); + if (upgradeConfirmed) { + await this.router.navigate(["organizations", org.id, "billing", "subscription"], { + queryParams: { upgrade: true }, + }); + } } } diff --git a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html index 5fcf7b0f42d..df731c5cf16 100644 --- a/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html +++ b/apps/web/src/app/admin-console/organizations/manage/group-add-edit.component.html @@ -33,7 +33,7 @@

{{ "editGroupMembersDesc" | i18n }} - + {{ "restrictedGroupAccessDesc" | i18n }}

@@ -52,8 +52,8 @@

{{ "editGroupCollectionsDesc" | i18n }} - - {{ "editGroupCollectionsRestrictionsDesc" | i18n }} + + {{ "restrictedCollectionAssignmentDesc" | i18n }}

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 dff549ba6e7..a02c4a8da95 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 @@ -183,7 +183,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy { shareReplay({ refCount: true, bufferSize: 1 }), ); - allowAdminAccessToAllCollectionItems$ = combineLatest([ + protected allowAdminAccessToAllCollectionItems$ = combineLatest([ this.organization$, this.flexibleCollectionsV1Enabled$, ]).pipe( @@ -196,7 +196,16 @@ export class GroupAddEditComponent implements OnInit, OnDestroy { }), ); - restrictGroupAccess$ = combineLatest([ + protected canEditAnyCollection$ = combineLatest([ + this.organization$, + this.flexibleCollectionsV1Enabled$, + ]).pipe( + map(([org, flexibleCollectionsV1Enabled]) => + org.canEditAnyCollection(flexibleCollectionsV1Enabled), + ), + ); + + protected cannotAddSelfToGroup$ = combineLatest([ this.allowAdminAccessToAllCollectionItems$, this.groupDetails$, ]).pipe(map(([allowAdminAccess, groupDetails]) => !allowAdminAccess && groupDetails != null)); @@ -229,7 +238,7 @@ export class GroupAddEditComponent implements OnInit, OnDestroy { this.orgCollections$, this.orgMembers$, this.groupDetails$, - this.restrictGroupAccess$, + this.cannotAddSelfToGroup$, this.accountService.activeAccount$, this.organization$, this.flexibleCollectionsV1Enabled$, diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html index 7f539f098ba..0f420c6903b 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.html @@ -1,115 +1,99 @@ - +

+ + + + {{ "user" | i18n }} + {{ "fingerprint" | i18n }} + + + + + + + + + {{ user.email }} +

{{ user.name }}

+ + + {{ fingerprints.get(user.id) }} + + + + + + + + {{ user.email }} +

{{ user.name }}

+ + + {{ "bulkFilteredMessage" | i18n }} + + +
+
+ + + + + + {{ "user" | i18n }} + {{ "status" | i18n }} + + + + + + + + + {{ user.email }} +

{{ user.name }}

+ + + {{ statuses.get(user.id) }} + + + {{ "bulkFilteredMessage" | i18n }} + + +
+
+
+ + + + + + diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts index 1d268990173..d94edd55f85 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-confirm.component.ts @@ -1,4 +1,5 @@ -import { Component, Input, OnInit } from "@angular/core"; +import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; +import { Component, Inject, OnInit } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; @@ -8,16 +9,22 @@ import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.se import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; +import { DialogService } from "@bitwarden/components"; import { BulkUserDetails } from "./bulk-status.component"; +type BulkConfirmDialogData = { + organizationId: string; + users: BulkUserDetails[]; +}; + @Component({ selector: "app-bulk-confirm", templateUrl: "bulk-confirm.component.html", }) export class BulkConfirmComponent implements OnInit { - @Input() organizationId: string; - @Input() users: BulkUserDetails[]; + organizationId: string; + users: BulkUserDetails[]; excludedUsers: BulkUserDetails[]; filteredUsers: BulkUserDetails[]; @@ -30,11 +37,15 @@ export class BulkConfirmComponent implements OnInit { error: string; constructor( + @Inject(DIALOG_DATA) protected data: BulkConfirmDialogData, protected cryptoService: CryptoService, protected apiService: ApiService, private organizationUserService: OrganizationUserService, private i18nService: I18nService, - ) {} + ) { + this.organizationId = data.organizationId; + this.users = data.users; + } async ngOnInit() { this.excludedUsers = this.users.filter((u) => !this.isAccepted(u)); @@ -110,4 +121,8 @@ export class BulkConfirmComponent implements OnInit { request, ); } + + static open(dialogService: DialogService, config: DialogConfig) { + return dialogService.open(BulkConfirmComponent, config); + } } diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html index d2adef98ee3..3bcc749821a 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.html @@ -1,101 +1,88 @@ - + + + + + + + {{ user.email }} + {{ user.name }} + + + {{ statuses.get(user.id) }} + + + {{ "bulkFilteredMessage" | i18n }} + + + + + + + + + + + diff --git a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts index fdf499f0398..15a24eb25eb 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts +++ b/apps/web/src/app/admin-console/organizations/members/components/bulk/bulk-remove.component.ts @@ -1,30 +1,26 @@ -import { Component, Input } from "@angular/core"; +import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DialogService } from "@bitwarden/components"; import { BulkUserDetails } from "./bulk-status.component"; +type BulkRemoveDialogData = { + organizationId: string; + users: BulkUserDetails[]; +}; + @Component({ selector: "app-bulk-remove", templateUrl: "bulk-remove.component.html", }) export class BulkRemoveComponent { - @Input() organizationId: string; - @Input() set users(value: BulkUserDetails[]) { - this._users = value; - this.showNoMasterPasswordWarning = this._users.some( - (u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false, - ); - } - - get users(): BulkUserDetails[] { - return this._users; - } - - private _users: BulkUserDetails[]; + organizationId: string; + users: BulkUserDetails[]; statuses: Map = new Map(); @@ -34,12 +30,19 @@ export class BulkRemoveComponent { showNoMasterPasswordWarning = false; constructor( + @Inject(DIALOG_DATA) protected data: BulkRemoveDialogData, protected apiService: ApiService, protected i18nService: I18nService, private organizationUserService: OrganizationUserService, - ) {} + ) { + this.organizationId = data.organizationId; + this.users = data.users; + this.showNoMasterPasswordWarning = this.users.some( + (u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false, + ); + } - async submit() { + submit = async () => { this.loading = true; try { const response = await this.deleteUsers(); @@ -54,7 +57,7 @@ export class BulkRemoveComponent { } this.loading = false; - } + }; protected async deleteUsers() { return await this.organizationUserService.deleteManyOrganizationUsers( @@ -66,4 +69,8 @@ export class BulkRemoveComponent { protected get removeUsersWarning() { return this.i18nService.t("removeOrgUsersConfirmation"); } + + static open(dialogService: DialogService, config: DialogConfig) { + return dialogService.open(BulkRemoveComponent, config); + } } diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html index 4d81d070fb1..35e28b5239e 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/member-dialog.component.html @@ -14,7 +14,7 @@ title="{{ 'loading' | i18n }}" aria-hidden="true" > - {{ "loading" | i18n }} + {{ "loading" | i18n }} -

{{ "inviteUserDesc" | i18n }}

+

{{ "inviteUserDesc" | i18n }}

{{ "email" | i18n }} @@ -32,13 +32,11 @@ }}
-
- + + {{ "memberRole" | i18n }} - -
- - -
-
+ + {{ "user" | i18n }} + {{ "userDesc" | i18n }} + + - - -
-
- - -
-
- - -
-
- - -
-
+ + + -

+

{{ "permissions" | i18n }}

-
-
-
- +
+
+
+ {{ + "managerPermissions" | i18n + }}
-
-
- +
+
+ {{ "adminPermissions" | i18n }}
-
- - -
-
- - -
-
- - -
+ + + {{ "accessEventLogs" | i18n }} + + + + {{ "accessImportExport" | i18n }} + + + + {{ "accessReports" | i18n }} + -
+ + + {{ "manageGroups" | i18n }} + + + + {{ "manageSso" | i18n }} + + + + {{ "managePolicies" | i18n }} + + - -
-
- - -
-
- - -
-
- - -
-
+ {{ "manageUsers" | i18n }} + + - -
+ {{ "manageAccountRecovery" | i18n }} +
-
-
-
- - -
-
- - -
-
- - -
+
+
+ + + {{ "accessEventLogs" | i18n }} + + + + {{ "accessImportExport" | i18n }} + + + + {{ "accessReports" | i18n }} +
-
+
-
-
-
+
+
+ + + {{ "manageGroups" | i18n }} + + + + {{ "manageSso" | i18n }} + + + + {{ "managePolicies" | i18n }} + + - -
-
- - -
-
- - -
-
- - -
-
+ {{ "manageUsers" | i18n }} + + - -
+ {{ "manageAccountRecovery" | i18n }} +
-

+

{{ "secretsManager" | i18n }}
{{ - (restrictedAccess$ | async) + (restrictEditingSelf$ | async) ? ("restrictedGroupAccess" | i18n) : ("groupAccessUserDesc" | i18n) }} @@ -417,15 +271,18 @@ [selectorLabelText]="'selectGroups' | i18n" [emptySelectionText]="'noGroupsAdded' | i18n" [flexibleCollectionsEnabled]="organization.flexibleCollections" - [hideMultiSelect]="restrictedAccess$ | async" + [hideMultiSelect]="restrictEditingSelf$ | async" > -
- {{ "restrictedCollectionAccess" | i18n }} +
+ {{ "cannotAddYourselfToCollections" | i18n }}
-
- {{ "userPermissionOverrideHelper" | i18n }} +
+ {{ "userPermissionOverrideHelperDesc" | i18n }} + + {{ "restrictedCollectionAssignmentDesc" | i18n }} +
@@ -433,6 +290,7 @@ {{ "accessAllCollectionsDesc" | i18n }} 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 a67bea39c0a..8309d4d7253 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 @@ -105,7 +105,9 @@ export class MemberDialogComponent implements OnDestroy { groups: [[] as AccessItemValue[]], }); - protected restrictedAccess$: Observable; + protected allowAdminAccessToAllCollectionItems$: Observable; + protected restrictEditingSelf$: Observable; + protected canEditAnyCollection$: Observable; protected permissionsGroup = this.formBuilder.group({ manageAssignedCollectionsGroup: this.formBuilder.group>({ @@ -182,43 +184,59 @@ export class MemberDialogComponent implements OnDestroy { ? this.userService.get(this.params.organizationId, this.params.organizationUserId) : of(null); - // The orgUser cannot manage their own Group assignments if collection access is restricted - // TODO: fix disabled state of access-selector rows so that any controls are hidden - this.restrictedAccess$ = combineLatest([ + this.allowAdminAccessToAllCollectionItems$ = combineLatest([ this.organization$, - userDetails$, - this.accountService.activeAccount$, this.configService.getFeatureFlag$(FeatureFlag.FlexibleCollectionsV1), + ]).pipe( + map(([organization, flexibleCollectionsV1Enabled]) => { + if (!flexibleCollectionsV1Enabled || !organization.flexibleCollections) { + return true; + } + + return organization.allowAdminAccessToAllCollectionItems; + }), + ); + + // The orgUser cannot manage their own Group assignments if collection access is restricted + this.restrictEditingSelf$ = combineLatest([ + this.allowAdminAccessToAllCollectionItems$, + userDetails$, + this.accountService.activeAccount$, ]).pipe( map( - ([organization, userDetails, activeAccount, flexibleCollectionsV1Enabled]) => - // Feature flag conditionals - flexibleCollectionsV1Enabled && - organization.flexibleCollections && - // Business logic conditionals - userDetails != null && - userDetails.userId == activeAccount.id && - !organization.allowAdminAccessToAllCollectionItems, + ([allowAdminAccess, userDetails, activeAccount]) => + !allowAdminAccess && userDetails != null && userDetails.userId == activeAccount.id, ), shareReplay({ refCount: true, bufferSize: 1 }), ); - this.restrictedAccess$.pipe(takeUntil(this.destroy$)).subscribe((restrictedAccess) => { - if (restrictedAccess) { + this.restrictEditingSelf$.pipe(takeUntil(this.destroy$)).subscribe((restrictEditingSelf) => { + if (restrictEditingSelf) { this.formGroup.controls.groups.disable(); } else { this.formGroup.controls.groups.enable(); } }); + const flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$( + FeatureFlag.FlexibleCollectionsV1, + ); + + this.canEditAnyCollection$ = combineLatest([ + this.organization$, + flexibleCollectionsV1Enabled$, + ]).pipe( + map(([org, flexibleCollectionsV1Enabled]) => + org.canEditAnyCollection(flexibleCollectionsV1Enabled), + ), + ); + combineLatest({ organization: this.organization$, collections: this.collectionAdminService.getAll(this.params.organizationId), userDetails: userDetails$, groups: groups$, - flexibleCollectionsV1Enabled: this.configService.getFeatureFlag$( - FeatureFlag.FlexibleCollectionsV1, - ), + flexibleCollectionsV1Enabled: flexibleCollectionsV1Enabled$, }) .pipe(takeUntil(this.destroy$)) .subscribe( @@ -454,7 +472,7 @@ export class MemberDialogComponent implements OnDestroy { .filter((v) => v.type === AccessItemType.Collection) .map(convertToSelectionView); - userView.groups = (await firstValueFrom(this.restrictedAccess$)) + userView.groups = (await firstValueFrom(this.restrictEditingSelf$)) ? null : this.formGroup.value.groups.map((m) => m.id); diff --git a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/nested-checkbox.component.html b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/nested-checkbox.component.html index 665e7fd9573..537a5f8759b 100644 --- a/apps/web/src/app/admin-console/organizations/members/components/member-dialog/nested-checkbox.component.html +++ b/apps/web/src/app/admin-console/organizations/members/components/member-dialog/nested-checkbox.component.html @@ -1,28 +1,20 @@
- - -
+ + + {{ parentId | i18n }} + +
-
- - +
+ + + {{ c.key | i18n }} +
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 af04d83c34d..d776ac1e5df 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 @@ -481,16 +481,13 @@ export class PeopleComponent extends BasePeopleComponent { return; } - const [modal] = await this.modalService.openViewRef( - BulkRemoveComponent, - this.bulkRemoveModalRef, - (comp) => { - comp.organizationId = this.organization.id; - comp.users = this.getCheckedUsers(); + const dialogRef = BulkRemoveComponent.open(this.dialogService, { + data: { + organizationId: this.organization.id, + users: this.getCheckedUsers(), }, - ); - - await modal.onClosedPromise(); + }); + await lastValueFrom(dialogRef.closed); await this.load(); } @@ -558,16 +555,14 @@ export class PeopleComponent extends BasePeopleComponent { return; } - const [modal] = await this.modalService.openViewRef( - BulkConfirmComponent, - this.bulkConfirmModalRef, - (comp) => { - comp.organizationId = this.organization.id; - comp.users = this.getCheckedUsers(); + const dialogRef = BulkConfirmComponent.open(this.dialogService, { + data: { + organizationId: this.organization.id, + users: this.getCheckedUsers(), }, - ); + }); - await modal.onClosedPromise(); + await lastValueFrom(dialogRef.closed); await this.load(); } diff --git a/apps/web/src/app/admin-console/organizations/policies/disable-send.component.html b/apps/web/src/app/admin-console/organizations/policies/disable-send.component.html index d30ee4997a9..0e50c5838ee 100644 --- a/apps/web/src/app/admin-console/organizations/policies/disable-send.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/disable-send.component.html @@ -2,15 +2,7 @@ {{ "disableSendExemption" | i18n }} -
-
- - -
-
+ + + {{ "turnOn" | i18n }} + diff --git a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.html b/apps/web/src/app/admin-console/organizations/policies/password-generator.component.html index 350f7da7b4b..80df5fa2e6a 100644 --- a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/password-generator.component.html @@ -1,144 +1,64 @@
-
-
- - -
+ + + {{ "turnOn" | i18n }} + + +
+ + {{ "defaultType" | i18n }} + + + +
-
-
- - -
+

{{ "password" | i18n }}

+
+ + {{ "minLength" | i18n }} + +
-

{{ "password" | i18n }}

-
-
- - -
+
+ + {{ "minNumbers" | i18n }} + + + + {{ "minSpecial" | i18n }} + +
-
-
- - -
-
- - -
-
-
- - -
-
- - -
-
- - -
-
- - -
-

{{ "passphrase" | i18n }}

-
-
- - -
-
-
- - -
-
- - + + + A-Z + + + + a-z + + + + 0-9 + + + + !@#$%^&* + +

{{ "passphrase" | i18n }}

+
+ + {{ "minimumNumberOfWords" | i18n }} + +
+ + + {{ "capitalize" | i18n }} + + + + {{ "includeNumber" | i18n }} +
diff --git a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts b/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts index 464586d6855..93124c42fa6 100644 --- a/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts +++ b/apps/web/src/app/admin-console/organizations/policies/password-generator.component.ts @@ -1,5 +1,5 @@ import { Component } from "@angular/core"; -import { UntypedFormBuilder } from "@angular/forms"; +import { UntypedFormBuilder, Validators } from "@angular/forms"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -20,14 +20,14 @@ export class PasswordGeneratorPolicy extends BasePolicy { export class PasswordGeneratorPolicyComponent extends BasePolicyComponent { data = this.formBuilder.group({ defaultType: [null], - minLength: [null], + minLength: [null, [Validators.min(5), Validators.max(128)]], useUpper: [null], useLower: [null], useNumbers: [null], useSpecial: [null], - minNumbers: [null], - minSpecial: [null], - minNumberWords: [null], + minNumbers: [null, [Validators.min(0), Validators.max(9)]], + minSpecial: [null, [Validators.min(0), Validators.max(9)]], + minNumberWords: [null, [Validators.min(3), Validators.max(20)]], capitalize: [null], includeNumber: [null], }); diff --git a/apps/web/src/app/admin-console/organizations/policies/policies.component.html b/apps/web/src/app/admin-console/organizations/policies/policies.component.html index d4533b59b16..8f1e925034f 100644 --- a/apps/web/src/app/admin-console/organizations/policies/policies.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/policies.component.html @@ -3,24 +3,24 @@ - {{ "loading" | i18n }} + {{ "loading" | i18n }} - - - - + - -
- {{ p.name | i18n }} + + +
+ {{ "on" | i18n }} - {{ p.description | i18n }} + {{ p.description | i18n }}
+ +
diff --git a/apps/web/src/app/admin-console/organizations/policies/require-sso.component.html b/apps/web/src/app/admin-console/organizations/policies/require-sso.component.html index 095b12ff366..0056f654d01 100644 --- a/apps/web/src/app/admin-console/organizations/policies/require-sso.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/require-sso.component.html @@ -5,15 +5,7 @@ {{ "requireSsoExemption" | i18n }} -
-
- - -
-
+ + + {{ "turnOn" | i18n }} + diff --git a/apps/web/src/app/admin-console/organizations/policies/send-options.component.html b/apps/web/src/app/admin-console/organizations/policies/send-options.component.html index c2e5ae8a34c..7bf34ef3a69 100644 --- a/apps/web/src/app/admin-console/organizations/policies/send-options.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/send-options.component.html @@ -2,29 +2,15 @@ {{ "sendOptionsExemption" | i18n }} -
-
- - -
-
+ + + {{ "turnOn" | i18n }} +
-

{{ "options" | i18n }}

-
- - -
+

{{ "options" | i18n }}

+ + + {{ "disableHideEmail" | i18n }} +
diff --git a/apps/web/src/app/admin-console/organizations/policies/single-org.component.html b/apps/web/src/app/admin-console/organizations/policies/single-org.component.html index a270adcfc00..aaf6888eddb 100644 --- a/apps/web/src/app/admin-console/organizations/policies/single-org.component.html +++ b/apps/web/src/app/admin-console/organizations/policies/single-org.component.html @@ -2,15 +2,7 @@ {{ "singleOrgPolicyWarning" | i18n }} -
-
- - -
-
+ + + {{ "turnOn" | i18n }} + diff --git a/apps/web/src/app/admin-console/organizations/settings/account.component.html b/apps/web/src/app/admin-console/organizations/settings/account.component.html index 082fe7eb80b..d8cd5fddfe9 100644 --- a/apps/web/src/app/admin-console/organizations/settings/account.component.html +++ b/apps/web/src/app/admin-console/organizations/settings/account.component.html @@ -104,12 +104,11 @@ - - 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 d8091e46aef..5ff8d00eab4 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 @@ -28,8 +28,6 @@ import { DeleteOrganizationDialogResult, openDeleteOrganizationDialog } from "./ templateUrl: "account.component.html", }) export class AccountComponent { - @ViewChild("purgeOrganizationTemplate", { read: ViewContainerRef, static: true }) - purgeModalRef: ViewContainerRef; @ViewChild("apiKeyTemplate", { read: ViewContainerRef, static: true }) apiKeyModalRef: ViewContainerRef; @ViewChild("rotateApiKeyTemplate", { read: ViewContainerRef, static: true }) @@ -232,11 +230,14 @@ export class AccountComponent { } } - async purgeVault() { - await this.modalService.openViewRef(PurgeVaultComponent, this.purgeModalRef, (comp) => { - comp.organizationId = this.organizationId; + purgeVault = async () => { + const dialogRef = PurgeVaultComponent.open(this.dialogService, { + data: { + organizationId: this.organizationId, + }, }); - } + await lastValueFrom(dialogRef.closed); + }; async viewApiKey() { await this.modalService.openViewRef(ApiKeyComponent, this.apiKeyModalRef, (comp) => { diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts index 7a2a67b69c9..e3d19f5487c 100644 --- a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts +++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts @@ -5,7 +5,6 @@ import { ActivatedRoute } from "@angular/router"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -30,7 +29,6 @@ export class OrganizationVaultExportComponent extends ExportComponent { private route: ActivatedRoute, policyService: PolicyService, logService: LogService, - userVerificationService: UserVerificationService, formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, @@ -43,7 +41,6 @@ export class OrganizationVaultExportComponent extends ExportComponent { eventCollectionService, policyService, logService, - userVerificationService, formBuilder, fileDownloadService, dialogService, diff --git a/apps/web/src/app/admin-console/settings/sponsored-families.component.ts b/apps/web/src/app/admin-console/settings/sponsored-families.component.ts index 562192a262a..3477b9a4256 100644 --- a/apps/web/src/app/admin-console/settings/sponsored-families.component.ts +++ b/apps/web/src/app/admin-console/settings/sponsored-families.component.ts @@ -1,15 +1,15 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { FormBuilder, FormControl, FormGroup, Validators } from "@angular/forms"; -import { map, Observable, Subject, takeUntil } from "rxjs"; +import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; import { notAllowedValueAsync } from "@bitwarden/angular/admin-console/validators/not-allowed-value-async.validator"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { PlanSponsorshipType } from "@bitwarden/common/billing/enums/"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; interface RequestSponsorshipForm { @@ -43,7 +43,7 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy { private syncService: SyncService, private organizationService: OrganizationService, private formBuilder: FormBuilder, - private stateService: StateService, + private accountService: AccountService, ) { this.sponsorshipForm = this.formBuilder.group({ selectedSponsorshipOrgId: new FormControl("", { @@ -52,7 +52,10 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy { sponsorshipEmail: new FormControl("", { validators: [Validators.email], asyncValidators: [ - notAllowedValueAsync(async () => await this.stateService.getEmail(), true), + notAllowedValueAsync( + () => firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.email))), + true, + ), ], updateOn: "blur", }), diff --git a/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.html b/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.html index 4be0f8d94ca..b07cbbfad12 100644 --- a/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.html +++ b/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.html @@ -1,50 +1,36 @@ - + {{ sponsoringOrg.familySponsorshipFriendlyName }} -{{ sponsoringOrg.name }} - +{{ sponsoringOrg.name }} + {{ statusMessage }} - - + + diff --git a/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.ts b/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.ts index 0ef8850ac96..eff75b61b39 100644 --- a/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.ts +++ b/apps/web/src/app/admin-console/settings/sponsoring-org-row.component.ts @@ -20,10 +20,7 @@ export class SponsoringOrgRowComponent implements OnInit { @Output() sponsorshipRemoved = new EventEmitter(); statusMessage = "loading"; - statusClass: "text-success" | "text-danger" = "text-success"; - - revokeSponsorshipPromise: Promise; - resendEmailPromise: Promise; + statusClass: "tw-text-success" | "tw-text-danger" = "tw-text-success"; private locale = ""; @@ -48,20 +45,15 @@ export class SponsoringOrgRowComponent implements OnInit { async revokeSponsorship() { try { - this.revokeSponsorshipPromise = this.doRevokeSponsorship(); - await this.revokeSponsorshipPromise; + await this.doRevokeSponsorship(); } catch (e) { this.logService.error(e); } - - this.revokeSponsorshipPromise = null; } async resendEmail() { - this.resendEmailPromise = this.apiService.postResendSponsorshipOffer(this.sponsoringOrg.id); - await this.resendEmailPromise; + await this.apiService.postResendSponsorshipOffer(this.sponsoringOrg.id); this.platformUtilsService.showToast("success", null, this.i18nService.t("emailSent")); - this.resendEmailPromise = null; } get isSentAwaitingSync() { @@ -106,31 +98,31 @@ export class SponsoringOrgRowComponent implements OnInit { "revokeWhenExpired", formatDate(validUntil, "MM/dd/yyyy", this.locale), ); - this.statusClass = "text-danger"; + this.statusClass = "tw-text-danger"; } else if (toDelete) { // They want to delete and we don't have a valid until date so we can // this should only happen on a self-hosted install this.statusMessage = this.i18nService.t("requestRemoved"); - this.statusClass = "text-danger"; + this.statusClass = "tw-text-danger"; } else if (validUntil) { // They don't want to delete and they have a valid until date // that means they are actively sponsoring someone this.statusMessage = this.i18nService.t("active"); - this.statusClass = "text-success"; + this.statusClass = "tw-text-success"; } else if (selfHosted && lastSyncDate) { // We are on a self-hosted install and it has been synced but we have not gotten // a valid until date so we can't know if they are actively sponsoring someone this.statusMessage = this.i18nService.t("sent"); - this.statusClass = "text-success"; + this.statusClass = "tw-text-success"; } else if (!selfHosted) { // We are in cloud and all other status checks have been false therefore we have // sent the request but it hasn't been accepted yet this.statusMessage = this.i18nService.t("sent"); - this.statusClass = "text-success"; + this.statusClass = "tw-text-success"; } else { // We are on a self-hosted install and we have not synced yet this.statusMessage = this.i18nService.t("requested"); - this.statusClass = "text-success"; + this.statusClass = "tw-text-success"; } } } 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 2763de71b37..4b8d6ca1392 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 @@ -1,5 +1,5 @@ import { Injectable } from "@angular/core"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; @@ -52,7 +52,7 @@ export class UserKeyRotationService { // Create master key to validate the master password const masterKey = await this.cryptoService.makeMasterKey( masterPassword, - await this.stateService.getEmail(), + await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.email))), await this.kdfConfigService.getKdfConfig(), ); diff --git a/apps/web/src/app/auth/settings/account/account.component.html b/apps/web/src/app/auth/settings/account/account.component.html index deb2f0ef301..a5210611941 100644 --- a/apps/web/src/app/auth/settings/account/account.component.html +++ b/apps/web/src/app/auth/settings/account/account.component.html @@ -12,7 +12,7 @@ -
- + diff --git a/apps/web/src/app/auth/settings/account/profile.component.ts b/apps/web/src/app/auth/settings/account/profile.component.ts index 1b7d7f378a1..64c5687c0b8 100644 --- a/apps/web/src/app/auth/settings/account/profile.component.ts +++ b/apps/web/src/app/auth/settings/account/profile.component.ts @@ -1,4 +1,5 @@ import { ViewChild, ViewContainerRef, Component, OnDestroy, OnInit } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; import { Subject, takeUntil } from "rxjs"; import { ModalService } from "@bitwarden/angular/services/modal.service"; @@ -6,7 +7,6 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/update-profile.request"; import { ProfileResponse } from "@bitwarden/common/models/response/profile.response"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @@ -21,16 +21,19 @@ export class ProfileComponent implements OnInit, OnDestroy { profile: ProfileResponse; fingerprintMaterial: string; - formPromise: Promise; @ViewChild("avatarModalTemplate", { read: ViewContainerRef, static: true }) avatarModalRef: ViewContainerRef; private destroy$ = new Subject(); + protected formGroup = new FormGroup({ + name: new FormControl(null), + email: new FormControl(null), + }); + constructor( private apiService: ApiService, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, - private logService: LogService, private stateService: StateService, private modalService: ModalService, ) {} @@ -39,6 +42,15 @@ export class ProfileComponent implements OnInit, OnDestroy { this.profile = await this.apiService.getProfile(); this.loading = false; this.fingerprintMaterial = await this.stateService.getUserId(); + this.formGroup.get("name").setValue(this.profile.name); + this.formGroup.get("email").setValue(this.profile.email); + + this.formGroup + .get("name") + .valueChanges.pipe(takeUntil(this.destroy$)) + .subscribe((name) => { + this.profile.name = name; + }); } async ngOnDestroy() { @@ -46,7 +58,7 @@ export class ProfileComponent implements OnInit, OnDestroy { this.destroy$.complete(); } - async openChangeAvatar() { + openChangeAvatar = async () => { const modalOpened = await this.modalService.openViewRef( ChangeAvatarComponent, this.avatarModalRef, @@ -57,16 +69,14 @@ export class ProfileComponent implements OnInit, OnDestroy { }); }, ); - } + }; - async submit() { - try { - const request = new UpdateProfileRequest(this.profile.name, this.profile.masterPasswordHint); - this.formPromise = this.apiService.putProfile(request); - await this.formPromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("accountUpdated")); - } catch (e) { - this.logService.error(e); - } - } + submit = async () => { + const request = new UpdateProfileRequest( + this.formGroup.get("name").value, + this.profile.masterPasswordHint, + ); + await this.apiService.putProfile(request); + this.platformUtilsService.showToast("success", null, this.i18nService.t("accountUpdated")); + }; } 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 39d0af30ef1..8c52e71bdd2 100644 --- a/apps/web/src/app/auth/settings/change-password.component.ts +++ b/apps/web/src/app/auth/settings/change-password.component.ts @@ -1,10 +1,12 @@ import { Component } from "@angular/core"; import { Router } from "@angular/router"; +import { firstValueFrom, map } from "rxjs"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "@bitwarden/angular/auth/components/change-password.component"; 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 { 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -52,6 +54,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { private keyRotationService: UserKeyRotationService, kdfConfigService: KdfConfigService, masterPasswordService: InternalMasterPasswordServiceAbstraction, + accountService: AccountService, ) { super( i18nService, @@ -64,6 +67,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { dialogService, kdfConfigService, masterPasswordService, + accountService, ); } @@ -170,7 +174,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { ) { const masterKey = await this.cryptoService.makeMasterKey( this.currentMasterPassword, - await this.stateService.getEmail(), + await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.email))), await this.kdfConfigService.getKdfConfig(), ); 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 5755156bf96..6115b4bac1a 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 { 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 { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; @@ -62,6 +63,7 @@ export class EmergencyAccessTakeoverComponent private dialogRef: DialogRef, kdfConfigService: KdfConfigService, masterPasswordService: InternalMasterPasswordServiceAbstraction, + accountService: AccountService, ) { super( i18nService, @@ -74,6 +76,7 @@ export class EmergencyAccessTakeoverComponent dialogService, kdfConfigService, masterPasswordService, + accountService, ); } diff --git a/apps/web/src/app/auth/settings/emergency-access/view/emergency-add-edit-cipher.component.ts b/apps/web/src/app/auth/settings/emergency-access/view/emergency-add-edit-cipher.component.ts index 9312ce5fc03..1e070d42ab2 100644 --- a/apps/web/src/app/auth/settings/emergency-access/view/emergency-add-edit-cipher.component.ts +++ b/apps/web/src/app/auth/settings/emergency-access/view/emergency-add-edit-cipher.component.ts @@ -5,13 +5,13 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password/"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -39,7 +39,7 @@ export class EmergencyAddEditCipherComponent extends BaseAddEditComponent { i18nService: I18nService, platformUtilsService: PlatformUtilsService, auditService: AuditService, - stateService: StateService, + accountService: AccountService, collectionService: CollectionService, totpService: TotpService, passwordGenerationService: PasswordGenerationServiceAbstraction, @@ -61,7 +61,7 @@ export class EmergencyAddEditCipherComponent extends BaseAddEditComponent { i18nService, platformUtilsService, auditService, - stateService, + accountService, collectionService, totpService, passwordGenerationService, 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 985fb3e038a..1424310a335 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 @@ -1,8 +1,10 @@ import { DIALOG_DATA } from "@angular/cdk/dialog"; import { Component, Inject } from "@angular/core"; import { FormGroup, FormControl, Validators } from "@angular/forms"; +import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.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"; @@ -11,7 +13,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { KdfType } from "@bitwarden/common/platform/enums"; @Component({ @@ -35,7 +36,7 @@ export class ChangeKdfConfirmationComponent { private platformUtilsService: PlatformUtilsService, private cryptoService: CryptoService, private messagingService: MessagingService, - private stateService: StateService, + private accountService: AccountService, private logService: LogService, private kdfConfigService: KdfConfigService, @Inject(DIALOG_DATA) params: { kdfConfig: KdfConfig }, @@ -78,7 +79,9 @@ export class ChangeKdfConfirmationComponent { } const masterKey = await this.cryptoService.getOrDeriveMasterKey(masterPassword); request.masterPasswordHash = await this.cryptoService.hashMasterKey(masterPassword, masterKey); - const email = await this.stateService.getEmail(); + const email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); const newMasterKey = await this.cryptoService.makeMasterKey( masterPassword, diff --git a/apps/web/src/app/auth/settings/security/security-keys.component.html b/apps/web/src/app/auth/settings/security/security-keys.component.html index 1ffc1607e7d..acfe4319c95 100644 --- a/apps/web/src/app/auth/settings/security/security-keys.component.html +++ b/apps/web/src/app/auth/settings/security/security-keys.component.html @@ -1,11 +1,11 @@
-

{{ "apiKey" | i18n }}

+

{{ "apiKey" | i18n }}

-

+

{{ "userApiKeyDesc" | i18n }}

-
-
+ + {{ "verifyEmailDesc" | i18n }} + + diff --git a/apps/web/src/app/auth/settings/verify-email.component.ts b/apps/web/src/app/auth/settings/verify-email.component.ts index d9d2acb87b7..e8809cd8931 100644 --- a/apps/web/src/app/auth/settings/verify-email.component.ts +++ b/apps/web/src/app/auth/settings/verify-email.component.ts @@ -1,25 +1,29 @@ +import { CommonModule } from "@angular/common"; import { Component, EventEmitter, Output } from "@angular/core"; +import { JslibModule } from "@bitwarden/angular/jslib.module"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { AsyncActionsModule, BannerModule, ButtonModule, LinkModule } from "@bitwarden/components"; @Component({ + standalone: true, selector: "app-verify-email", templateUrl: "verify-email.component.html", + imports: [AsyncActionsModule, BannerModule, ButtonModule, CommonModule, JslibModule, LinkModule], }) export class VerifyEmailComponent { actionPromise: Promise; @Output() onVerified = new EventEmitter(); + @Output() onDismiss = new EventEmitter(); constructor( private apiService: ApiService, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, - private logService: LogService, private tokenService: TokenService, ) {} diff --git a/apps/web/src/app/auth/update-password.component.ts b/apps/web/src/app/auth/update-password.component.ts index 403d31be437..b8cfb47db1a 100644 --- a/apps/web/src/app/auth/update-password.component.ts +++ b/apps/web/src/app/auth/update-password.component.ts @@ -4,6 +4,7 @@ import { Router } from "@angular/router"; import { UpdatePasswordComponent as BaseUpdatePasswordComponent } from "@bitwarden/angular/auth/components/update-password.component"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; 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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -36,6 +37,7 @@ export class UpdatePasswordComponent extends BaseUpdatePasswordComponent { dialogService: DialogService, kdfConfigService: KdfConfigService, masterPasswordService: InternalMasterPasswordServiceAbstraction, + accountService: AccountService, ) { super( router, @@ -52,6 +54,7 @@ export class UpdatePasswordComponent extends BaseUpdatePasswordComponent { dialogService, kdfConfigService, masterPasswordService, + accountService, ); } } diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.html b/apps/web/src/app/billing/organizations/organization-plans.component.html index 3c8ef2c9337..1bd6b99dd17 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.html +++ b/apps/web/src/app/billing/organizations/organization-plans.component.html @@ -51,8 +51,8 @@

{{ "chooseYourPlan" | i18n }}

-
- + +
{{ selectableProduct.nameLocalizationKey | i18n }}
  • {{ "includeAllTeamsStarterFeatures" | i18n }}
  • @@ -144,7 +147,7 @@ - + @@ -173,6 +176,7 @@ !selectableProduct.PasswordManager.basePrice && selectableProduct.PasswordManager.hasAdditionalSeatsOption " + class="tw-pl-4" > {{ "costPerUser" @@ -185,11 +189,11 @@ }} /{{ "month" | i18n }} - {{ + {{ "freeForever" | i18n }} - -
+
+
- +

{{ "summary" | i18n }}

- - {{ (selectablePlan.isAnnual ? "annually" : "monthly") | i18n }} - -

- {{ "basePrice" | i18n }}: - {{ - (selectablePlan.isAnnual - ? selectablePlan.PasswordManager.basePrice / 12 - : selectablePlan.PasswordManager.basePrice - ) | currency: "$" - }} - × 12 - {{ "monthAbbr" | i18n }} - = - - {{ - selectablePlan.PasswordManager.basePrice | currency: "$" - }} - {{ "freeWithSponsorship" | i18n }} - - - {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} +

+ + {{ (selectablePlan.isAnnual ? "annually" : "monthly") | i18n }} + +

+ {{ "basePrice" | i18n }}: + {{ + (selectablePlan.isAnnual + ? selectablePlan.PasswordManager.basePrice / 12 + : selectablePlan.PasswordManager.basePrice + ) | currency: "$" + }} + × 12 + {{ "monthAbbr" | i18n }} + = + + {{ + selectablePlan.PasswordManager.basePrice | currency: "$" + }} + {{ "freeWithSponsorship" | i18n }} + + + {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} + /{{ "year" | i18n }} + +

+

+ {{ "additionalUsers" | i18n }}: + {{ "users" | i18n }}: + {{ formGroup.controls["additionalSeats"].value || 0 }} × + {{ + (selectablePlan.isAnnual + ? selectablePlan.PasswordManager.seatPrice / 12 + : selectablePlan.PasswordManager.seatPrice + ) | currency: "$" + }} + × 12 {{ "monthAbbr" | i18n }} = + {{ + passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats) + | currency: "$" + }} /{{ "year" | i18n }} - -

-

- {{ "additionalUsers" | i18n }}: +

- {{ "users" | i18n }}: - {{ formGroup.controls["additionalSeats"].value || 0 }} × - {{ - (selectablePlan.isAnnual - ? selectablePlan.PasswordManager.seatPrice / 12 - : selectablePlan.PasswordManager.seatPrice - ) | currency: "$" - }} - × 12 {{ "monthAbbr" | i18n }} = - {{ - passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats) - | currency: "$" - }} - /{{ "year" | i18n }} -

-

- {{ "additionalStorageGb" | i18n }}: - {{ formGroup.controls["additionalStorage"].value || 0 }} × - {{ - (selectablePlan.isAnnual - ? selectablePlan.PasswordManager.additionalStoragePricePerGb / 12 - : selectablePlan.PasswordManager.additionalStoragePricePerGb - ) | currency: "$" - }} - × 12 {{ "monthAbbr" | i18n }} = - {{ additionalStorageTotal(selectablePlan) | currency: "$" }} /{{ "year" | i18n }} -

-
- -

- {{ "basePrice" | i18n }}: - {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} - {{ "monthAbbr" | i18n }} - = - {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} - /{{ "month" | i18n }} -

-

- {{ "additionalUsers" | i18n }}: + + +

- {{ "users" | i18n }}: - {{ formGroup.controls["additionalSeats"].value || 0 }} × - {{ selectablePlan.PasswordManager.seatPrice | currency: "$" }} - {{ "monthAbbr" | i18n }} = - {{ - passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats) - | currency: "$" - }} - /{{ "month" | i18n }} -

-

- {{ "additionalStorageGb" | i18n }}: - {{ formGroup.controls["additionalStorage"].value || 0 }} × - {{ selectablePlan.PasswordManager.additionalStoragePricePerGb | currency: "$" }} - {{ "monthAbbr" | i18n }} = - {{ additionalStorageTotal(selectablePlan) | currency: "$" }} /{{ "month" | i18n }} -

-
-
+ {{ "basePrice" | i18n }}: + {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} + {{ "monthAbbr" | i18n }} + = + {{ selectablePlan.PasswordManager.basePrice | currency: "$" }} + /{{ "month" | i18n }} +

+

+ {{ "additionalUsers" | i18n }}: + {{ "users" | i18n }}: + {{ formGroup.controls["additionalSeats"].value || 0 }} × + {{ selectablePlan.PasswordManager.seatPrice | currency: "$" }} + {{ "monthAbbr" | i18n }} = + {{ + passwordManagerSeatTotal(selectablePlan, formGroup.value.additionalSeats) + | currency: "$" + }} + /{{ "month" | i18n }} +

+

+ {{ "additionalStorageGb" | i18n }}: + {{ formGroup.controls["additionalStorage"].value || 0 }} × + {{ selectablePlan.PasswordManager.additionalStoragePricePerGb | currency: "$" }} + {{ "monthAbbr" | i18n }} = + {{ additionalStorageTotal(selectablePlan) | currency: "$" }} /{{ "month" | i18n }} +

+ + +
diff --git a/apps/web/src/app/billing/organizations/organization-plans.component.ts b/apps/web/src/app/billing/organizations/organization-plans.component.ts index 41af702ba0f..2228ad9f3ad 100644 --- a/apps/web/src/app/billing/organizations/organization-plans.component.ts +++ b/apps/web/src/app/billing/organizations/organization-plans.component.ts @@ -438,6 +438,10 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { return this.selectedSecretsManagerPlan != null; } + get teamsStarterPlanIsAvailable() { + return this.selectablePlans.some((plan) => plan.type === PlanType.TeamsStarter); + } + changedProduct() { const selectedPlan = this.selectablePlans[0]; @@ -511,8 +515,13 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { if (!this.formGroup.controls.businessOwned.value || this.selectedPlan.canBeUsedByBusiness) { return; } - this.formGroup.controls.product.setValue(ProductType.TeamsStarter); - this.formGroup.controls.plan.setValue(PlanType.TeamsStarter); + if (this.teamsStarterPlanIsAvailable) { + this.formGroup.controls.product.setValue(ProductType.TeamsStarter); + this.formGroup.controls.plan.setValue(PlanType.TeamsStarter); + } else { + this.formGroup.controls.product.setValue(ProductType.Teams); + this.formGroup.controls.plan.setValue(PlanType.TeamsAnnually); + } this.changedProduct(); } @@ -763,11 +772,20 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy { } if (this.currentPlan && this.currentPlan.product !== ProductType.Enterprise) { - const upgradedPlan = this.passwordManagerPlans.find((plan) => - this.currentPlan.product === ProductType.Free - ? plan.type === PlanType.FamiliesAnnually - : plan.upgradeSortOrder == this.currentPlan.upgradeSortOrder + 1, - ); + const upgradedPlan = this.passwordManagerPlans.find((plan) => { + if (this.currentPlan.product === ProductType.Free) { + return plan.type === PlanType.FamiliesAnnually; + } + + if ( + this.currentPlan.product === ProductType.Families && + !this.teamsStarterPlanIsAvailable + ) { + return plan.type === PlanType.TeamsAnnually; + } + + return plan.upgradeSortOrder === this.currentPlan.upgradeSortOrder + 1; + }); this.plan = upgradedPlan.type; this.product = upgradedPlan.product; diff --git a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.html b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.html index 5a71e353d73..25ac3a7a155 100644 --- a/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.html +++ b/apps/web/src/app/billing/organizations/organization-subscription-cloud.component.html @@ -142,10 +142,22 @@

{{ "manageSubscription" | i18n }}

+

+ {{ "smStandaloneTrialSeatCountUpdateMessageFragment1" | i18n }} + {{ "passwordManager" | i18n }} + {{ "smStandaloneTrialSeatCountUpdateMessageFragment2" | i18n }} + {{ "contactSupportShort" | i18n }}. + +

{{ subscriptionDesc }}

{{ "passwordManager" | i18n }}

@@ -168,32 +180,36 @@ > {{ "removeSponsorship" | i18n }} -

{{ "storage" | i18n }}

-

- {{ "subscriptionStorage" | i18n: sub.maxStorageGb || 0 : sub.storageName || "0 MB" }} -

- - -
-
- - + +

{{ "storage" | i18n }}

+

+ {{ "subscriptionStorage" | i18n: sub.maxStorageGb || 0 : sub.storageName || "0 MB" }} +

+ + +
+
+ + +
-
+

{{ "secretsManager" | i18n }}

diff --git a/apps/web/src/app/billing/shared/add-credit-dialog.component.html b/apps/web/src/app/billing/shared/add-credit-dialog.component.html new file mode 100644 index 00000000000..790099df882 --- /dev/null +++ b/apps/web/src/app/billing/shared/add-credit-dialog.component.html @@ -0,0 +1,61 @@ +
+ + +

{{ "creditDelayed" | i18n }}

+
+ + + PayPal + + + Bitcoin + + +
+
+ + {{ "amount" | i18n }} + + $USD + +
+
+ + + + +
+
+
+ + + + + + + + + + + + + + + +
diff --git a/apps/web/src/app/billing/shared/add-credit.component.ts b/apps/web/src/app/billing/shared/add-credit-dialog.component.ts similarity index 58% rename from apps/web/src/app/billing/shared/add-credit.component.ts rename to apps/web/src/app/billing/shared/add-credit-dialog.component.ts index 71050a9a6e1..68f074076d7 100644 --- a/apps/web/src/app/billing/shared/add-credit.component.ts +++ b/apps/web/src/app/billing/shared/add-credit-dialog.component.ts @@ -1,22 +1,26 @@ -import { - Component, - ElementRef, - EventEmitter, - Input, - OnInit, - Output, - ViewChild, -} from "@angular/core"; -import { firstValueFrom } from "rxjs"; +import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; +import { Component, ElementRef, Inject, OnInit, ViewChild } from "@angular/core"; +import { FormControl, FormGroup, Validators } from "@angular/forms"; +import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { BitPayInvoiceRequest } from "@bitwarden/common/billing/models/request/bit-pay-invoice.request"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { DialogService } from "@bitwarden/components"; + +export interface AddCreditDialogData { + organizationId: string; +} + +export enum AddCreditDialogResult { + Added = "added", + Cancelled = "cancelled", +} export type PayPalConfig = { businessId?: string; @@ -24,17 +28,9 @@ export type PayPalConfig = { }; @Component({ - selector: "app-add-credit", - templateUrl: "add-credit.component.html", + templateUrl: "add-credit-dialog.component.html", }) -export class AddCreditComponent implements OnInit { - @Input() creditAmount: string; - @Input() showOptions = true; - @Input() method = PaymentMethodType.PayPal; - @Input() organizationId: string; - @Output() onAdded = new EventEmitter(); - @Output() onCanceled = new EventEmitter(); - +export class AddCreditDialogComponent implements OnInit { @ViewChild("ppButtonForm", { read: ElementRef, static: true }) ppButtonFormRef: ElementRef; paymentMethodType = PaymentMethodType; @@ -44,21 +40,30 @@ export class AddCreditComponent implements OnInit { ppLoading = false; subject: string; returnUrl: string; - formPromise: Promise; + organizationId: string; private userId: string; private name: string; private email: string; private region: string; + protected DialogResult = AddCreditDialogResult; + protected formGroup = new FormGroup({ + method: new FormControl(PaymentMethodType.PayPal), + creditAmount: new FormControl(null, [Validators.required]), + }); + constructor( - private stateService: StateService, + private dialogRef: DialogRef, + @Inject(DIALOG_DATA) protected data: AddCreditDialogData, + private accountService: AccountService, private apiService: ApiService, private platformUtilsService: PlatformUtilsService, private organizationService: OrganizationService, private logService: LogService, private configService: ConfigService, ) { + this.organizationId = data.organizationId; const payPalConfig = process.env.PAYPAL_CONFIG as PayPalConfig; this.ppButtonFormAction = payPalConfig.buttonAction; this.ppButtonBusinessId = payPalConfig.businessId; @@ -79,8 +84,11 @@ export class AddCreditComponent implements OnInit { if (this.creditAmount == null) { this.creditAmount = "10.00"; } - this.userId = await this.stateService.getUserId(); - this.subject = await this.stateService.getEmail(); + const [userId, email] = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])), + ); + this.userId = userId; + this.subject = email; this.email = this.subject; this.ppButtonCustomField = "user_id:" + this.userId; } @@ -90,7 +98,18 @@ export class AddCreditComponent implements OnInit { this.returnUrl = window.location.href; } - async submit() { + get creditAmount() { + return this.formGroup.value.creditAmount; + } + set creditAmount(value: string) { + this.formGroup.get("creditAmount").setValue(value); + } + + get method() { + return this.formGroup.value.method; + } + + submit = async () => { if (this.creditAmount == null || this.creditAmount === "") { return; } @@ -101,33 +120,20 @@ export class AddCreditComponent implements OnInit { return; } if (this.method === PaymentMethodType.BitPay) { - try { - const req = new BitPayInvoiceRequest(); - req.email = this.email; - req.name = this.name; - req.credit = true; - req.amount = this.creditAmountNumber; - req.organizationId = this.organizationId; - req.userId = this.userId; - req.returnUrl = this.returnUrl; - this.formPromise = this.apiService.postBitPayInvoice(req); - const bitPayUrl: string = await this.formPromise; - this.platformUtilsService.launchUri(bitPayUrl); - } catch (e) { - this.logService.error(e); - } + const req = new BitPayInvoiceRequest(); + req.email = this.email; + req.name = this.name; + req.credit = true; + req.amount = this.creditAmountNumber; + req.organizationId = this.organizationId; + req.userId = this.userId; + req.returnUrl = this.returnUrl; + const bitPayUrl: string = await this.apiService.postBitPayInvoice(req); + this.platformUtilsService.launchUri(bitPayUrl); return; } - try { - this.onAdded.emit(); - } catch (e) { - this.logService.error(e); - } - } - - cancel() { - this.onCanceled.emit(); - } + this.dialogRef.close(AddCreditDialogResult.Added); + }; formatAmount() { try { @@ -157,3 +163,15 @@ export class AddCreditComponent implements OnInit { return null; } } + +/** + * Strongly typed helper to open a AddCreditDialog + * @param dialogService Instance of the dialog service that will be used to open the dialog + * @param config Configuration for the dialog + */ +export function openAddCreditDialog( + dialogService: DialogService, + config: DialogConfig, +) { + return dialogService.open(AddCreditDialogComponent, config); +} diff --git a/apps/web/src/app/billing/shared/add-credit.component.html b/apps/web/src/app/billing/shared/add-credit.component.html deleted file mode 100644 index 73c71812be6..00000000000 --- a/apps/web/src/app/billing/shared/add-credit.component.html +++ /dev/null @@ -1,80 +0,0 @@ -
-
- -

{{ "addCredit" | i18n }}

-
-
- - -
-
- - -
-
-
-
-
- -
-
$USD
- -
-
-
- {{ "creditDelayed" | i18n }} -
- - -
-
-
- - - - - - - - - - - - - - - -
diff --git a/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts b/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts index 41d0ad7e7af..8f16daeaa7b 100644 --- a/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts +++ b/apps/web/src/app/billing/shared/adjust-payment-dialog.component.ts @@ -1,16 +1,17 @@ import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; import { Component, Inject, ViewChild } from "@angular/core"; import { FormGroup } from "@angular/forms"; +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 { PaymentMethodWarningsServiceAbstraction as PaymentMethodWarningService } from "@bitwarden/common/billing/abstractions/payment-method-warnings-service.abstraction"; import { PaymentMethodType } from "@bitwarden/common/billing/enums"; import { PaymentRequest } from "@bitwarden/common/billing/models/request/payment.request"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { DialogService } from "@bitwarden/components"; +import { DialogService, ToastService } from "@bitwarden/components"; import { PaymentComponent } from "./payment.component"; import { TaxInfoComponent } from "./tax-info.component"; @@ -44,10 +45,10 @@ export class AdjustPaymentDialogComponent { @Inject(DIALOG_DATA) protected data: AdjustPaymentDialogData, private apiService: ApiService, private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, - private logService: LogService, private organizationApiService: OrganizationApiServiceAbstraction, private paymentMethodWarningService: PaymentMethodWarningService, + private configService: ConfigService, + private toastService: ToastService, ) { this.organizationId = data.organizationId; this.currentType = data.currentType; @@ -73,14 +74,17 @@ export class AdjustPaymentDialogComponent { } }); await response; - if (this.organizationId) { + const showPaymentMethodWarningBanners = await firstValueFrom( + this.configService.getFeatureFlag$(FeatureFlag.ShowPaymentMethodWarningBanners), + ); + if (this.organizationId && showPaymentMethodWarningBanners) { await this.paymentMethodWarningService.removeSubscriptionRisk(this.organizationId); } - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("updatedPaymentMethod"), - ); + this.toastService.showToast({ + variant: "success", + title: null, + message: this.i18nService.t("updatedPaymentMethod"), + }); this.dialogRef.close(AdjustPaymentDialogResult.Adjusted); }; diff --git a/apps/web/src/app/billing/shared/billing-shared.module.ts b/apps/web/src/app/billing/shared/billing-shared.module.ts index 65a651b73df..35fe33c7e06 100644 --- a/apps/web/src/app/billing/shared/billing-shared.module.ts +++ b/apps/web/src/app/billing/shared/billing-shared.module.ts @@ -3,7 +3,7 @@ import { NgModule } from "@angular/core"; import { HeaderModule } from "../../layouts/header/header.module"; import { SharedModule } from "../../shared"; -import { AddCreditComponent } from "./add-credit.component"; +import { AddCreditDialogComponent } from "./add-credit-dialog.component"; import { AdjustPaymentDialogComponent } from "./adjust-payment-dialog.component"; import { AdjustStorageComponent } from "./adjust-storage.component"; import { BillingHistoryComponent } from "./billing-history.component"; @@ -17,7 +17,7 @@ import { UpdateLicenseComponent } from "./update-license.component"; @NgModule({ imports: [SharedModule, PaymentComponent, TaxInfoComponent, HeaderModule], declarations: [ - AddCreditComponent, + AddCreditDialogComponent, AdjustPaymentDialogComponent, AdjustStorageComponent, BillingHistoryComponent, diff --git a/apps/web/src/app/billing/shared/payment-method.component.html b/apps/web/src/app/billing/shared/payment-method.component.html index 5f78294fa64..2ac9233b5bb 100644 --- a/apps/web/src/app/billing/shared/payment-method.component.html +++ b/apps/web/src/app/billing/shared/payment-method.component.html @@ -33,22 +33,9 @@ {{ creditOrBalance | currency: "$" }}

{{ "creditAppliedDesc" | i18n }}

- - -

{{ "paymentMethod" | i18n }}

{{ "noPaymentMethod" | i18n }}

diff --git a/apps/web/src/app/billing/shared/payment-method.component.ts b/apps/web/src/app/billing/shared/payment-method.component.ts index fee97cb912a..967bff6d1ab 100644 --- a/apps/web/src/app/billing/shared/payment-method.component.ts +++ b/apps/web/src/app/billing/shared/payment-method.component.ts @@ -15,6 +15,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service" import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogService } from "@bitwarden/components"; +import { AddCreditDialogResult, openAddCreditDialog } from "./add-credit-dialog.component"; import { AdjustPaymentDialogResult, openAdjustPaymentDialog, @@ -30,7 +31,6 @@ export class PaymentMethodComponent implements OnInit { loading = false; firstLoaded = false; - showAddCredit = false; billing: BillingPaymentResponse; org: OrganizationSubscriptionResponse; sub: SubscriptionResponse; @@ -111,18 +111,17 @@ export class PaymentMethodComponent implements OnInit { this.loading = false; } - addCredit() { - this.showAddCredit = true; - } - - closeAddCredit(load: boolean) { - this.showAddCredit = false; - if (load) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.load(); + addCredit = async () => { + const dialogRef = openAddCreditDialog(this.dialogService, { + data: { + organizationId: this.organizationId, + }, + }); + const result = await lastValueFrom(dialogRef.closed); + if (result === AddCreditDialogResult.Added) { + await this.load(); } - } + }; changePayment = async () => { const dialogRef = openAdjustPaymentDialog(this.dialogService, { diff --git a/apps/web/src/app/billing/shared/update-license.component.html b/apps/web/src/app/billing/shared/update-license.component.html index 56058b158e8..37eaa30c64c 100644 --- a/apps/web/src/app/billing/shared/update-license.component.html +++ b/apps/web/src/app/billing/shared/update-license.component.html @@ -1,20 +1,39 @@ -
-
- - - {{ + + + {{ "licenseFile" | i18n }} +
+ + {{ this.licenseFile ? this.licenseFile.name : ("noFileChosen" | i18n) }} +
+ + {{ "licenseFileDesc" | i18n : (!organizationId ? "bitwarden_premium_license.json" : "bitwarden_organization_license.json") - }}
-
- -
diff --git a/apps/web/src/app/billing/shared/update-license.component.ts b/apps/web/src/app/billing/shared/update-license.component.ts index 2c24565d710..30b5983090b 100644 --- a/apps/web/src/app/billing/shared/update-license.component.ts +++ b/apps/web/src/app/billing/shared/update-license.component.ts @@ -1,9 +1,9 @@ import { Component, EventEmitter, Input, Output } from "@angular/core"; +import { FormBuilder, Validators } from "@angular/forms"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; @Component({ @@ -17,19 +17,30 @@ export class UpdateLicenseComponent { @Output() onCanceled = new EventEmitter(); formPromise: Promise; - + title: string = this.i18nService.t("updateLicense"); + updateLicenseForm = this.formBuilder.group({ + file: [null, Validators.required], + }); + licenseFile: File = null; constructor( private apiService: ApiService, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, - private logService: LogService, private organizationApiService: OrganizationApiServiceAbstraction, + private formBuilder: FormBuilder, ) {} - - async submit() { - const fileEl = document.getElementById("file") as HTMLInputElement; - const files = fileEl.files; - if (files == null || files.length === 0) { + protected setSelectedFile(event: Event) { + const fileInputEl = event.target; + const file: File = fileInputEl.files.length > 0 ? fileInputEl.files[0] : null; + this.licenseFile = file; + } + submit = async () => { + this.updateLicenseForm.markAllAsTouched(); + if (this.updateLicenseForm.invalid) { + return; + } + const files = this.licenseFile; + if (files == null) { this.platformUtilsService.showToast( "error", this.i18nService.t("errorOccurred"), @@ -37,35 +48,30 @@ export class UpdateLicenseComponent { ); return; } + const fd = new FormData(); + fd.append("license", files); - try { - const fd = new FormData(); - fd.append("license", files[0]); - - let updatePromise: Promise = null; - if (this.organizationId == null) { - updatePromise = this.apiService.postAccountLicense(fd); - } else { - updatePromise = this.organizationApiService.updateLicense(this.organizationId, fd); - } - - this.formPromise = updatePromise.then(() => { - return this.apiService.refreshIdentityToken(); - }); - - await this.formPromise; - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("licenseUploadSuccess"), - ); - this.onUpdated.emit(); - } catch (e) { - this.logService.error(e); + let updatePromise: Promise = null; + if (this.organizationId == null) { + updatePromise = this.apiService.postAccountLicense(fd); + } else { + updatePromise = this.organizationApiService.updateLicense(this.organizationId, fd); } - } - cancel() { + this.formPromise = updatePromise.then(() => { + return this.apiService.refreshIdentityToken(); + }); + + await this.formPromise; + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("licenseUploadSuccess"), + ); + this.onUpdated.emit(); + }; + + cancel = () => { this.onCanceled.emit(); - } + }; } diff --git a/apps/web/src/app/settings/low-kdf.component.html b/apps/web/src/app/settings/low-kdf.component.html deleted file mode 100644 index fd191b21e86..00000000000 --- a/apps/web/src/app/settings/low-kdf.component.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- - {{ "lowKdfIterations" | i18n }} -
-
-

{{ "updateLowKdfIterationsDesc" | i18n }}

- - {{ "updateKdfSettings" | i18n }} - -
-
diff --git a/apps/web/src/app/settings/low-kdf.component.ts b/apps/web/src/app/settings/low-kdf.component.ts deleted file mode 100644 index a411c1402f2..00000000000 --- a/apps/web/src/app/settings/low-kdf.component.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Component } from "@angular/core"; - -@Component({ - selector: "app-low-kdf", - templateUrl: "low-kdf.component.html", -}) -export class LowKdfComponent {} diff --git a/apps/web/src/app/shared/loose-components.module.ts b/apps/web/src/app/shared/loose-components.module.ts index b511f5d7660..c7ae63f25c4 100644 --- a/apps/web/src/app/shared/loose-components.module.ts +++ b/apps/web/src/app/shared/loose-components.module.ts @@ -53,7 +53,6 @@ import { TwoFactorSetupComponent } from "../auth/settings/two-factor-setup.compo import { TwoFactorVerifyComponent } from "../auth/settings/two-factor-verify.component"; import { TwoFactorWebAuthnComponent } from "../auth/settings/two-factor-webauthn.component"; import { TwoFactorYubiKeyComponent } from "../auth/settings/two-factor-yubikey.component"; -import { VerifyEmailComponent } from "../auth/settings/verify-email.component"; import { UserVerificationModule } from "../auth/shared/components/user-verification"; import { SsoComponent } from "../auth/sso.component"; import { TwoFactorOptionsComponent } from "../auth/two-factor-options.component"; @@ -70,7 +69,6 @@ import { HeaderModule } from "../layouts/header/header.module"; import { ProductSwitcherModule } from "../layouts/product-switcher/product-switcher.module"; import { UserLayoutComponent } from "../layouts/user-layout.component"; import { DomainRulesComponent } from "../settings/domain-rules.component"; -import { LowKdfComponent } from "../settings/low-kdf.component"; import { PreferencesComponent } from "../settings/preferences.component"; import { VaultTimeoutInputComponent } from "../settings/vault-timeout-input.component"; import { GeneratorComponent } from "../tools/generator.component"; @@ -186,11 +184,9 @@ import { SharedModule } from "./shared.module"; UpdatePasswordComponent, UpdateTempPasswordComponent, VaultTimeoutInputComponent, - VerifyEmailComponent, VerifyEmailTokenComponent, VerifyRecoverDeleteComponent, VerifyRecoverDeleteProviderComponent, - LowKdfComponent, ], exports: [ UserVerificationModule, @@ -264,11 +260,9 @@ import { SharedModule } from "./shared.module"; UpdateTempPasswordComponent, UserLayoutComponent, VaultTimeoutInputComponent, - VerifyEmailComponent, VerifyEmailTokenComponent, VerifyRecoverDeleteComponent, VerifyRecoverDeleteProviderComponent, - LowKdfComponent, HeaderModule, DangerZoneComponent, ], diff --git a/apps/web/src/app/tools/generator.component.ts b/apps/web/src/app/tools/generator.component.ts index ee422ca5277..fc27e658465 100644 --- a/apps/web/src/app/tools/generator.component.ts +++ b/apps/web/src/app/tools/generator.component.ts @@ -1,11 +1,11 @@ -import { Component } from "@angular/core"; +import { Component, NgZone } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { GeneratorComponent as BaseGeneratorComponent } from "@bitwarden/angular/tools/generator/components/generator.component"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { DialogService } from "@bitwarden/components"; @@ -20,21 +20,23 @@ export class GeneratorComponent extends BaseGeneratorComponent { constructor( passwordGenerationService: PasswordGenerationServiceAbstraction, usernameGenerationService: UsernameGenerationServiceAbstraction, - stateService: StateService, + accountService: AccountService, platformUtilsService: PlatformUtilsService, i18nService: I18nService, logService: LogService, route: ActivatedRoute, + ngZone: NgZone, private dialogService: DialogService, ) { super( passwordGenerationService, usernameGenerationService, platformUtilsService, - stateService, + accountService, i18nService, logService, route, + ngZone, window, ); if (platformUtilsService.isSelfHost()) { diff --git a/apps/web/src/app/tools/reports/pages/breach-report.component.ts b/apps/web/src/app/tools/reports/pages/breach-report.component.ts index 8f371cf754c..5728d360785 100644 --- a/apps/web/src/app/tools/reports/pages/breach-report.component.ts +++ b/apps/web/src/app/tools/reports/pages/breach-report.component.ts @@ -1,8 +1,9 @@ import { Component, OnInit } from "@angular/core"; +import { firstValueFrom, map } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BreachAccountResponse } from "@bitwarden/common/models/response/breach-account.response"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; @Component({ selector: "app-breach-report", @@ -17,11 +18,13 @@ export class BreachReportComponent implements OnInit { constructor( private auditService: AuditService, - private stateService: StateService, + private accountService: AccountService, ) {} async ngOnInit() { - this.username = await this.stateService.getEmail(); + this.username = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); } async submit() { diff --git a/apps/web/src/app/tools/vault-export/export.component.ts b/apps/web/src/app/tools/vault-export/export.component.ts index 4fdd3ff9e08..7902d2818d6 100644 --- a/apps/web/src/app/tools/vault-export/export.component.ts +++ b/apps/web/src/app/tools/vault-export/export.component.ts @@ -1,11 +1,9 @@ import { Component } from "@angular/core"; import { UntypedFormBuilder } from "@angular/forms"; -import { UserVerificationDialogComponent } from "@bitwarden/auth/angular"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -26,7 +24,6 @@ export class ExportComponent extends BaseExportComponent { eventCollectionService: EventCollectionService, policyService: PolicyService, logService: LogService, - userVerificationService: UserVerificationService, formBuilder: UntypedFormBuilder, fileDownloadService: FileDownloadService, dialogService: DialogService, @@ -39,84 +36,10 @@ export class ExportComponent extends BaseExportComponent { eventCollectionService, policyService, logService, - userVerificationService, formBuilder, fileDownloadService, dialogService, organizationService, ); } - - submit = async () => { - if (this.isFileEncryptedExport && this.filePassword != this.confirmFilePassword) { - this.platformUtilsService.showToast( - "error", - this.i18nService.t("errorOccurred"), - this.i18nService.t("filePasswordAndConfirmFilePasswordDoNotMatch"), - ); - return; - } - - this.exportForm.markAllAsTouched(); - if (this.exportForm.invalid) { - return; - } - - if (this.disabledByPolicy) { - this.platformUtilsService.showToast( - "error", - null, - this.i18nService.t("personalVaultExportPolicyInEffect"), - ); - return; - } - - const userVerified = await this.verifyUser(); - if (!userVerified) { - return; - } - - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.doExport(); - }; - - protected saved() { - super.saved(); - this.platformUtilsService.showToast("success", null, this.i18nService.t("exportSuccess")); - } - - private async verifyUser(): Promise { - let confirmDescription = "exportWarningDesc"; - if (this.isFileEncryptedExport) { - confirmDescription = "fileEncryptedExportWarningDesc"; - } else if (this.isAccountEncryptedExport) { - confirmDescription = "encExportKeyWarningDesc"; - } - - const result = await UserVerificationDialogComponent.open(this.dialogService, { - title: "confirmVaultExport", - bodyText: confirmDescription, - confirmButtonOptions: { - text: "exportVault", - type: "primary", - }, - }); - - // Handle the result of the dialog based on user action and verification success - if (result.userAction === "cancel") { - // User cancelled the dialog - return false; - } - - // User confirmed the dialog so check verification success - if (!result.verificationSuccess) { - if (result.noAvailableClientVerificationMethods) { - // No client-side verification methods are available - // Could send user to configure a verification method like PIN or biometrics - } - return false; - } - return true; - } } diff --git a/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html index 6adf6bcf8f0..3f5624c0c97 100644 --- a/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html +++ b/apps/web/src/app/vault/components/collection-dialog/collection-dialog.component.html @@ -105,7 +105,7 @@ [items]="accessItems" [columnHeader]="'groupSlashMemberColumnHeader' | i18n" [selectorLabelText]="'selectGroupsAndMembers' | i18n" - [selectorHelpText]="'userPermissionOverrideHelper' | i18n" + [selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n" [emptySelectionText]="'noMembersOrGroupsAdded' | i18n" [flexibleCollectionsEnabled]="organization.flexibleCollections" > diff --git a/apps/web/src/app/vault/core/views/collection-admin.view.ts b/apps/web/src/app/vault/core/views/collection-admin.view.ts index 96a8150b0a4..f8695ba2171 100644 --- a/apps/web/src/app/vault/core/views/collection-admin.view.ts +++ b/apps/web/src/app/vault/core/views/collection-admin.view.ts @@ -85,14 +85,26 @@ export class CollectionAdminView extends CollectionView { * Whether the user can modify user access to this collection */ canEditUserAccess(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean { - return this.canEdit(org, flexibleCollectionsV1Enabled) || org.permissions.manageUsers; + const allowAdminAccessToAllCollectionItems = + !flexibleCollectionsV1Enabled || org.allowAdminAccessToAllCollectionItems; + + return ( + (org.permissions.manageUsers && allowAdminAccessToAllCollectionItems) || + this.canEdit(org, flexibleCollectionsV1Enabled) + ); } /** * Whether the user can modify group access to this collection */ canEditGroupAccess(org: Organization, flexibleCollectionsV1Enabled: boolean): boolean { - return this.canEdit(org, flexibleCollectionsV1Enabled) || org.permissions.manageGroups; + const allowAdminAccessToAllCollectionItems = + !flexibleCollectionsV1Enabled || org.allowAdminAccessToAllCollectionItems; + + return ( + (org.permissions.manageGroups && allowAdminAccessToAllCollectionItems) || + this.canEdit(org, flexibleCollectionsV1Enabled) + ); } /** diff --git a/apps/web/src/app/vault/individual-vault/add-edit.component.ts b/apps/web/src/app/vault/individual-vault/add-edit.component.ts index 56f18c4a3bd..fee728ca995 100644 --- a/apps/web/src/app/vault/individual-vault/add-edit.component.ts +++ b/apps/web/src/app/vault/individual-vault/add-edit.component.ts @@ -7,6 +7,7 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EventType, ProductType } from "@bitwarden/common/enums"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; @@ -14,7 +15,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -52,7 +52,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On i18nService: I18nService, platformUtilsService: PlatformUtilsService, auditService: AuditService, - stateService: StateService, + accountService: AccountService, collectionService: CollectionService, protected totpService: TotpService, protected passwordGenerationService: PasswordGenerationServiceAbstraction, @@ -74,7 +74,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit, On i18nService, platformUtilsService, auditService, - stateService, + accountService, collectionService, messagingService, eventCollectionService, diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.html b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.html index f4248331ffc..05a089c5d39 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.html +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.html @@ -4,8 +4,8 @@ - - {{ "deleteSelectedItemsDesc" | i18n: cipherIds.length }} + + {{ "deleteSelectedItemsDesc" | i18n: cipherIds.length + unassignedCiphers.length }} {{ "deleteSelectedCollectionsDesc" | i18n: collections.length }} @@ -13,7 +13,7 @@ {{ "deleteSelectedConfirmation" | i18n }} - {{ "permanentlyDeleteSelectedItemsDesc" | i18n: cipherIds.length }} + {{ "permanentlyDeleteSelectedItemsDesc" | i18n: cipherIds.length + unassignedCiphers.length }} diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts index ee036f5e3b3..c0de8c6bd22 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-delete-dialog/bulk-delete-dialog.component.ts @@ -20,6 +20,7 @@ export interface BulkDeleteDialogParams { organization?: Organization; organizations?: Organization[]; collections?: CollectionView[]; + unassignedCiphers?: string[]; } export enum BulkDeleteDialogResult { @@ -51,6 +52,7 @@ export class BulkDeleteDialogComponent { organization: Organization; organizations: Organization[]; collections: CollectionView[]; + unassignedCiphers: string[]; private flexibleCollectionsV1Enabled$ = this.configService.getFeatureFlag$( FeatureFlag.FlexibleCollectionsV1, @@ -75,6 +77,7 @@ export class BulkDeleteDialogComponent { this.organization = params.organization; this.organizations = params.organizations; this.collections = params.collections; + this.unassignedCiphers = params.unassignedCiphers || []; } protected async cancel() { @@ -83,6 +86,15 @@ export class BulkDeleteDialogComponent { protected submit = async () => { const deletePromises: Promise[] = []; + const restrictProviderAccess = await firstValueFrom(this.restrictProviderAccess$); + + // Unassigned ciphers under an Owner/Admin OR Custom Users With Edit will call the deleteCiphersAdmin method + if ( + this.unassignedCiphers.length && + this.organization.canEditUnassignedCiphers(restrictProviderAccess) + ) { + deletePromises.push(this.deleteCiphersAdmin(this.unassignedCiphers)); + } if (this.cipherIds.length) { const flexibleCollectionsV1Enabled = await firstValueFrom(this.flexibleCollectionsV1Enabled$); const restrictProviderAccess = await firstValueFrom(this.restrictProviderAccess$); @@ -93,7 +105,7 @@ export class BulkDeleteDialogComponent { ) { deletePromises.push(this.deleteCiphers()); } else { - deletePromises.push(this.deleteCiphersAdmin()); + deletePromises.push(this.deleteCiphersAdmin(this.cipherIds)); } } @@ -103,7 +115,7 @@ export class BulkDeleteDialogComponent { await Promise.all(deletePromises); - if (this.cipherIds.length) { + if (this.cipherIds.length || this.unassignedCiphers.length) { this.platformUtilsService.showToast( "success", null, @@ -135,8 +147,8 @@ export class BulkDeleteDialogComponent { } } - private async deleteCiphersAdmin(): Promise { - const deleteRequest = new CipherBulkDeleteRequest(this.cipherIds, this.organization.id); + private async deleteCiphersAdmin(ciphers: string[]): Promise { + const deleteRequest = new CipherBulkDeleteRequest(ciphers, this.organization.id); if (this.permanent) { return await this.apiService.deleteManyCiphersAdmin(deleteRequest); } else { diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts new file mode 100644 index 00000000000..c09451addda --- /dev/null +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.spec.ts @@ -0,0 +1,265 @@ +import { TestBed } from "@angular/core/testing"; +import { BehaviorSubject, firstValueFrom } from "rxjs"; + +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { KdfType } from "@bitwarden/common/platform/enums"; +import { StateProvider } from "@bitwarden/common/platform/state"; +import { FakeStateProvider, mockAccountServiceWith } from "@bitwarden/common/spec"; +import { UserId } from "@bitwarden/common/types/guid"; +import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; + +import { + PREMIUM_BANNER_REPROMPT_KEY, + VaultBannersService, + VisibleVaultBanner, +} from "./vault-banners.service"; + +describe("VaultBannersService", () => { + let service: VaultBannersService; + const isSelfHost = jest.fn().mockReturnValue(false); + const hasPremiumFromAnySource$ = new BehaviorSubject(false); + const fakeStateProvider = new FakeStateProvider(mockAccountServiceWith("user-id" as UserId)); + const getEmailVerified = jest.fn().mockResolvedValue(true); + const hasMasterPassword = jest.fn().mockResolvedValue(true); + const getKdfConfig = jest + .fn() + .mockResolvedValue({ kdfType: KdfType.PBKDF2_SHA256, iterations: 600000 }); + const getLastSync = jest.fn().mockResolvedValue(null); + + beforeEach(() => { + jest.useFakeTimers(); + getLastSync.mockClear().mockResolvedValue(new Date("2024-05-14")); + isSelfHost.mockClear(); + getEmailVerified.mockClear().mockResolvedValue(true); + + TestBed.configureTestingModule({ + providers: [ + VaultBannersService, + { + provide: PlatformUtilsService, + useValue: { isSelfHost }, + }, + { + provide: BillingAccountProfileStateService, + useValue: { hasPremiumFromAnySource$: hasPremiumFromAnySource$ }, + }, + { + provide: StateProvider, + useValue: fakeStateProvider, + }, + { + provide: PlatformUtilsService, + useValue: { isSelfHost }, + }, + { + provide: TokenService, + useValue: { getEmailVerified }, + }, + { + provide: UserVerificationService, + useValue: { hasMasterPassword }, + }, + { + provide: KdfConfigService, + useValue: { getKdfConfig }, + }, + { + provide: SyncService, + useValue: { getLastSync }, + }, + ], + }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + describe("Premium", () => { + it("waits until sync is completed before showing premium banner", async () => { + getLastSync.mockResolvedValue(new Date("2024-05-14")); + hasPremiumFromAnySource$.next(false); + isSelfHost.mockReturnValue(false); + + service = TestBed.inject(VaultBannersService); + + jest.advanceTimersByTime(201); + + expect(await firstValueFrom(service.shouldShowPremiumBanner$)).toBe(true); + }); + + it("does not show a premium banner for self-hosted users", async () => { + getLastSync.mockResolvedValue(new Date("2024-05-14")); + hasPremiumFromAnySource$.next(false); + isSelfHost.mockReturnValue(true); + + service = TestBed.inject(VaultBannersService); + + jest.advanceTimersByTime(201); + + expect(await firstValueFrom(service.shouldShowPremiumBanner$)).toBe(false); + }); + + it("does not show a premium banner when they have access to premium", async () => { + getLastSync.mockResolvedValue(new Date("2024-05-14")); + hasPremiumFromAnySource$.next(true); + isSelfHost.mockReturnValue(false); + + service = TestBed.inject(VaultBannersService); + + jest.advanceTimersByTime(201); + + expect(await firstValueFrom(service.shouldShowPremiumBanner$)).toBe(false); + }); + + describe("dismissing", () => { + beforeEach(async () => { + jest.useFakeTimers(); + const date = new Date("2023-06-08"); + date.setHours(0, 0, 0, 0); + jest.setSystemTime(date.getTime()); + + service = TestBed.inject(VaultBannersService); + await service.dismissBanner(VisibleVaultBanner.Premium); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it("updates state on first dismiss", async () => { + const state = await firstValueFrom( + fakeStateProvider.getActive(PREMIUM_BANNER_REPROMPT_KEY).state$, + ); + + const oneWeekLater = new Date("2023-06-15"); + oneWeekLater.setHours(0, 0, 0, 0); + + expect(state).toEqual({ + numberOfDismissals: 1, + nextPromptDate: oneWeekLater.getTime(), + }); + }); + + it("updates state on second dismiss", async () => { + const state = await firstValueFrom( + fakeStateProvider.getActive(PREMIUM_BANNER_REPROMPT_KEY).state$, + ); + + const oneMonthLater = new Date("2023-07-08"); + oneMonthLater.setHours(0, 0, 0, 0); + + expect(state).toEqual({ + numberOfDismissals: 2, + nextPromptDate: oneMonthLater.getTime(), + }); + }); + + it("updates state on third dismiss", async () => { + const state = await firstValueFrom( + fakeStateProvider.getActive(PREMIUM_BANNER_REPROMPT_KEY).state$, + ); + + const oneYearLater = new Date("2024-06-08"); + oneYearLater.setHours(0, 0, 0, 0); + + expect(state).toEqual({ + numberOfDismissals: 3, + nextPromptDate: oneYearLater.getTime(), + }); + }); + }); + }); + + describe("KDFSettings", () => { + beforeEach(async () => { + hasMasterPassword.mockResolvedValue(true); + getKdfConfig.mockResolvedValue({ kdfType: KdfType.PBKDF2_SHA256, iterations: 599999 }); + }); + + it("shows low KDF iteration banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowLowKDFBanner()).toBe(true); + }); + + it("does not show low KDF iteration banner if KDF type is not PBKDF2_SHA256", async () => { + getKdfConfig.mockResolvedValue({ kdfType: KdfType.Argon2id, iterations: 600001 }); + + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowLowKDFBanner()).toBe(false); + }); + + it("does not show low KDF for iterations about 600,000", async () => { + getKdfConfig.mockResolvedValue({ kdfType: KdfType.PBKDF2_SHA256, iterations: 600001 }); + + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowLowKDFBanner()).toBe(false); + }); + + it("dismisses low KDF iteration banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowLowKDFBanner()).toBe(true); + + await service.dismissBanner(VisibleVaultBanner.KDFSettings); + + expect(await service.shouldShowLowKDFBanner()).toBe(false); + }); + }); + + describe("OutdatedBrowser", () => { + beforeEach(async () => { + // Hardcode `MSIE` in userAgent string + const userAgent = "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4.1 MSIE"; + Object.defineProperty(navigator, "userAgent", { + configurable: true, + get: () => userAgent, + }); + }); + + it("shows outdated browser banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowUpdateBrowserBanner()).toBe(true); + }); + + it("dismisses outdated browser banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowUpdateBrowserBanner()).toBe(true); + + await service.dismissBanner(VisibleVaultBanner.OutdatedBrowser); + + expect(await service.shouldShowUpdateBrowserBanner()).toBe(false); + }); + }); + + describe("VerifyEmail", () => { + beforeEach(async () => { + getEmailVerified.mockResolvedValue(false); + }); + + it("shows verify email banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowVerifyEmailBanner()).toBe(true); + }); + + it("dismisses verify email banner", async () => { + service = TestBed.inject(VaultBannersService); + + expect(await service.shouldShowVerifyEmailBanner()).toBe(true); + + await service.dismissBanner(VisibleVaultBanner.VerifyEmail); + + expect(await service.shouldShowVerifyEmailBanner()).toBe(false); + }); + }); +}); diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts new file mode 100644 index 00000000000..b54f2e9c115 --- /dev/null +++ b/apps/web/src/app/vault/individual-vault/vault-banners/services/vault-banners.service.ts @@ -0,0 +1,215 @@ +import { Injectable } from "@angular/core"; +import { Subject, Observable, combineLatest, firstValueFrom, map } from "rxjs"; +import { mergeMap, take } from "rxjs/operators"; + +import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; +import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums"; +import { + StateProvider, + ActiveUserState, + KeyDefinition, + PREMIUM_BANNER_DISK_LOCAL, + BANNERS_DISMISSED_DISK, +} from "@bitwarden/common/platform/state"; +import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; + +export enum VisibleVaultBanner { + KDFSettings = "kdf-settings", + OutdatedBrowser = "outdated-browser", + Premium = "premium", + VerifyEmail = "verify-email", +} + +type PremiumBannerReprompt = { + numberOfDismissals: number; + /** Timestamp representing when to show the prompt next */ + nextPromptDate: number; +}; + +/** Banners that will be re-shown on a new session */ +type SessionBanners = Omit; + +export const PREMIUM_BANNER_REPROMPT_KEY = new KeyDefinition( + PREMIUM_BANNER_DISK_LOCAL, + "bannerReprompt", + { + deserializer: (bannerReprompt) => bannerReprompt, + }, +); + +export const BANNERS_DISMISSED_DISK_KEY = new KeyDefinition( + BANNERS_DISMISSED_DISK, + "bannersDismissed", + { + deserializer: (bannersDismissed) => bannersDismissed, + }, +); + +@Injectable() +export class VaultBannersService { + shouldShowPremiumBanner$: Observable; + + private premiumBannerState: ActiveUserState; + private sessionBannerState: ActiveUserState; + + /** + * Emits when the sync service has completed a sync + * + * This is needed because `hasPremiumFromAnySource$` will emit false until the sync is completed + * resulting in the premium banner being shown briefly on startup when the user has access to + * premium features. + */ + private syncCompleted$ = new Subject(); + + constructor( + private tokenService: TokenService, + private userVerificationService: UserVerificationService, + private stateProvider: StateProvider, + private billingAccountProfileStateService: BillingAccountProfileStateService, + private platformUtilsService: PlatformUtilsService, + private kdfConfigService: KdfConfigService, + private syncService: SyncService, + ) { + this.pollUntilSynced(); + this.premiumBannerState = this.stateProvider.getActive(PREMIUM_BANNER_REPROMPT_KEY); + this.sessionBannerState = this.stateProvider.getActive(BANNERS_DISMISSED_DISK_KEY); + + const premiumSources$ = combineLatest([ + this.billingAccountProfileStateService.hasPremiumFromAnySource$, + this.premiumBannerState.state$, + ]); + + this.shouldShowPremiumBanner$ = this.syncCompleted$.pipe( + take(1), // Wait until the first sync is complete before considering the premium status + mergeMap(() => premiumSources$), + map(([canAccessPremium, dismissedState]) => { + const shouldShowPremiumBanner = + !canAccessPremium && !this.platformUtilsService.isSelfHost(); + + // Check if nextPromptDate is in the past passed + if (shouldShowPremiumBanner && dismissedState?.nextPromptDate) { + const nextPromptDate = new Date(dismissedState.nextPromptDate); + const now = new Date(); + return now >= nextPromptDate; + } + + return shouldShowPremiumBanner; + }), + ); + } + + /** Returns true when the update browser banner should be shown */ + async shouldShowUpdateBrowserBanner(): Promise { + const outdatedBrowser = window.navigator.userAgent.indexOf("MSIE") !== -1; + const alreadyDismissed = (await this.getBannerDismissedState()).includes( + VisibleVaultBanner.OutdatedBrowser, + ); + + return outdatedBrowser && !alreadyDismissed; + } + + /** Returns true when the verify email banner should be shown */ + async shouldShowVerifyEmailBanner(): Promise { + const needsVerification = !(await this.tokenService.getEmailVerified()); + + const alreadyDismissed = (await this.getBannerDismissedState()).includes( + VisibleVaultBanner.VerifyEmail, + ); + + return needsVerification && !alreadyDismissed; + } + + /** Returns true when the low KDF iteration banner should be shown */ + async shouldShowLowKDFBanner(): Promise { + const hasLowKDF = (await this.userVerificationService.hasMasterPassword()) + ? await this.isLowKdfIteration() + : false; + + const alreadyDismissed = (await this.getBannerDismissedState()).includes( + VisibleVaultBanner.KDFSettings, + ); + + return hasLowKDF && !alreadyDismissed; + } + + /** Dismiss the given banner and perform any respective side effects */ + async dismissBanner(banner: SessionBanners): Promise { + if (banner === VisibleVaultBanner.Premium) { + await this.dismissPremiumBanner(); + } else { + await this.sessionBannerState.update((current) => { + const bannersDismissed = current ?? []; + + return [...bannersDismissed, banner]; + }); + } + } + + /** Returns banners that have already been dismissed */ + private async getBannerDismissedState(): Promise { + // `state$` can emit null when a value has not been set yet, + // use nullish coalescing to default to an empty array + return (await firstValueFrom(this.sessionBannerState.state$)) ?? []; + } + + /** Increment dismissal state of the premium banner */ + private async dismissPremiumBanner(): Promise { + await this.premiumBannerState.update((current) => { + const numberOfDismissals = current?.numberOfDismissals ?? 0; + const now = new Date(); + + // Set midnight of the current day + now.setHours(0, 0, 0, 0); + + // First dismissal, re-prompt in 1 week + if (numberOfDismissals === 0) { + now.setDate(now.getDate() + 7); + return { + numberOfDismissals: 1, + nextPromptDate: now.getTime(), + }; + } + + // Second dismissal, re-prompt in 1 month + if (numberOfDismissals === 1) { + now.setMonth(now.getMonth() + 1); + return { + numberOfDismissals: 2, + nextPromptDate: now.getTime(), + }; + } + + // 3+ dismissals, re-prompt each year + // Avoid day/month edge cases and only increment year + const nextYear = new Date(now.getFullYear() + 1, now.getMonth(), now.getDate()); + nextYear.setHours(0, 0, 0, 0); + return { + numberOfDismissals: numberOfDismissals + 1, + nextPromptDate: nextYear.getTime(), + }; + }); + } + + private async isLowKdfIteration() { + const kdfConfig = await this.kdfConfigService.getKdfConfig(); + return ( + kdfConfig.kdfType === KdfType.PBKDF2_SHA256 && + kdfConfig.iterations < PBKDF2_ITERATIONS.defaultValue + ); + } + + /** Poll the `syncService` until a sync is completed */ + private pollUntilSynced() { + const interval = setInterval(async () => { + const lastSync = await this.syncService.getLastSync(); + if (lastSync !== null) { + clearInterval(interval); + this.syncCompleted$.next(); + } + }, 200); + } +} diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.html b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.html new file mode 100644 index 00000000000..bcbe424b469 --- /dev/null +++ b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.html @@ -0,0 +1,52 @@ + + {{ "updateBrowserDesc" | i18n }} + + {{ "updateBrowser" | i18n }} + + + + + {{ "lowKDFIterationsBanner" | i18n }} + + {{ "changeKDFSettings" | i18n }} + + + + + + + {{ "premiumUpgradeUnlockFeatures" | i18n }} + + {{ "goPremium" | i18n }} + + diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts new file mode 100644 index 00000000000..8c637d22b17 --- /dev/null +++ b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.spec.ts @@ -0,0 +1,140 @@ +import { ComponentFixture, TestBed } from "@angular/core/testing"; +import { By } from "@angular/platform-browser"; +import { mock } from "jest-mock-extended"; +import { BehaviorSubject } from "rxjs"; + +import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; +import { BannerComponent, BannerModule } from "@bitwarden/components"; + +import { VerifyEmailComponent } from "../../../auth/settings/verify-email.component"; +import { LooseComponentsModule } from "../../../shared"; + +import { VaultBannersService, VisibleVaultBanner } from "./services/vault-banners.service"; +import { VaultBannersComponent } from "./vault-banners.component"; + +describe("VaultBannersComponent", () => { + let component: VaultBannersComponent; + let fixture: ComponentFixture; + const premiumBanner$ = new BehaviorSubject(false); + + const bannerService = mock({ + shouldShowPremiumBanner$: premiumBanner$, + shouldShowUpdateBrowserBanner: jest.fn(), + shouldShowVerifyEmailBanner: jest.fn(), + shouldShowLowKDFBanner: jest.fn(), + dismissBanner: jest.fn(), + }); + + beforeEach(async () => { + bannerService.shouldShowPremiumBanner$ = premiumBanner$; + bannerService.shouldShowUpdateBrowserBanner.mockResolvedValue(false); + bannerService.shouldShowVerifyEmailBanner.mockResolvedValue(false); + bannerService.shouldShowLowKDFBanner.mockResolvedValue(false); + + await TestBed.configureTestingModule({ + imports: [BannerModule, LooseComponentsModule, VerifyEmailComponent], + declarations: [VaultBannersComponent, I18nPipe], + providers: [ + { + provide: VaultBannersService, + useValue: bannerService, + }, + { + provide: I18nService, + useValue: mock({ t: (key) => key }), + }, + { + provide: ApiService, + useValue: mock(), + }, + { + provide: PlatformUtilsService, + useValue: mock(), + }, + { + provide: TokenService, + useValue: mock(), + }, + ], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(VaultBannersComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + describe("premiumBannerVisible$", () => { + it("shows premium banner", async () => { + premiumBanner$.next(true); + + fixture.detectChanges(); + + const banner = fixture.debugElement.query(By.directive(BannerComponent)); + expect(banner.componentInstance.bannerType).toBe("premium"); + }); + + it("dismisses premium banner", async () => { + premiumBanner$.next(false); + + fixture.detectChanges(); + + const banner = fixture.debugElement.query(By.directive(BannerComponent)); + expect(banner).toBeNull(); + }); + }); + + describe("determineVisibleBanner", () => { + [ + { + name: "OutdatedBrowser", + method: bannerService.shouldShowUpdateBrowserBanner, + banner: VisibleVaultBanner.OutdatedBrowser, + }, + { + name: "VerifyEmail", + method: bannerService.shouldShowVerifyEmailBanner, + banner: VisibleVaultBanner.VerifyEmail, + }, + { + name: "LowKDF", + method: bannerService.shouldShowLowKDFBanner, + banner: VisibleVaultBanner.KDFSettings, + }, + ].forEach(({ name, method, banner }) => { + describe(name, () => { + beforeEach(async () => { + method.mockResolvedValue(true); + + await component.ngOnInit(); + fixture.detectChanges(); + }); + + it(`shows ${name} banner`, async () => { + expect(component.visibleBanners).toEqual([banner]); + }); + + it(`dismisses ${name} banner`, async () => { + const dismissButton = fixture.debugElement.nativeElement.querySelector( + 'button[biticonbutton="bwi-close"]', + ); + + // Mock out the banner service returning false after dismissing + method.mockResolvedValue(false); + + dismissButton.dispatchEvent(new Event("click")); + + expect(bannerService.dismissBanner).toHaveBeenCalledWith(banner); + + expect(component.visibleBanners).toEqual([]); + }); + }); + }); + }); +}); diff --git a/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts new file mode 100644 index 00000000000..e612bc231da --- /dev/null +++ b/apps/web/src/app/vault/individual-vault/vault-banners/vault-banners.component.ts @@ -0,0 +1,41 @@ +import { Component, OnInit } from "@angular/core"; +import { Observable } from "rxjs"; + +import { VaultBannersService, VisibleVaultBanner } from "./services/vault-banners.service"; + +@Component({ + selector: "app-vault-banners", + templateUrl: "./vault-banners.component.html", +}) +export class VaultBannersComponent implements OnInit { + visibleBanners: VisibleVaultBanner[] = []; + premiumBannerVisible$: Observable; + VisibleVaultBanner = VisibleVaultBanner; + + constructor(private vaultBannerService: VaultBannersService) { + this.premiumBannerVisible$ = this.vaultBannerService.shouldShowPremiumBanner$; + } + + async ngOnInit(): Promise { + await this.determineVisibleBanners(); + } + + async dismissBanner(banner: VisibleVaultBanner): Promise { + await this.vaultBannerService.dismissBanner(banner); + + await this.determineVisibleBanners(); + } + + /** Determine which banners should be present */ + private async determineVisibleBanners(): Promise { + const showBrowserOutdated = await this.vaultBannerService.shouldShowUpdateBrowserBanner(); + const showVerifyEmail = await this.vaultBannerService.shouldShowVerifyEmailBanner(); + const showLowKdf = await this.vaultBannerService.shouldShowLowKDFBanner(); + + this.visibleBanners = [ + showBrowserOutdated ? VisibleVaultBanner.OutdatedBrowser : null, + showVerifyEmail ? VisibleVaultBanner.VerifyEmail : null, + showLowKdf ? VisibleVaultBanner.KDFSettings : null, + ].filter(Boolean); // remove all falsy values, i.e. null + } +} diff --git a/apps/web/src/app/vault/individual-vault/vault.component.html b/apps/web/src/app/vault/individual-vault/vault.component.html index 3f95665f37a..f39ec3378dc 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.html +++ b/apps/web/src/app/vault/individual-vault/vault.component.html @@ -1,3 +1,5 @@ + + -
-
+
+
@@ -30,7 +32,7 @@
-
+
{{ trashCleanupWarning }} @@ -81,44 +83,6 @@
-
- - - - -
-
- - {{ "updateBrowser" | i18n }} -
-
-

{{ "updateBrowserDesc" | i18n }}

- - {{ "updateBrowser" | i18n }} - -
-
-
-
- {{ "goPremium" | i18n }} -
-
-

{{ "premiumUpgradeUnlockFeatures" | i18n }}

- - {{ "goPremium" | i18n }} - -
-
-
diff --git a/apps/web/src/app/vault/individual-vault/vault.component.ts b/apps/web/src/app/vault/individual-vault/vault.component.ts index 474e9045d0e..ca04b3aa51f 100644 --- a/apps/web/src/app/vault/individual-vault/vault.component.ts +++ b/apps/web/src/app/vault/individual-vault/vault.component.ts @@ -35,9 +35,6 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { EventType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; @@ -47,7 +44,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { KdfType, PBKDF2_ITERATIONS } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service"; @@ -122,10 +118,6 @@ export class VaultComponent implements OnInit, OnDestroy { @ViewChild("collectionsModal", { read: ViewContainerRef, static: true }) collectionsModalRef: ViewContainerRef; - showVerifyEmail = false; - showBrowserOutdated = false; - showPremiumCallout = false; - showLowKdf = false; trashCleanupWarning: string = null; kdfIterations: number; activeFilter: VaultFilter = new VaultFilter(); @@ -161,7 +153,6 @@ export class VaultComponent implements OnInit, OnDestroy { private i18nService: I18nService, private modalService: ModalService, private dialogService: DialogService, - private tokenService: TokenService, private messagingService: MessagingService, private platformUtilsService: PlatformUtilsService, private broadcasterService: BroadcasterService, @@ -180,14 +171,11 @@ export class VaultComponent implements OnInit, OnDestroy { private searchPipe: SearchPipe, private configService: ConfigService, private apiService: ApiService, - private userVerificationService: UserVerificationService, private billingAccountProfileStateService: BillingAccountProfileStateService, private toastService: ToastService, - protected kdfConfigService: KdfConfigService, ) {} async ngOnInit() { - this.showBrowserOutdated = window.navigator.userAgent.indexOf("MSIE") !== -1; this.trashCleanupWarning = this.i18nService.t( this.platformUtilsService.isSelfHost() ? "trashCleanupWarningSelfHosted" @@ -197,18 +185,8 @@ export class VaultComponent implements OnInit, OnDestroy { const firstSetup$ = this.route.queryParams.pipe( first(), switchMap(async (params: Params) => { - this.showVerifyEmail = !(await this.tokenService.getEmailVerified()); - this.showLowKdf = (await this.userVerificationService.hasMasterPassword()) - ? await this.isLowKdfIteration() - : false; await this.syncService.fullSync(false); - const canAccessPremium = await firstValueFrom( - this.billingAccountProfileStateService.hasPremiumFromAnySource$, - ); - this.showPremiumCallout = - !this.showVerifyEmail && !canAccessPremium && !this.platformUtilsService.isSelfHost(); - const cipherId = getCipherIdFromParams(params); if (!cipherId) { return; @@ -412,16 +390,6 @@ export class VaultComponent implements OnInit, OnDestroy { ); } - get isShowingCards() { - return ( - this.showBrowserOutdated || this.showPremiumCallout || this.showVerifyEmail || this.showLowKdf - ); - } - - emailVerified(verified: boolean) { - this.showVerifyEmail = !verified; - } - ngOnDestroy() { this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); this.destroy$.next(); @@ -1005,14 +973,6 @@ export class VaultComponent implements OnInit, OnDestroy { : this.cipherService.softDeleteWithServer(id); } - async isLowKdfIteration() { - const kdfConfig = await this.kdfConfigService.getKdfConfig(); - return ( - kdfConfig.kdfType === KdfType.PBKDF2_SHA256 && - kdfConfig.iterations < PBKDF2_ITERATIONS.defaultValue - ); - } - protected async repromptCipher(ciphers: CipherView[]) { const notProtected = !ciphers.find((cipher) => cipher.reprompt !== CipherRepromptType.None); diff --git a/apps/web/src/app/vault/individual-vault/vault.module.ts b/apps/web/src/app/vault/individual-vault/vault.module.ts index 81fc38eda11..c79c64c1ebf 100644 --- a/apps/web/src/app/vault/individual-vault/vault.module.ts +++ b/apps/web/src/app/vault/individual-vault/vault.module.ts @@ -1,7 +1,8 @@ import { NgModule } from "@angular/core"; -import { BreadcrumbsModule } from "@bitwarden/components"; +import { BannerModule, BreadcrumbsModule } from "@bitwarden/components"; +import { VerifyEmailComponent } from "../../auth/settings/verify-email.component"; import { LooseComponentsModule, SharedModule } from "../../shared"; import { CollectionDialogModule } from "../components/collection-dialog"; import { VaultItemsModule } from "../components/vault-items/vault-items.module"; @@ -11,6 +12,8 @@ import { GroupBadgeModule } from "../org-vault/group-badge/group-badge.module"; import { BulkDialogsModule } from "./bulk-action-dialogs/bulk-dialogs.module"; import { OrganizationBadgeModule } from "./organization-badge/organization-badge.module"; import { PipesModule } from "./pipes/pipes.module"; +import { VaultBannersService } from "./vault-banners/services/vault-banners.service"; +import { VaultBannersComponent } from "./vault-banners/vault-banners.component"; import { VaultFilterModule } from "./vault-filter/vault-filter.module"; import { VaultHeaderComponent } from "./vault-header/vault-header.component"; import { VaultOnboardingService as VaultOnboardingServiceAbstraction } from "./vault-onboarding/services/abstraction/vault-onboarding.service"; @@ -34,10 +37,13 @@ import { VaultComponent } from "./vault.component"; VaultItemsModule, CollectionDialogModule, VaultOnboardingComponent, + BannerModule, + VerifyEmailComponent, ], - declarations: [VaultComponent, VaultHeaderComponent], + declarations: [VaultComponent, VaultHeaderComponent, VaultBannersComponent], exports: [VaultComponent], providers: [ + VaultBannersService, { provide: VaultOnboardingServiceAbstraction, useClass: VaultOnboardingService, diff --git a/apps/web/src/app/vault/org-vault/add-edit.component.ts b/apps/web/src/app/vault/org-vault/add-edit.component.ts index 82055cc9165..9c7c3c30f32 100644 --- a/apps/web/src/app/vault/org-vault/add-edit.component.ts +++ b/apps/web/src/app/vault/org-vault/add-edit.component.ts @@ -6,13 +6,13 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -40,7 +40,7 @@ export class AddEditComponent extends BaseAddEditComponent { i18nService: I18nService, platformUtilsService: PlatformUtilsService, auditService: AuditService, - stateService: StateService, + accountService: AccountService, collectionService: CollectionService, totpService: TotpService, passwordGenerationService: PasswordGenerationServiceAbstraction, @@ -63,7 +63,7 @@ export class AddEditComponent extends BaseAddEditComponent { i18nService, platformUtilsService, auditService, - stateService, + accountService, collectionService, totpService, passwordGenerationService, diff --git a/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.html b/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.html index a2b668f7dbf..9ce066f06e0 100644 --- a/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.html +++ b/apps/web/src/app/vault/org-vault/bulk-collections-dialog/bulk-collections-dialog.component.html @@ -15,7 +15,7 @@ [items]="accessItems" [columnHeader]="'groupSlashMemberColumnHeader' | i18n" [selectorLabelText]="'selectGroupsAndMembers' | i18n" - [selectorHelpText]="'userPermissionOverrideHelper' | i18n" + [selectorHelpText]="'userPermissionOverrideHelperDesc' | i18n" [emptySelectionText]="'noMembersOrGroupsAdded' | i18n" [flexibleCollectionsEnabled]="flexibleCollectionsEnabled$ | async" > diff --git a/apps/web/src/app/vault/org-vault/vault.component.html b/apps/web/src/app/vault/org-vault/vault.component.html index a6d1cd30747..06907b9e5dc 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.html +++ b/apps/web/src/app/vault/org-vault/vault.component.html @@ -12,7 +12,7 @@ >
-
+
@@ -26,7 +26,7 @@
-
+
(); private refresh$ = new BehaviorSubject(null); private destroy$ = new Subject(); @@ -747,7 +751,7 @@ export class VaultComponent implements OnInit, OnDestroy { if (ciphers.length === 1 && collections.length === 0) { await this.deleteCipher(ciphers[0]); } else if (ciphers.length === 0 && collections.length === 1) { - await this.deleteCollection(collections[0]); + await this.deleteCollection(collections[0] as CollectionAdminView); } else { await this.bulkDelete(ciphers, collections, this.organization); } @@ -976,6 +980,7 @@ export class VaultComponent implements OnInit, OnDestroy { } if ( + !this.organization.permissions.editAnyCollection && this.flexibleCollectionsV1Enabled && !c.edit && !this.organization.allowAdminAccessToAllCollectionItems @@ -988,8 +993,11 @@ export class VaultComponent implements OnInit, OnDestroy { return; } + // Allow restore of an Unassigned Item try { - const asAdmin = this.organization?.canEditAnyCollection(this.flexibleCollectionsV1Enabled); + const asAdmin = + this.organization?.canEditAnyCollection(this.flexibleCollectionsV1Enabled) || + c.isUnassigned; await this.cipherService.restoreWithServer(c.id, asAdmin); this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem")); this.refresh(); @@ -1000,6 +1008,7 @@ export class VaultComponent implements OnInit, OnDestroy { async bulkRestore(ciphers: CipherView[]) { if ( + !this.organization.permissions.editAnyCollection && this.flexibleCollectionsV1Enabled && ciphers.some((c) => !c.edit && !this.organization.allowAdminAccessToAllCollectionItems) ) { @@ -1011,13 +1020,46 @@ export class VaultComponent implements OnInit, OnDestroy { return; } - const selectedCipherIds = ciphers.map((cipher) => cipher.id); - if (selectedCipherIds.length === 0) { - this.platformUtilsService.showToast("error", null, this.i18nService.t("nothingSelected")); + // assess if there are unassigned ciphers and/or editable ciphers selected in bulk for restore + const editAccessCiphers: string[] = []; + const unassignedCiphers: string[] = []; + + // If user has edit all Access no need to check for unassigned ciphers + const canEditAll = this.organization.canEditAllCiphers( + this.flexibleCollectionsV1Enabled, + this.restrictProviderAccessEnabled, + ); + + if (canEditAll) { + ciphers.map((cipher) => { + editAccessCiphers.push(cipher.id); + }); + } else { + ciphers.map((cipher) => { + if (cipher.collectionIds.length === 0) { + unassignedCiphers.push(cipher.id); + } else if (cipher.edit) { + editAccessCiphers.push(cipher.id); + } + }); + } + + if (unassignedCiphers.length === 0 && editAccessCiphers.length === 0) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("nothingSelected"), + ); return; } - await this.cipherService.restoreManyWithServer(selectedCipherIds); + if (unassignedCiphers.length > 0 || editAccessCiphers.length > 0) { + await this.cipherService.restoreManyWithServer( + [...unassignedCiphers, ...editAccessCiphers], + this.organization.id, + ); + } + this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItems")); this.refresh(); } @@ -1026,7 +1068,10 @@ export class VaultComponent implements OnInit, OnDestroy { if ( this.flexibleCollectionsV1Enabled && !c.edit && - !this.organization.allowAdminAccessToAllCollectionItems + !this.organization.canEditAllCiphers( + this.flexibleCollectionsV1Enabled, + this.restrictProviderAccessEnabled, + ) ) { this.showMissingPermissionsError(); return; @@ -1049,7 +1094,7 @@ export class VaultComponent implements OnInit, OnDestroy { } try { - await this.deleteCipherWithServer(c.id, permanent); + await this.deleteCipherWithServer(c.id, permanent, c.isUnassigned); this.platformUtilsService.showToast( "success", null, @@ -1061,7 +1106,7 @@ export class VaultComponent implements OnInit, OnDestroy { } } - async deleteCollection(collection: CollectionView): Promise { + async deleteCollection(collection: CollectionAdminView): Promise { if (!collection.canDelete(this.organization, this.flexibleCollectionsV1Enabled)) { this.showMissingPermissionsError(); return; @@ -1107,6 +1152,18 @@ export class VaultComponent implements OnInit, OnDestroy { return; } + // Allow bulk deleting of Unassigned Items + const unassignedCiphers: string[] = []; + const assignedCiphers: string[] = []; + + ciphers.map((c) => { + if (c.isUnassigned) { + unassignedCiphers.push(c.id); + } else { + assignedCiphers.push(c.id); + } + }); + if (ciphers.length === 0 && collections.length === 0) { this.platformUtilsService.showToast("error", null, this.i18nService.t("nothingSelected")); return; @@ -1117,8 +1174,11 @@ export class VaultComponent implements OnInit, OnDestroy { collections.every((c) => c.canDelete(organization, this.flexibleCollectionsV1Enabled)); const canDeleteCiphers = ciphers == null || - this.organization.allowAdminAccessToAllCollectionItems || - ciphers.every((c) => c.edit); + ciphers.every((c) => c.edit) || + this.organization.canEditAllCiphers( + this.flexibleCollectionsV1Enabled, + this.restrictProviderAccessEnabled, + ); if (this.flexibleCollectionsV1Enabled && (!canDeleteCiphers || !canDeleteCollections)) { this.showMissingPermissionsError(); @@ -1128,9 +1188,10 @@ export class VaultComponent implements OnInit, OnDestroy { const dialog = openBulkDeleteDialog(this.dialogService, { data: { permanent: this.filter.type === "trash", - cipherIds: ciphers.map((c) => c.id), + cipherIds: assignedCiphers, collections: collections, organization, + unassignedCiphers, }, }); @@ -1327,11 +1388,12 @@ export class VaultComponent implements OnInit, OnDestroy { }); } - protected deleteCipherWithServer(id: string, permanent: boolean) { - const asAdmin = this.organization?.canEditAllCiphers( - this.flexibleCollectionsV1Enabled, - this.restrictProviderAccessEnabled, - ); + protected deleteCipherWithServer(id: string, permanent: boolean, isUnassigned: boolean) { + const asAdmin = + this.organization?.canEditAllCiphers( + this.flexibleCollectionsV1Enabled, + this.restrictProviderAccessEnabled, + ) || isUnassigned; return permanent ? this.cipherService.deleteWithServer(id, asAdmin) : this.cipherService.softDeleteWithServer(id, asAdmin); diff --git a/apps/web/src/app/vault/settings/purge-vault.component.html b/apps/web/src/app/vault/settings/purge-vault.component.html index 485e64617e2..407e0a39ad1 100644 --- a/apps/web/src/app/vault/settings/purge-vault.component.html +++ b/apps/web/src/app/vault/settings/purge-vault.component.html @@ -1,38 +1,19 @@ - +
+ + +

+ {{ (organizationId ? "purgeOrgVaultDesc" : "purgeVaultDesc") | i18n }} +

+ {{ "purgeVaultWarning" | i18n }} + +
+ + + + +
+
diff --git a/apps/web/src/app/vault/settings/purge-vault.component.ts b/apps/web/src/app/vault/settings/purge-vault.component.ts index 4ef9e20e2a1..869cbaab1b4 100644 --- a/apps/web/src/app/vault/settings/purge-vault.component.ts +++ b/apps/web/src/app/vault/settings/purge-vault.component.ts @@ -1,55 +1,60 @@ -import { Component, Input } from "@angular/core"; +import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog"; +import { Component, Inject } from "@angular/core"; +import { FormControl, FormGroup } from "@angular/forms"; import { Router } from "@angular/router"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { Verification } from "@bitwarden/common/auth/types/verification"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; +import { DialogService } from "@bitwarden/components"; + +export interface PurgeVaultDialogData { + organizationId: string; +} @Component({ selector: "app-purge-vault", templateUrl: "purge-vault.component.html", }) export class PurgeVaultComponent { - @Input() organizationId?: string = null; + organizationId: string = null; - masterPassword: Verification; - formPromise: Promise; + formGroup = new FormGroup({ + masterPassword: new FormControl(null), + }); constructor( + @Inject(DIALOG_DATA) protected data: PurgeVaultDialogData, + private dialogRef: DialogRef, private apiService: ApiService, private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private userVerificationService: UserVerificationService, private router: Router, - private logService: LogService, private syncService: SyncService, - ) {} + ) { + this.organizationId = data && data.organizationId ? data.organizationId : null; + } - async submit() { - try { - this.formPromise = this.userVerificationService - .buildRequest(this.masterPassword) - .then((request) => this.apiService.postPurgeCiphers(request, this.organizationId)); - await this.formPromise; - this.platformUtilsService.showToast("success", null, this.i18nService.t("vaultPurged")); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.syncService.fullSync(true); - if (this.organizationId != null) { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["organizations", this.organizationId, "vault"]); - } else { - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.router.navigate(["vault"]); - } - } catch (e) { - this.logService.error(e); + submit = async () => { + const response = this.userVerificationService + .buildRequest(this.formGroup.value.masterPassword) + .then((request) => this.apiService.postPurgeCiphers(request, this.organizationId)); + await response; + this.platformUtilsService.showToast("success", null, this.i18nService.t("vaultPurged")); + await this.syncService.fullSync(true); + if (this.organizationId != null) { + await this.router.navigate(["organizations", this.organizationId, "vault"]); + } else { + await this.router.navigate(["vault"]); } + this.dialogRef.close(); + }; + + static open(dialogService: DialogService, config?: DialogConfig) { + return dialogService.open(PurgeVaultComponent, config); } } diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index e26099610cd..bc401e2de44 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Genereer ’n e-posalias met ’n eksterne aanstuurdiens." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Gasheernaam", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Verleen toegang tot versamelings deur dit tot hierdie groep toe te voeg." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Kies groepe" }, - "userPermissionOverrideHelper": { - "message": "Ingestelde toestemmings vir ’n lid sal toestemmings deur daardie lid se groep vervang" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Geen lede of groepe toegevoeg" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Werk u enkripsie-instellings by om aan die nuwe beveiligingsaanbevelings te voldoen en die beskerming van u rekening te verbeter." }, - "changeKdfLoggedOutWarning": { - "message": "As u voortgaan word u uit alle aktiewe sessies geteken. U sal weer aan moet teken en tweestapwaarmerking moet voltooi. Om dataverlies te voorkom, beveel ons aan dat u u kluis uitstuur alvorens u u enkripsie-instellings verander." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Geheimebestuurder" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 018acea8f2a..7f63cfaf24c 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "اسم المضيف", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 457e0c6e1f8..26d9ec8d075 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Abunəliyinizə edilən düzəlişlər, faktura cəminizdə nisbətli dəyişikliklərlə nəticələnəcək. Yeni dəvət edilən istifadəçilər abunəlik yerlərini aşsa, əlavə istifadəçilər üçün nisbətli ödəniş dərhal alınacaq." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Paket təklifi olmayan əlavə yerlər" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "əlavə etmək istəyirsinizsə, lütfən əlaqə saxlayın" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Abunəliyinizə edilən düzəlişlər, faktura cəminizdə nisbətli dəyişikliklərlə nəticələnəcək. Yeni dəvət edilən istifadəçilər abunəlik yerlərini aşsa, $MAX$ yer limitinə çatana qədər əlavə istifadəçilər üçün nisbətli ödəniş dərhal alınacaq.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Xarici yönləndirmə xidməti ilə e-poçt ləqəbi yaradın." }, + "forwarderError": { + "message": "$SERVICENAME$ xətası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Veb sayt: $WEBSITE$. Bitwarden tərəfindən yaradılıb.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Yararsız $SERVICENAME$ API jetonu", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Yararsız $SERVICENAME$ API jetonu: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ maskalı e-poçt hesab kimliyi alına bilmir.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Yararsız $SERVICENAME$ domeni.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Yararsız $SERVICENAME$ url-si.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Bilinməyən $SERVICENAME$ xətası baş verdi.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Bilinməyən yönləndirici: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Host adı", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Bu qrupa əlavə edərək kolleksiyalara müraciət icazəsi verin." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Yalnız idarə etdiyiniz kolleksiyaları təyin edə bilərsiniz." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Qrupları seç" }, - "userPermissionOverrideHelper": { - "message": "Bir üzv üçün ayarlanan icazələr, həmin üzvün qrupu tərəfindən ayarlanan icazələri əvəz edəcək" + "userPermissionOverrideHelperDesc": { + "message": "Bir üzv üçün ayarlanan icazələr, həmin üzvün qrupu tərəfindən ayarlanan icazələri əvəz edəcək." }, "noMembersOrGroupsAdded": { "message": "Heç bir üzv və ya qrup əlavə edilmədi" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Yeni güvənlik tövsiyələrini qarşılamaq və hesab qorumasını təkmilləşdirmək üçün şifrələmə ayarlarınızı güncəlləyin." }, - "changeKdfLoggedOutWarning": { - "message": "Proses, bütün aktiv seanslardan çıxış etməyinizi təmin edəcək. Təkrar giriş etməyiniz və iki addımlı giriş quraşdırmasını tamamlamağınız lazımdır. Məlumat itkisinin qarşısını almaq üçün şifrələmə ayarlarınızı dəyişdirməzdən əvvəl anbarınızı xaricə köçürməyinizi tövsiyə edirik." + "kdfSettingsChangeLogoutWarning": { + "message": "Proses, bütün aktiv seanslardan çıxış etməyinizi təmin edəcək. Təkrar giriş etməyiniz və əgər varsa iki addımlı girişi tamamlamağınız lazımdır. Məlumat itkisinin qarşısını almaq üçün şifrələmə ayarlarınızı dəyişdirməzdən əvvəl anbarınızı xaricə köçürməyinizi tövsiyə edirik." }, "secretsManager": { "message": "Sirr Meneceri" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Bu kolleksiyanı idarə etmək üçün müraciətiniz yoxdur." }, + "grantAddAccessCollectionWarningTitle": { + "message": "İdarə edə bilər icazələri əskikdir" + }, + "grantAddAccessCollectionWarning": { + "message": "Kolleksiyanın silinməsi daxil olmaqla tam kolleksiya idarəetməsinə icazə vermək üçün \"İdarə edə bilər\" icazələrini verin." + }, "grantCollectionAccess": { "message": "Qrup və ya üzvlərin bu kolleksiyaya müraciətinə icazə verin." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Uğurlu" }, - "viewCollection": { - "message": "Kolleksiyaya bax" - }, "restrictedGroupAccess": { "message": "Özünüzü qruplara əlavə edə bilməzsiniz." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Özünüzü kolleksiyalara əlavə edə bilməzsiniz." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Fakturanı \"Provayder Portalı\"ndan idarə et" + }, + "viewInfo": { + "message": "Məlumata bax" + }, + "viewAccess": { + "message": "Müraciətə bax" + }, + "noCollectionsSelected": { + "message": "Heç bir kolleksiya seçməmisiniz." + }, + "updateName": { + "message": "Adı güncəllə" + }, + "updatedOrganizationName": { + "message": "Təşkilat adı güncəlləndi" + }, + "providerPlan": { + "message": "İdarə edilən Xidmət Provayderi" + }, + "orgSeats": { + "message": "Təşkilat yerləri" + }, + "providerDiscount": { + "message": "$AMOUNT$% Endirim", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "İnfrastrukturunuzu qoruyun" + }, + "protectYourFamilyOrBusiness": { + "message": "Ailənizi və ya işinizi qoruyun" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "İzləmə hesabatları ilə təhlükəsizlik boşluqlarını bağlayın" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Təkmil izləmə üçün ödənişli plana yüksəldərək təhlükəsizlik üzrə zəif nöqtələri qabaqlayın." } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 24c92511eaa..e9e125fbddc 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць месцаў у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць месцаў у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў, пакуль не будзе дасягнута абмежаванне (максімальная колькасць месцаў: $MAX$).", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Генерыраваць псеўданім электроннай пошты са знешнім сэрвісам перасылкі." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Назва вузла", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Забяспечыць доступ да калекцый, дадаўшы іх у гэту групу." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Выбраць групы" }, - "userPermissionOverrideHelper": { - "message": "Дазволы прызначаныя для ўдзельніка, заменяць дазволы, якія прызначаны групай гэтага ўдзельніка" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Няма дададзены ўдзельнікі або групы" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Абнавіце свае налады шыфравання, каб адпавядаць новым рэкамендацыям бяспекі і палепшыць абарону ўліковага запісу." }, - "changeKdfLoggedOutWarning": { - "message": "Калі вы працягніце, то гэта прывядзе да выхаду з усіх актыўных сеансаў. Вам неабходна будзе паўторна выканаць уваход і прайсці двухэтапную праверку. Перад зменай наладаў шыфравання мы рэкамендуем экспартаваць ваша сховішча, каб прадухіліць магчымую страту даных." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Менеджар сакрэтаў" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index b9c8890219e..d8b35e1ab97 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Промените в абонамента Ви ще предизвикат пропорционални промени в сумата, която плащате. Ако новопоканените потребители превишат ограничението на абонамента Ви, незабавно ще получите съответстващо пропорционално задължение за допълнителните потребители." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Ако искате да добавите допълнителни" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "места без да ползвате пакетното предложение, свържете се с нас" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Промените в абонамента Ви ще предизвикат пропорционални промени в сумата, която плащате. Ако новопоканените потребители превишат ограничението на абонамента Ви, незабавно ще получите съответстващо пропорционално задължение за допълнителните потребители, докато не бъде достигнато ограничението от $MAX$ потребители.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "Грешка от $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Уебсайт: $WEBSITE$. Създадено от Битуорден.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неправилен идентификатор за ППИ на $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не може да бъде получен идентификатор на маскиран чрез е-поща акаунт от $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Неправилен домейн за $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Неправилен адрес на $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Възникна неочаквана грешка свързана с $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестна пренасочваща услуга: „$SERVICENAME$“.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име на сървъра", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Дайте достъп до колекциите, като ги добавите към тази група." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Можете да свързвате само колекции, които имате право да управлявате." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Изберете групи" }, - "userPermissionOverrideHelper": { - "message": "Правата дадени на един член ще заменят правата дадени му от неговата група" + "userPermissionOverrideHelperDesc": { + "message": "Правата дадени на един член ще заменят правата дадени му от неговата група." }, "noMembersOrGroupsAdded": { "message": "Няма добавени членове или групи" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Променете настройките си за шифроване, така че да отговарят на новите препоръки за сигурността и да подобрите защитата на регистрацията си." }, - "changeKdfLoggedOutWarning": { - "message": "Ако продължите, ще излезете от всички активни сесии. Ще трябва да се впишете отново и да завършите настройката на двустепенното удостоверяване. Препоръчително е да изнесете трезора си преди да променяте настройките за шифроване, за да избегнете загуба на данни." + "kdfSettingsChangeLogoutWarning": { + "message": "Ако продължите, ще излезете от всички активни сесии. Ще трябва да се впишете отново и да извършите двустепенно удостоверяване, ако такова е настроено. Препоръчително е да изнесете трезора си преди да променяте настройките за шифроване, за да избегнете загуба на данни." }, "secretsManager": { "message": "Управление на тайни" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Нямате достъп за управление на тази колекция." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Липсват правомощия за управление" + }, + "grantAddAccessCollectionWarning": { + "message": "Дайте правомощия за управление, за да позволите пълното управление на колекции, включително изтриването им." + }, "grantCollectionAccess": { "message": "Дайте права на групи и членове до тази колекция." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Успех" }, - "viewCollection": { - "message": "Преглед на колекцията" - }, "restrictedGroupAccess": { "message": "Не може да добавяте себе си към групи." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Не може да добавяте себе си към колекции." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Управление на плащанията от Портала за доставчици" + }, + "viewInfo": { + "message": "Преглед на информацията" + }, + "viewAccess": { + "message": "Преглед на достъпа" + }, + "noCollectionsSelected": { + "message": "Не сте избрали нито една колекция." + }, + "updateName": { + "message": "Промяна на името" + }, + "updatedOrganizationName": { + "message": "Името на организацията е променено" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Места в организацията" + }, + "providerDiscount": { + "message": "$AMOUNT$% отстъпка", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Подсигурете инфраструктурата си" + }, + "protectYourFamilyOrBusiness": { + "message": "Защитете семейството или бизнеса си" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Отстранете пропуските в сигурността с докладите за наблюдение" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Не допускайте уязвимост в сигурността си като надградите до платен план с подобрено наблюдение." } } diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index ff1d1d7af5b..800061e3cfb 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index 7c78284cec4..665ebfdc6fb 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 0542b36e29a..fc1c53edafc 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Els ajustos a la vostra subscripció donaran lloc a canvis prorratejats als vostres totals de facturació. Si els nous usuaris convidats superen les vostres places de subscripció, rebreu immediatament un càrrec prorratejat pels usuaris addicionals." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Els ajustos a la vostra subscripció donaran lloc a canvis prorratejats en els vostres totals de facturació. Si els usuaris recentment convidats excedeixen les vostres places de subscripció, rebreu immediatament un càrrec previst dels usuaris addicionals fins que s'aconseguisca arribar al vostre límit de places ($MAX$).", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Genera un àlies de correu electrònic amb un servei de reenviament extern." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom de l'amfitrió", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Doneu accés a les col·leccions afegint-les a aquest grup." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Només podeu assignar col·leccions que gestioneu." + "restrictedCollectionAssignmentDesc": { + "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { "message": "Doneu accés a totes les col·leccions actuals i futures." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Selecciona grups" }, - "userPermissionOverrideHelper": { - "message": "Els permisos establerts per a un membre substituiran els permisos establerts pel grup d'aquest membre" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No s'han afegit membres ni grups" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Actualitzeu la configuració d'encriptació per complir les noves recomanacions de seguretat i millorar la protecció del compte." }, - "changeKdfLoggedOutWarning": { - "message": "Si continueu, tancareu totes les sessions actives. Haureu de tornar a iniciar sessió i completar la configuració d'inici de sessió en dos passos. Recomanem que exporteu la caixa forta abans de canviar la configuració d'encriptació per evitar la pèrdua de dades." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Administrador de secrets" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "No teniu accés per gestionar aquesta col·lecció." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Concedeix als grups o membres l'accés a aquesta col·lecció." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Èxit" }, - "viewCollection": { - "message": "Mostra col·lecció" - }, "restrictedGroupAccess": { "message": "No podeu afegir-vos als grups." }, - "restrictedCollectionAccess": { - "message": "No podeu afegir-vos a les col·leccions." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Assigna" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Gestioneu la facturació des del portal de proveïdors" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index cdaa76774e8..6d598b27e69 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Úpravy Vašeho předplatného budou mít za následek poměrné změny Vašich fakturačních součtů. Pokud počet nově pozvaných členů překročí počet členů v předplatném, bude Vám okamžitě doúčtován poměrný poplatek za další členy." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Pokud chcete přidat další" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "uživatele bez hromadné nabídky, kontaktujte" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Úpravy Vašeho předplatného budou mít za následek poměrné změny Vašich fakturačních součtů. Pokud počet nově pozvaných členů překročí počet členů v předplatném, bude Vám okamžitě doúčtován poměrný poplatek za další členy dokud nebude dosaženo maximálního limitu: $MAX$.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Vygeneruje alias e-mailu pomocí externí přeposílací služby." }, + "forwarderError": { + "message": "Chyba $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webová stránka: $WEBSITE$. Vygenerováno Bitwardenem.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Neplatný token API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Neplatný token API $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nelze získat maskované ID e-mailového účtu $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Neplatná doména $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Neplatné URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Došlo k neznámé chybě $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Neznámý přeposílatel: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Název hostitele", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Udělí členům přístup ke kolekcím přidáním do této skupiny." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Můžete přiřadit jen Vámi spravované kolekce." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Zvolte skupiny" }, - "userPermissionOverrideHelper": { - "message": "Oprávnění nastavená pro člena nahradí oprávnění nastavená skupinou tohoto člena" + "userPermissionOverrideHelperDesc": { + "message": "Oprávnění nastavená pro člena nahradí oprávnění nastavená skupinou tohoto člena." }, "noMembersOrGroupsAdded": { "message": "Nebyli přidáni žádní členové ani skupiny" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Aktualizujte své nastavení šifrování tak, aby splňovalo nová bezpečnostní doporučení a zlepšilo ochranu účtu." }, - "changeKdfLoggedOutWarning": { - "message": "Pokračováním se odhlásíte ze všech aktivních relací. Budete se muset znovu přihlásit a dokončit nastavení dvoufázového přihlášení. Před změnou nastavení šifrování doporučujeme exportovat trezor, aby nedošlo ke ztrátě dat." + "kdfSettingsChangeLogoutWarning": { + "message": "Pokračováním se odhlásíte ze všech aktivních relací. Budete se muset znovu přihlásit a dokončit nastavení dvoufázového přihlášení, pokud nějaké máte. Před změnou nastavení šifrování doporučujeme exportovat trezor, aby nedošlo ke ztrátě dat." }, "secretsManager": { "message": "Správce tajných klíčů" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Nemáte přístup ke správě této kolekce." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Chybějící oprávnění \"Může spravovat\"" + }, + "grantAddAccessCollectionWarning": { + "message": "Udělte oprávnění \"Může spravovat\" pro úplnou správu kolekce, včetně jejího smazání." + }, "grantCollectionAccess": { "message": "Udělí skupinám nebo členům přístup k této kolekci." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Úspěch" }, - "viewCollection": { - "message": "Zobrazit kolekci" - }, "restrictedGroupAccess": { "message": "Do skupin nemůžete přidat sami sebe." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Do kolekcí nemůžete přidat sami sebe." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Spravovat fakturaci z portálu poskytovatele" + }, + "viewInfo": { + "message": "Zobrazit informace" + }, + "viewAccess": { + "message": "Zobrazit přístup" + }, + "noCollectionsSelected": { + "message": "Nevybrali jste žádné kolekce." + }, + "updateName": { + "message": "Aktualizovat název" + }, + "updatedOrganizationName": { + "message": "Aktualizovaný název organizace" + }, + "providerPlan": { + "message": "Spravovaný poskytovatel služby" + }, + "orgSeats": { + "message": "Počet uživatelů v organizaci" + }, + "providerDiscount": { + "message": "Sleva $AMOUNT$ %", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Zabezpečte Vaši infrastrukturu" + }, + "protectYourFamilyOrBusiness": { + "message": "Ochraňte svou rodinu nebo byznys" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Odeberte bezpečnostní nedostatky pomocí monitorovacích zpráv" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Přechodem na placený plán rozšířeného monitorování získáte náskok před zranitelnostmi zabezpečení." } } diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 3e206c23b1c..020932e2ec0 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 0e9ff6921e4..3d591f919d7 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Abonnementsjusteringer vil resultere i forholdsmæssige ændringer af dine faktureringstotaler. Overstiger antal nyligt inviterede brugere abonnementskvoten, modtager du straks en forholdsmæssig opkrævning for de ekstra brugere." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Ønskes der tilføjet yderligere" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "pladser uden pakketilbuddet, kontakt venligst" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Abonnementsjusteringer vil resultere i forholdsmæssige ændringer af dine faktureringstotaler. Overstiger antal nyligt inviterede brugere abonnementskvoten, modtager du straks en forholdsmæssig opkrævning for de ekstra brugere, indtil pladskvoten på $MAX$ er nået.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generér et e-mail alias med en ekstern viderestillingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$-fejl: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Websted: $WEBSITE$. Genereret af Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Ugyldigt $SERVICENAME$ API-token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Ugyldigt $SERVICENAME$ API-token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Kan ikke få $SERVICENAME$ maskeret e-mailkonto-ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ugyldigt $SERVICENAME$-domæne.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ugyldig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ukendt $SERVICENAME$-fejl opstod.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ukendt videresender: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Værtsnavn", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Tildel adgang til samlinger ved at føje dem til denne gruppe." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Der kan kun tildeles samlinger, man selv håndterer." + "restrictedCollectionAssignmentDesc": { + "message": "Man kan kun tildele samlinger, man selv håndterer." }, "accessAllCollectionsDesc": { "message": "Tildel adgang til alle nuværende og fremtidige samlinger." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Vælg grupper" }, - "userPermissionOverrideHelper": { - "message": "Tilladelser angivet for et medlem vil erstatte tilladelser angivet af medlemmets gruppe" + "userPermissionOverrideHelperDesc": { + "message": "Tilladelser angivet for et medlem vil erstatte tilladelser angivet af medlemmets gruppe." }, "noMembersOrGroupsAdded": { "message": "Ingen medlemmer eller grupper tilføjet" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Opdatér krypteringsindstillingerne for at opfylde nye sikkerhedsanbefalinger og forbedre kontobeskyttelsen." }, - "changeKdfLoggedOutWarning": { - "message": "Fortsættes, logges man ud af alle aktive sessioner. Man vil skulle logge ind igen og færdiggøre opsætningen af totrinsindlogning. For at forhindre datatab anbefales det, at boksen eksporteres, inden krypteringsindstillingerne ændres." + "kdfSettingsChangeLogoutWarning": { + "message": "Fortsættes, logges alle aktive sessioner af. Man vil skulle logge ind igen og færdiggøre opsætningen af totrinsindlogning. Eksport af boksen inden krypteringsindstillingerne ændres anbefales for at forhindre datatab." }, "secretsManager": { "message": "Hemmelighedshåndtering" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Du har ikke adgang til at håndtere denne samling." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Manglende Kan håndtere tilladelser" + }, + "grantAddAccessCollectionWarning": { + "message": "Tildel Kan håndtere tilladelser for at tillade fuld samlingshåndtering, herunder sletning af samling." + }, "grantCollectionAccess": { "message": "Tildel grupper eller medlemmer adgang til denne samling." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Gennemført" }, - "viewCollection": { - "message": "Vis samling" - }, "restrictedGroupAccess": { "message": "Man kan ikke føje sig selv til grupper." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Man kan ikke føje sig selv til samlinger." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Håndter fakturering via udbyderportalen" + }, + "viewInfo": { + "message": "Se info" + }, + "viewAccess": { + "message": "Se adgang" + }, + "noCollectionsSelected": { + "message": "Der er ikke valgt nogen samlinger." + }, + "updateName": { + "message": "Opdatér navn" + }, + "updatedOrganizationName": { + "message": "Opdateret organisationsnavn" + }, + "providerPlan": { + "message": "Administreret Tjenesteudbyder" + }, + "orgSeats": { + "message": "Organisationspladser" + }, + "providerDiscount": { + "message": "$AMOUNT$% rabat", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Sikr infrastrukturen" + }, + "protectYourFamilyOrBusiness": { + "message": "Beskyt familien eller virksomheden" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Luk sikkerhedshuller med monitoreringsrapporter" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Vær opdateret mod sikkerhedssårbarheder ved at opgradere til en betalt abonnementstype for forbedret monitorering." } } diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index 357abc5de2b..d33f03ffe2a 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Anpassungen an deinem Abonnement führen zu anteiligen Änderungen an deiner Rechnungssumme. Wenn neu eingeladene Benutzer deine Abonnement-Benutzerplätze überschreiten, wird dir sofort eine anteilige Gebühr für die zusätzlichen Benutzer berechnet." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Anpassungen an deinem Abonnement führen zu anteiligen Änderungen an deiner Rechnungssumme. Wenn neu eingeladene Benutzer deine Abo-Benutzerplätze überschreiten, wird dir sofort eine anteilige Gebühr für die zusätzlichen Benutzer berechnet, bis dein Benutzerlimit von $MAX$ erreicht ist.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generiere ein E-Mail-Alias mit einem externen Weiterleitungsdienst." }, + "forwarderError": { + "message": "$SERVICENAME$ Fehler: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Von Bitwarden generiert.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generiert von Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Ungültiger API-Token von $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Ungültiger API-Token von $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Maskierte E-Mail-Konto-ID für $SERVICENAME$ konnte nicht abgerufen werden.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ungültige $SERVICENAME$-Domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ungültige $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unbekannter $SERVICENAME$-Fehler aufgetreten.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unbekannter Weiterleitungsdienst: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Gewähre Zugriff auf Sammlungen, indem du diese zu dieser Gruppe hinzufügst." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Du kannst nur von dir verwaltete Sammlungen zuweisen." + "restrictedCollectionAssignmentDesc": { + "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { "message": "Gewähre Zugriff auf alle aktuellen und zukünftigen Sammlungen." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Gruppen auswählen" }, - "userPermissionOverrideHelper": { - "message": "Gesetzte Berechtigungen für ein Mitglied ersetzen dessen gesetzte Mitgliedergruppe-Berechtigungen" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Keine Mitglieder oder Gruppen hinzugefügt" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Aktualisiere deine Verschlüsselungseinstellungen, um neue Sicherheitsempfehlungen zu erfüllen und den Kontoschutz zu verbessern." }, - "changeKdfLoggedOutWarning": { - "message": "Wenn du fortfährst, wirst du von allen aktiven Sitzungen abgemeldet. Du musst dich erneut anmelden und die Zwei-Faktor-Authentifizierung durchführen. Wir empfehlen, deinen Tresor zu exportieren, bevor du deine Verschlüsselungseinstellungen änderst, um Datenverluste zu vermeiden." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Du hast keinen Zugriff zur Verwaltung dieser Sammlung." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Gewähre Gruppen oder Mitgliedern Zugriff auf diese Sammlung." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Erfolg" }, - "viewCollection": { - "message": "Sammlung anzeigen" - }, "restrictedGroupAccess": { "message": "Du kannst dich nicht selbst zu Gruppen hinzufügen." }, - "restrictedCollectionAccess": { - "message": "Du kannst dich nicht selbst zu Sammlungen hinzufügen." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Zuweisen" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Rechnungen über das Anbieter-Portal verwalten" + }, + "viewInfo": { + "message": "Info anzeigen" + }, + "viewAccess": { + "message": "Zugriff anzeigen" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Namen aktualisieren" + }, + "updatedOrganizationName": { + "message": "Aktualisierter Organisationsname" + }, + "providerPlan": { + "message": "Verwalteter Dienstanbieter" + }, + "orgSeats": { + "message": "Benutzerplätze der Organisation" + }, + "providerDiscount": { + "message": "$AMOUNT$% Rabatt", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Sicherheitslücken durch Kontrollberichte schließen" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Schütze dich vor Sicherheitsschwachstellen, indem du ein kostenpflichtiges Abo für eine verbesserte Sicherheitskontrolle abschließt." } } diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 332ec7c72af..0a84ca3f07b 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Οι προσαρμογές της συνδρομής σας θα έχουν ως αποτέλεσμα αλλαγές στα σύνολα τιμολόγησης. Εάν οι νεοπροσκεκλημένοι χρήστες υπερβούν τις συνδρομητικές σας θέσεις, θα λάβετε αμέσως μια αναθεωρημένη χρέωση για τους πρόσθετους χρήστες." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Οι προσαρμογές της συνδρομής σας θα έχουν ως αποτέλεσμα αλλαγές στα σύνολα τιμολόγησης. Εάν οι νεοπροσκεκλημένοι χρήστες υπερβούν τις θέσεις συνδρομής, θα λάβετε αμέσως μια τροποποιημένη χρέωση για τους επιπλέον χρήστες μέχρι να συμπληρωθεί το όριο θέσης $MAX$ σας.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index d308acaaa81..e79497d25e4 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -1710,11 +1710,11 @@ "twoFactorDuoDesc": { "message": "Enter the Bitwarden application information from your Duo Admin panel." }, - "twoFactorDuoIntegrationKey": { - "message": "Integration key" + "twoFactorDuoClientId": { + "message": "Client Id" }, - "twoFactorDuoSecretKey": { - "message": "Secret key" + "twoFactorDuoClientSecret": { + "message": "Client Secret" }, "twoFactorDuoApiHostname": { "message": "API hostname" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -6588,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6822,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -7749,7 +7755,7 @@ "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8217,10 +8223,22 @@ } } }, + "lowKDFIterationsBanner": { + "message": "Low KDF iterations. Increase your iterations to improve the security of your account." + }, + "changeKDFSettings": { + "message": "Change KDF settings" + }, "secureYourInfrastructure": { "message": "Secure your infrastructure" }, "protectYourFamilyOrBusiness": { "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index 5fc7b328bae..378e8475893 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in pro-rated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a pro-rated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in pro-rated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a pro-rated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index be655448a81..dc9bb0a37ec 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index cc599c2965e..74b83f74684 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Domajna nomo", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 5edaab44cac..828d6999a64 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -2789,10 +2789,10 @@ "message": "Todo" }, "addAccess": { - "message": "Add Access" + "message": "Añadir acceso" }, "addAccessFilter": { - "message": "Add Access Filter" + "message": "Añadir filtro de acceso" }, "refresh": { "message": "Actualizar" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Los ajustes a su suscripción provocarán cambios prorrateados en su facturación total. Si los usuarios recién invitados exceden sus asientos de suscripción, recibirá inmediatamente un cargo prorrateado para los usuarios adicionales." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Los ajustes a su suscripción provocarán cambios prorrateados en su facturación total. Si los usuarios recién invitados exceden sus asientos de suscripción, recibirás inmediatamente un cargo prorrateado para los usuarios adicionales hasta que alcances tu límite de $MAX$ asientos.", "placeholders": { @@ -4913,7 +4919,7 @@ "message": "Error" }, "accountRecoveryManageUsers": { - "message": "Manage users must also be granted with the manage account recovery permission" + "message": "El permiso \"gestionar usuarios\" también debe ser otorgado junto con el permiso \"gestionar cuenta\"" }, "setupProvider": { "message": "Configurador del proveedor" @@ -5236,7 +5242,7 @@ "message": "Validar certificado" }, "spUniqueEntityId": { - "message": "Set a unique SP entity ID" + "message": "Configurar un ID único de Service Provider" }, "spUniqueEntityIdDesc": { "message": "Genera un identificador único para su organización" @@ -5441,7 +5447,7 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpAnchor": { - "message": "require single sign-on authentication policy", + "message": "Requiere de la política de autenticación vía single sign-on", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpEnd": { @@ -5458,11 +5464,11 @@ "message": "Conector de claves" }, "memberDecryptionKeyConnectorDescStart": { - "message": "Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The", + "message": "Enlaza tu acceso con SSO a tu propio servidor de des-encriptación. Utilizando esta opción, los usuarios no tendrán que usar sus contraseñas maestras para desencriptar los datos de la caja fuerte.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The require SSO authentication and single organization policies are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.'" }, "memberDecryptionKeyConnectorDescLink": { - "message": "require SSO authentication and single organization policies", + "message": "requiere de autenticación vía SSO y políticas de organización.", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Connect login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their master passwords to decrypt vault data. The require SSO authentication and single organization policies are required to set up Key Connector decryption. Contact Bitwarden Support for set up assistance.'" }, "memberDecryptionKeyConnectorDescEnd": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generar un alias de correo electrónico mediante un servicio de reenvío externo." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nombre del host", "description": "Part of a URL." @@ -5981,13 +6089,13 @@ "message": "Activado" }, "off": { - "message": "Off" + "message": "Apagado" }, "members": { "message": "Miembros" }, "reporting": { - "message": "Informando" + "message": "Auditoría" }, "numberOfUsers": { "message": "Número de usuarios" @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Conceder acceso a las colecciones añadiéndolas a este grupo." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6679,25 +6787,25 @@ "message": "Verification required for this action. Set a PIN to continue." }, "setPin": { - "message": "Set PIN" + "message": "Configurar PIN" }, "verifyWithBiometrics": { - "message": "Verify with biometrics" + "message": "Verificar con biometría" }, "awaitingConfirmation": { - "message": "Awaiting confirmation" + "message": "Esperando confirmación" }, "couldNotCompleteBiometrics": { - "message": "Could not complete biometrics." + "message": "No se ha podido configurar el acceso biométrico." }, "needADifferentMethod": { - "message": "Need a different method?" + "message": "¿Necesita un método distinto?" }, "useMasterPassword": { - "message": "Use master password" + "message": "Utilizar contraseña maestra" }, "usePin": { - "message": "Use PIN" + "message": "Utilizar PIN" }, "useBiometrics": { "message": "Use biometrics" @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Seleccionar grupos" }, - "userPermissionOverrideHelper": { - "message": "Los permisos establecidos para un miembro reemplazarán los permisos establecidos por el grupo de ese miembro" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Ningún miembro o grupo añadido" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Actualice sus ajustes de cifrado para cumplir con las nuevas recomendaciones de seguridad y mejorar la protección de la cuenta." }, - "changeKdfLoggedOutWarning": { - "message": "Al continuar, saldrá de todas las sesiones activas. Deberá volver a iniciar sesión y completar la configuración de inicio de sesión en dos pasos. Le recomendamos que exporte su caja fuerte antes de cambiar la configuración de cifrado para evitar la pérdida de datos." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Administrador de secretos" @@ -7356,16 +7464,16 @@ "message": "For engineering and DevOps teams to manage secrets throughout the software development lifecycle." }, "free2PersonOrganization": { - "message": "Free 2-person Organizations" + "message": "Organizaciones gratis de 2-personas" }, "unlimitedSecrets": { - "message": "Unlimited secrets" + "message": "Secretos ilimitados" }, "unlimitedProjects": { - "message": "Unlimited projects" + "message": "Proyectos ilimitados" }, "projectsIncluded": { - "message": "$COUNT$ projects included", + "message": "incluído(s) $COUNT$ proyecto(s)", "placeholders": { "count": { "content": "$1", @@ -7374,7 +7482,7 @@ } }, "serviceAccountsIncluded": { - "message": "$COUNT$ service accounts included", + "message": "$COUNT$ cuenta(s) de servicio incluida(s)", "placeholders": { "count": { "content": "$1", @@ -7383,7 +7491,7 @@ } }, "additionalServiceAccountCost": { - "message": "$COST$ per month for additional service accounts", + "message": "$COST$ al mes por cuenta de servicio adicional", "placeholders": { "cost": { "content": "$1", @@ -7452,28 +7560,28 @@ "message": "Set a limit for your service accounts. Once this limit is reached, you will not be able to create new service accounts." }, "serviceAccountLimit": { - "message": "Service account limit (optional)" + "message": "Límite de cuenta de servicio (opcional)" }, "maxServiceAccountCost": { "message": "Max potential service account cost" }, "loggedInExclamation": { - "message": "Logged in!" + "message": "¡Ha iniciado sesión!" }, "beta": { "message": "Beta" }, "assignCollectionAccess": { - "message": "Assign collection access" + "message": "Asignar acceso a colecciones" }, "editedCollections": { - "message": "Edited collections" + "message": "Colecciones modificadas" }, "baseUrl": { - "message": "Server URL" + "message": "URL del servidor" }, "aliasDomain": { - "message": "Alias domain" + "message": "Dominio alias" }, "alreadyHaveAccount": { "message": "¿Ya tienes una cuenta?" @@ -7507,22 +7615,22 @@ "description": "This is followed a by a hyperlink to the help website." }, "installBrowserExtension": { - "message": "Install browser extension" + "message": "Instalar extensión del navegador" }, "installBrowserExtensionDetails": { "message": "Use the extension to quickly save logins and auto-fill forms without opening the web app." }, "projectAccessUpdated": { - "message": "Project access updated" + "message": "Actualizada la configuración de acceso del projecto" }, "unexpectedErrorSend": { - "message": "An unexpected error has occurred while loading this Send. Try again later." + "message": "Ha ocurrido un error inesperado tratando de cargar este Envío. Por favor pruebe más tarde." }, "seatLimitReached": { - "message": "Seat limit has been reached" + "message": "Se ha alcanzado el límite de licencias" }, "contactYourProvider": { - "message": "Contact your provider to purchase additional seats." + "message": "Contacte con su proveedor para adquirir licencias adicionales." }, "seatLimitReachedContactYourProvider": { "message": "Seat limit has been reached. Contact your provider to purchase additional seats." @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7571,10 +7685,10 @@ "message": "Learn more about collection management" }, "organizationInformation": { - "message": "Organization information" + "message": "Información de la Organización" }, "confirmationDetails": { - "message": "Confirmation details" + "message": "Detalles de la confirmación" }, "smFreeTrialThankYou": { "message": "Thank you for signing up for Bitwarden Secrets Manager!" @@ -7583,7 +7697,7 @@ "message": "We've sent a confirmation email to your email at " }, "confirmCollectionEnhancementsDialogTitle": { - "message": "This action is irreversible" + "message": "Esta acción es irreversible" }, "confirmCollectionEnhancementsDialogContent": { "message": "Turning on this feature will deprecate the manager role and replace it with a Can manage permission. This will take a few moments. Do not make any organization changes until it is complete. Are you sure you want to proceed?" @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 9bdb81baef6..9cfe91f00b6 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Genereeri e-posti alias, kasutades selleks välist teenuspakkujat." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hosti nimi", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index b1a04c8c417..fdf2b3944d8 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Zure harpidetzako doikuntzak fakturazioko guztizkoetan hainbanatutako aldaketak eragingo ditu. Erabiltzaile gonbidatuek harpidetza postuak gainditzen badituzte, berehala tarifa hainbanatua jasoko dute erabiltzaile gehigarrientzat." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Zure harpidetzako doikuntzak fakturazioko guztizkoetan hainbanatutako aldaketak eragingo ditu. Erabiltzaile gonbidatuek harpidetza postuak gainditzen badituzte, berehala tarifa hainbanatua jasoko dute erabiltzaile gehigarrientzat, $MAX$-eko gehienezko muga gainditzen ez den bitartean.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Emaileko ezizen bat sortu kanpoko bidalketa zerbitzu batekin." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ostalariaren izena", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index a31f0e7ddcd..90c48d2cbf9 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "تنظیمات اشتراک شما منجر به تغییرات نسبتاً زیادی در مجموع صورتحساب شما می‌شود. اگر عضو‌هایی که به تازگی دعوت شده‌اند بیشتر از جایگاه‌های اشتراک شما باشند، بلافاصله هزینه‌ای متناسب برای عضو‌هایی اضافی دریافت خواهید کرد." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "تنظیمات اشتراک شما منجر به تغییرات نسبتاً زیادی در مجموع صورتحساب شما می‌شود. اگر اعضای تازه دعوت شده از جایگاه‌های اشتراک شما بیشتر شوند، بلافاصله هزینه‌ای متناسب برای اعضای اضافی دریافت می‌کنید تا زمانی که به محدودیت جایگاه $MAX$ شما برسند.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "یک نام مستعار ایمیل با یک سرویس ارسال خارجی ایجاد کنید." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "نام میزبان", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "با افزودن مجموعه‌ها به این گروه، اجازه دسترسی به مجموعه‌ها را بدهید." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "انتخاب گروه‌ها" }, - "userPermissionOverrideHelper": { - "message": "مجوزهای تنظیم شده برای یک عضو، جایگزین مجوزهای تعیین شده توسط گروه آن عضو می‌شود" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "عضو یا گروهی اضافه نشد" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "تنظیمات رمزگذاری خود را برای رعایت توصیه‌های امنیتی جدید و بهبود حفاظت از حساب به‌روزرسانی کنید." }, - "changeKdfLoggedOutWarning": { - "message": "ادامه، شما را از تمام نشست‌های فعال خارج می‌کند. شما باید دوباره وارد شوید و راه اندازی دو مرحله ای ورود را تکمیل کنید. توصیه می‌کنیم قبل از تغییر در تنظیمات رمزگذاری برای جلوگیری از، از دست رفتن داده‌ها، گاوصندوق خود را برون ریزی کنید." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "مدیر رازها" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 39fba33e802..65606dca28d 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -2789,10 +2789,10 @@ "message": "Kaikki" }, "addAccess": { - "message": "Add Access" + "message": "Lisää käyttöoikeus" }, "addAccessFilter": { - "message": "Add Access Filter" + "message": "Lisää käyttöoikeussuodatin" }, "refresh": { "message": "Päivitä" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Tilausmuutokset aiheuttavat suhteutettuja laskutusmuutoksia. Jos hiljattain kutsuttujen jäsenten määrä ylittää tilauksesi jäsenpaikkojen määrän, veloitetaan suhteutettu hinta uusista jäsenistä välittömästi." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Tilausmuutokset aiheuttavat suhteutettuja laskutusmuutoksia. Jos hiljattain kutsuttujen jäsenten määrä ylittää tilauksesi jäsenpaikkojen määrän, veloitetaan suhteutettu hinta uusista jäsenistä välittömästi, kunnes $MAX$ paikan enimmäismäärä täyttyy.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Luo sähköpostialias ulkoisella ohjauspalvelulla." }, + "forwarderError": { + "message": "$SERVICENAME$ -virhe: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Verkkosivusto: $WEBSITE$. Bitwardenin luoma.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Virheellinen $SERVICENAME$ -rajapinnan tunniste: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ -palvelun peittämän sähköpostitilin tunnistetta ei saatu.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Virheellinen $SERVICENAME$ -verkkotunnus.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Virheellinen $SERVICENAME$ -URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Tapahtui tuntematon $SERVICENAME$ -virhe.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Tuntematon ohjaaja: $SERVICENAME$.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Isäntä", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Myönnä käyttöoikeudet kokoelmiin lisäämällä heidät tähän ryhmään." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Voit määrittää vain hallitsemiasi kokoelmia." + "restrictedCollectionAssignmentDesc": { + "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { "message": "Myönnä käyttöoikeudet kaikkiin nykyisiin ja tuleviin kokoelmiin" @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Valitse ryhmät" }, - "userPermissionOverrideHelper": { - "message": "Jäsenkohtaisesti määritetyt käyttöoikeudet korvaavat kyseisen jäsenen ryhmän määrittämät oikeudet" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Jäseniä tai ryhmiä ei ole lisätty." @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Päivitä salausasetuksesi uusien suojaussuositusten mukaisiksi ja vahvista tilisi suojausta." }, - "changeKdfLoggedOutWarning": { - "message": "Jos jatkat, kirjataan kaikki aktiiviset istunnot ulos, jonka jälkeen sinun on kirjauduttava sisään uudelleen ja suoritettava kaksivaiheisen todennuksen määritys. Tietojesi säilyvyyden varmistamiseksi suosittelemme, että viet holvisi sisällön ennen kuin muutat salausasetuksiasi." + "kdfSettingsChangeLogoutWarning": { + "message": "Jos jatkat, kaikki aktiiviset istunnot kirjataan ulos. Sinun on kirjauduttava sisään uudelleen ja suoritettava kaksivaiheisen todennuksen määritys. Tietojesi säilyvyyden varmistamiseksi suosittelemme, että viet holvisi sisällön, ennen kuin muutat salausasetuksiasi." }, "secretsManager": { "message": "Salaisuushallinta" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Oikeutesi eivät riitä kokoelman hallintaan." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Puuttuvat \"Voi hallita\" -käyttöoikeudet" + }, + "grantAddAccessCollectionWarning": { + "message": "Myönnä ”Voi hallita” -oikeudet, jotka mahdollistavat kokoelman täydellisen hallinnan, mukaanlukien sen poistamisen." + }, "grantCollectionAccess": { "message": "Myönnä ryhmille tai henkilöille kokoelman käyttöoikeus." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Onnistui" }, - "viewCollection": { - "message": "Näytä kokoelma" - }, "restrictedGroupAccess": { "message": "Et voi lisätä itseäsi ryhmiin." }, - "restrictedCollectionAccess": { - "message": "Et voi lisätä itseäsi kokoelmiin." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Määritä" @@ -7968,7 +8079,7 @@ } }, "deleteProviderWarningDescription": { - "message": "You must unlink all clients before you can delete $ID$.", + "message": "Kaikki pääteliitokset on poistettava ennen toimittajan $ID$ poistoa.", "placeholders": { "id": { "content": "$1", @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Hallitse laskutusta Toimittajaportaaliista" + }, + "viewInfo": { + "message": "Tarkastele tietoja" + }, + "viewAccess": { + "message": "Tarkastele oikeuksia" + }, + "noCollectionsSelected": { + "message": "Et ole valinnut yhtään kokoelmaa." + }, + "updateName": { + "message": "Päivitä nimi" + }, + "updatedOrganizationName": { + "message": "Päivitetty organisaation nimi" + }, + "providerPlan": { + "message": "Hallittu palvelutoimittaja" + }, + "orgSeats": { + "message": "Organisaation käyttäjäpaikat" + }, + "providerDiscount": { + "message": "$AMOUNT$ % alennus", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index d638415f411..4033bfff4d2 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Ang mga pagsasaayos sa iyong subscription ay magreresulta sa mga prorated na pagbabago sa iyong mga kabuuan ng pagsingil. Kung ang mga bagong inimbitahang miyembro ay lumampas sa iyong mga upuan sa subscription, agad kang makakatanggap ng prorated na singil para sa mga karagdagang miyembro." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Ang mga pagsasaayos sa iyong subscription ay magreresulta sa mga prorated na pagbabago sa iyong mga kabuuan ng pagsingil. Kung ang mga bagong inimbitahang miyembro ay lumampas sa iyong mga upuan sa subscription, agad kang makakatanggap ng prorated charge para sa mga karagdagang miyembro hanggang sa maabot ang iyong $MAX$ seat limit.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Bumuo ng isang email alias na may isang panlabas na serbisyo sa pagpapasa." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Pangalan ng Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Magbigay ng access sa mga koleksyon sa pamamagitan ng pagdaragdag ng mga ito sa grupong ito." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Pumili ng mga grupo" }, - "userPermissionOverrideHelper": { - "message": "Ang mga pahintulot na itinakda para sa isang miyembro ay papalitan ang mga pahintulot na itinakda ng grupo ng miyembrong iyon" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Walang idinagdag na mga miyembro o grupo" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 5beb47d4659..5814456ece7 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Les ajustements apportés à votre abonnement entraîneront des modifications au prorata de vos totaux de facturation. Si les utilisateurs nouvellement invités dépassent votre nombre de licences, vous recevrez immédiatement des frais au prorata pour les utilisateurs supplémentaires." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Si vous souhaitez ajouter" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "des licences sans l'offre groupée, veuillez contacter" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Les ajustements apportés à votre abonnement entraîneront des modifications au prorata de vos totaux de facturation. Si les utilisateurs nouvellement invités dépassent votre nombre de licences, vous recevrez immédiatement des frais au prorata pour les utilisateurs supplémentaires jusqu'à ce que votre limite de $MAX$ licences soit atteinte.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Générer un alias de courriel avec un service de transfert externe." }, + "forwarderError": { + "message": "Erreur $SERVICENAME$ : $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Généré par Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site web : $WEBSITE$. Généré par Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Jeton API $SERVICENAME$ invalide", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Jeton API $SERVICENAME$ non valide : $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Impossible d'obtenir l'ID du compte de courriel masqué $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domaine de $SERVICENAME$ invalide.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "L'URL $SERVICENAME$ invalide.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Une erreur $SERVICENAME$ inconnue s'est produite.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Émetteur inconnu: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nom d'hôte", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Accorder l'accès aux collections en les ajoutant à ce groupe." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Vous ne pouvez affecter que les collections que vous gérez." + "restrictedCollectionAssignmentDesc": { + "message": "Vous pouvez seulement assigner les collections que vous gérez." }, "accessAllCollectionsDesc": { "message": "Accorder l'accès à toutes les collections actuelles et futures." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Sélectionner les groupes" }, - "userPermissionOverrideHelper": { - "message": "Les permissions définies pour un membre remplaceront les permissions définies par le groupe de ce membre" + "userPermissionOverrideHelperDesc": { + "message": "Les permissions définies pour un membre remplaceront les permissions définies par le groupe de ce membre." }, "noMembersOrGroupsAdded": { "message": "Aucun membre ou groupe ajouté" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Mettez à jour vos paramètres de chiffrement pour répondre à de nouvelles recommandations de sécurité et améliorer la protection de votre compte." }, - "changeKdfLoggedOutWarning": { - "message": "En poursuivant, vous serez déconnecté de toutes les sessions actives. Vous devrez vous reconnecter et terminer la configuration de l'authentification à deux facteurs. Nous vous recommandons d'exporter votre coffre avant de modifier vos paramètres de chiffrement afin d'éviter toute perte de données." + "kdfSettingsChangeLogoutWarning": { + "message": "Effectuer cette action vous déconnectera de toutes les sessions actives. Vous devrez vous connecter à nouveau et compléter votre authentification à 2 facteurs, s'il y a lieu. Nous vous recommandons d'exporter votre coffre avant de modifier vos paramètres de chiffrement pour prévenir la perte de vos données." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Vous n'avez pas accès à la gestion de cette collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "\"Peut Gérer les Permissions\" manquant" + }, + "grantAddAccessCollectionWarning": { + "message": "Accorder \"Peut Gérer les Permissions\" pour permettre une gestion complète de la collection, y compris la suppression de la collection." + }, "grantCollectionAccess": { "message": "Accorder l'accès à cette collection aux groupes ou aux membres." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Succès" }, - "viewCollection": { - "message": "Afficher la Collection" - }, "restrictedGroupAccess": { "message": "Vous ne pouvez vous ajoutez vous-même aux groupes." }, - "restrictedCollectionAccess": { - "message": "Vous ne pouvez vous ajoutez vous-même aux collections." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Assigner" @@ -7968,7 +8079,7 @@ } }, "deleteProviderWarningDescription": { - "message": "You must unlink all clients before you can delete $ID$.", + "message": "Vous devez dissocier tous les clients avant de pouvoir supprimer $ID$.", "placeholders": { "id": { "content": "$1", @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Gérer la facturation depuis le Portail Fournisseur" + }, + "viewInfo": { + "message": "Afficher les informations" + }, + "viewAccess": { + "message": "Afficher les accès" + }, + "noCollectionsSelected": { + "message": "Vous n'avez sélectionné aucune collection." + }, + "updateName": { + "message": "Mettre le nom à jour" + }, + "updatedOrganizationName": { + "message": "Nom de l'organisation mis à jour" + }, + "providerPlan": { + "message": "Service Provider géré" + }, + "orgSeats": { + "message": "Licences de l'Organisation" + }, + "providerDiscount": { + "message": "Remise de $AMOUNT$%", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Sécurisez votre infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protégez votre famille ou votre entreprise" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Fermer les failles de sécurité avec des rapports de surveillance" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Restez en avance sur les vulnérabilités de sécurité en passant à un plan payant pour une surveillance améliorée." } } diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index 9b8b8bb461e..a6ff9c1fed6 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 0bf2d56635f..2d2c238df02 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 448149e7b84..2c2ae12f653 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Promjene na pretplati rezultirati će proporcionalnim izmjenama ukupnog zaduženja. Ako novopozvanim korisnikom prekoračiš broj licenci, odmah će biti naplaćeno proporcionalno uvećanje za nove korisnike." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Promjene na pretplati rezultirati će proporcionalnim izmjenama ukupnog zaduženja. Ako novopozvanim korisnikom prekoračiš broj licenci, odmah će biti naplaćeno proporcionalno uvećanje za nove korisnike dok se ne dosegne krajnji broj licenci ($MAX$).", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generiraj pseudonim e-pošte s vanjskom uslugom prosljeđivanja." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Naziv poslužitelja", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Odobri pristup zbirkama dodavanjem u ovu grupu." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Odaberi grupe" }, - "userPermissionOverrideHelper": { - "message": "Dopuštenja postavljena za člana zamijenit će dopuštenja postavljena od strane grupe tog člana" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Nema dodanih članova ili grupa" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Nastavkom ćeš se odjaviti iz svih aktivnih sesija. Morat ćeš se ponovno prijaviti i dovršiti postavljanje prijave dvostrukom autentifikacijom. Preporučujemo izvoz trezora prije promjene postavki enkripcije kako bi se spriječio gubitak podataka." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Upravitelj tajni" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index ca79bcd5213..7fe5fa0f96e 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Az előfizetés módosítása a számlázási összegek arányos módosítását eredményezi. Ha az újonnan meghívott felhasználók túllépik az előfizetői helyeket, akkor haladéktalanul külön díjat kapunk a további felhasználókért." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Ha szeretnénk hozzáadni további" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "helyeket a csomagban szereplő ajánlat nélkül, vegyük fel a kapcsolatot" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Az előfizetés módosítása a számlázási összegek arányos módosítását eredményezi. Ha az újonnan meghívott felhasználók túllépik az előfizetési helyeket, akkor haladéktalanul külön díjat kapunk a további felhasználókért, amíg el nem érjük a $MAX$ helykorlátot.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Email álnév generálása külső továbbító szolgáltatással." }, + "forwarderError": { + "message": "$SERVICENAME$ hiba: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Webhely: $WEBSITE$. Generálta: Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "$SERVICENAME$ API vezérjel érvénytelen.", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "$SERVICENAME$ API vezérjel érvénytelen: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nem lehet beolvasni $SERVICENAME$ maszkolt email fiók azonosítót.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "$SERVICENAME$ domain érvénytelen.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "$SERVICENAME$ webcím érvénytelen.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ismeretlen $SERVICENAME$ hiba történt.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Ismeretlen továbbító: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Kiszolglónév", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Hozzáférés kiosztása gyűjteményekhez csoporthoz adásukkal." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Csak a saját kezelésű gyűjteményeket lehet hozzárendelni." }, "accessAllCollectionsDesc": { @@ -6720,7 +6828,7 @@ "selectGroups": { "message": "Csoportok kiválasztása" }, - "userPermissionOverrideHelper": { + "userPermissionOverrideHelperDesc": { "message": "A tagok számára beállított jogosultságok felváltják az adott tag csoportja által beállított jogosultságokat." }, "noMembersOrGroupsAdded": { @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Frissítsük a titkosítási beállításokat, hogy megfeleljünk az új biztonsági ajánlásoknak és javítsuk a fiókvédelmet." }, - "changeKdfLoggedOutWarning": { - "message": "A folytatással minden aktív munkamenetből kijelentkezünkk. Újra be kell jelentkezni és ki kell tölteni a kétlépcsős bejelentkezési beállításokat. Az adatvesztés elkerülése érdekében célszerű a titkosítási beállítások módosítása előtt a széf exportálása." + "kdfSettingsChangeLogoutWarning": { + "message": "A folytatás kijelentkeztet az összes aktív munkamenetből. Újra be kell jelentkezni és kétlépcsős bejelentkezést kell végrehajtani, ha van ilyen. Célszerű a titkosítási beállítások módosítása előtt a széf exportálása az adatvesztés elkerülése érdekében." }, "secretsManager": { "message": "Titkos kód kezelő" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Nincs jogosultság ennek a gyűjteménynek a kezelésére." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Adjunk hozzáférést csoportoknak vagy személyeknek eennél a gyűjteménynél." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Sikeres" }, - "viewCollection": { - "message": "Gyűjtemény megtekintése" - }, "restrictedGroupAccess": { "message": "Nem adhadjuk magunkat a csoporthoz." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Nem adhadjuk magunkat a gyűjteményhez." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "A számlázás kezelése a szolgáltatói portálon keresztül" + }, + "viewInfo": { + "message": "Infó megtekintése" + }, + "viewAccess": { + "message": "Hozzáférés megtekintése" + }, + "noCollectionsSelected": { + "message": "Nincs semmilyen gyűjtemény kiválasztva." + }, + "updateName": { + "message": "Név frissítés" + }, + "updatedOrganizationName": { + "message": "Frissített szervezeti név" + }, + "providerPlan": { + "message": "Menedzselt szolgáltató" + }, + "orgSeats": { + "message": "Szervezeti helyek" + }, + "providerDiscount": { + "message": "$AMOUNT$% kedvezmény", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Infrastruktúra biztosítása" + }, + "protectYourFamilyOrBusiness": { + "message": "Család vagy üzlet megvédése" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 77fa91ebf1c..4d1bffa5c59 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Penyesuaian pada paket langganan Anda akan mengakibatkan perubahan prorata pada total tagihan Anda. Jika anggota yang baru diundang melampaui kuota langganan Anda, Anda akan langsung dikenakan biaya prorata untuk pengguna tambahan tersebut." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Penyesuaian pada paket langganan Anda akan mengakibatkan perubahan prorata pada total tagihan Anda. Jika anggota yang baru diundang melampaui kuota langganan Anda, Anda akan langsung dikenakan biaya prorata untuk pengguna tambahan tersebut hingga batas kuota $MAX$ anggota tercapai.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index ebea88daa3e..734ad6faea5 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Le modifiche al tuo abbonamento comporteranno modifiche corrispondenti al totale di fatturazione. Se i nuovi utenti invitati superano gli slot del tuo abbonamento, riceverai subito un addebito corrispondente per gli utenti aggiuntivi." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Se vuoi aggiungere ulteriori" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "slot senza l'offerta in bundle, contatta" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Le modifiche al tuo abbonamento comporteranno modifiche corrispondenti al totale di fatturazione. Se i nuovi utenti invitati superano gli slot del tuo abbonamento, riceverai subito un addebito corrispondente per gli utenti aggiuntivi finché il limite di $MAX$ slot non è raggiunto.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Genera un alias email con un servizio di inoltro esterno." }, + "forwarderError": { + "message": "Errore $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Sito web: $WEBSITE$. Generato da Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token API $SERVICENAME$ non valido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token API $SERVICENAME$ non valido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Impossibile ottenere l'ID dell'account email mascherato di $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Dominio $SERVICENAME$ non valido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ non valido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Errore di $SERVICENAME$ sconosciuto.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Mittente sconosciuto: \"$SERVICENAME$\".", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome host", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Concedi accesso alle raccolte aggiungendo gli utenti a questo gruppo." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Puoi assegnare solo le raccolte che gestisci." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Seleziona gruppi" }, - "userPermissionOverrideHelper": { - "message": "I permessi impostati per un membro sostituiranno i permessi impostati dal gruppo di quel membro" + "userPermissionOverrideHelperDesc": { + "message": "I permessi impostati per un membro sostituiranno i permessi impostati dal gruppo di quel membro." }, "noMembersOrGroupsAdded": { "message": "Nessun membro o gruppo aggiunto" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Aggiorna le tue impostazioni di crittografia per soddisfare le nuove raccomandazioni sulla sicurezza e migliorare la protezione del tuo account." }, - "changeKdfLoggedOutWarning": { - "message": "Procedere ti farà uscire da tutte le sessioni attive. Dovrai accedere di nuovo e completare la configurazione della verifica in due passaggi. Ti consigliamo di esportare la tua cassaforte prima di cambiare le impostazioni di crittografia per prevenire perdite di dati." + "kdfSettingsChangeLogoutWarning": { + "message": "Procedere ti farà uscire da tutte le sessioni attive. Dovrai accedere di nuovo e completare la verifica in due passaggi, se impostata. Ti consigliamo di esportare la tua cassaforte prima di cambiare le impostazioni di crittografia per prevenire perdite di dati." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Non hai accesso alla gestione di questa raccolta." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Autorizzazione Può gestire mancante" + }, + "grantAddAccessCollectionWarning": { + "message": "Concedi l'autorizzazione Può gestire per consentire la gestione completa della raccolta, inclusa l'eliminazione della raccolta." + }, "grantCollectionAccess": { "message": "Consenti a gruppi o membri di accedere a questa raccolta." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Successo" }, - "viewCollection": { - "message": "Visualizza raccolta" - }, "restrictedGroupAccess": { "message": "Non puoi aggiungerti da solo ai gruppi." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Non puoi aggiungerti da solo alle raccolte." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Gestisci la fatturazione dal Portale del Fornitore" + }, + "viewInfo": { + "message": "Visualizza informazioni" + }, + "viewAccess": { + "message": "Visualizza accesso" + }, + "noCollectionsSelected": { + "message": "Non hai selezionato alcuna raccolta." + }, + "updateName": { + "message": "Aggiorna nome" + }, + "updatedOrganizationName": { + "message": "Nome dell'organizzazione aggiornato" + }, + "providerPlan": { + "message": "Fornitore di servizi gestiti" + }, + "orgSeats": { + "message": "Slot dell'organizzazione" + }, + "providerDiscount": { + "message": "$AMOUNT$% di sconto", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Proteggi la tua infrastruttura" + }, + "protectYourFamilyOrBusiness": { + "message": "Proteggi la tua famiglia o azienda" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Colma le lacune di sicurezza con i rapporti di monitoraggio" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stai al passo con le vulnerabilità della sicurezza passando a un piano a pagamento per un monitoraggio più avanzato." } } diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index c43c0d1650e..4ff4143236c 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "サブスクリプションを調整すると、請求の合計が日割りで変更されます。新たに招待されたユーザーがお客様の契約数を超えた場合、お客様は直ちに追加ユーザー分の日割り計算を請求されます。" }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "バンドルオファーなしで" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "シートを追加したい場合はお問い合わせください" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "サブスクリプションを調整すると、請求の合計が日割りで変更されます。新しく招待されたユーザーがお客様の契約数を超えた場合、契約数が$MAX$名に達するまで、追加されたユーザーに対する日割り計算の請求が即座に請求されます。", "placeholders": { @@ -4532,7 +4538,7 @@ "message": "権限" }, "managerPermissions": { - "message": "権限の管理" + "message": "管理者権限" }, "adminPermissions": { "message": "管理者権限" @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "外部転送サービスを使用してメールエイリアスを生成します。" }, + "forwarderError": { + "message": "$SERVICENAME$ エラー: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "ウェブサイト: $WEBSITE$ Bitwarden によって生成されました。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "不正な$SERVICENAME$ API トークン", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "不正な$SERVICENAME$ API トークン: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "$SERVICENAME$ マスク済みメールアカウント ID を取得できませんでした。", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "不正な $SERVICENAME$ ドメインです。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "不正な $SERVICENAME$ URL です。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "不明な $SERVICENAME$ エラーが起きました。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "不明な転送先: '$SERVICENAME$'", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "ホスト名", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "このグループに追加してコレクションへのアクセスを許可します。" }, - "editGroupCollectionsRestrictionsDesc": { - "message": "You can only assign collections you manage." + "restrictedCollectionAssignmentDesc": { + "message": "自分が管理しているコレクションのみを割り当てることができます。" }, "accessAllCollectionsDesc": { "message": "現在および将来のすべてのコレクションへのアクセスを許可します。" @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "グループを選択" }, - "userPermissionOverrideHelper": { - "message": "メンバーの権限設定は、そのメンバーのグループによって設定された権限に置き換えられます" + "userPermissionOverrideHelperDesc": { + "message": "メンバーの権限設定は、そのメンバーのグループによって設定された権限に置き換えられます。" }, "noMembersOrGroupsAdded": { "message": "メンバーまたはグループが追加されていません" @@ -6912,7 +7020,7 @@ "updateLowKdfIterationsDesc": { "message": "新しいセキュリティの推奨事項に対応し、アカウントの保護を向上させるために、暗号化設定を更新してください。" }, - "changeKdfLoggedOutWarning": { + "kdfSettingsChangeLogoutWarning": { "message": "続行すると、すべてのアクティブなセッションからログアウトします。再度ログインし、2段階認証を完了する必要があります。 暗号化設定を変更する前に、保管庫をエクスポートしてデータの損失を防ぐことをおすすめします。" }, "secretsManager": { @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "このコレクションを管理する権限がありません。" }, + "grantAddAccessCollectionWarningTitle": { + "message": "「管理可能」権限がありません" + }, + "grantAddAccessCollectionWarning": { + "message": "コレクションの削除を含む完全なコレクション管理を許可するには「管理可能」権限を許可してください。" + }, "grantCollectionAccess": { "message": "グループまたはメンバーにこのコレクションへのアクセスを許可します。" }, @@ -7638,13 +7752,10 @@ "success": { "message": "成功" }, - "viewCollection": { - "message": "コレクションを表示" - }, "restrictedGroupAccess": { "message": "あなた自身をグループに追加することはできません。" }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "コレクションに自分自身を追加することはできません。" }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "プロバイダーポータルからの請求を管理" + }, + "viewInfo": { + "message": "情報を表示" + }, + "viewAccess": { + "message": "アクセスを表示" + }, + "noCollectionsSelected": { + "message": "コレクションが選択されていません。" + }, + "updateName": { + "message": "名前を更新" + }, + "updatedOrganizationName": { + "message": "組織名を更新済み" + }, + "providerPlan": { + "message": "マネージドサービスプロバイダー" + }, + "orgSeats": { + "message": "組織のシート" + }, + "providerDiscount": { + "message": "$AMOUNT$%割引", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "インフラストラクチャの保護" + }, + "protectYourFamilyOrBusiness": { + "message": "家族やビジネスを保護" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "モニタリングレポートでセキュリティギャップを解消" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "監視を強化できる有料プランにアップグレードすると、セキュリティ脆弱性に素早く対応できます。" } } diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 897e1a548ad..6d4d333d16f 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index 11447428be8..6de3f4d2de3 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index e9fc3343308..5e4922cd645 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "비밀 데이터 관리자" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 7d02dbce267..60003985ca4 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Abonementa pielāgojumi izvērtīsies attiecīgās izmaiņās kopējā rēķinā. Ja jauno uzaicināto lietotāju skaits pārsniedz abonementu vietas, nekavējoties tiks veikts atbilstošs maksājums par papildu lietotājiem." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Ja vēlies pievienot papildu" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "vietas bez iekļautā piedāvājuma, lūgums sazināties ar" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Abonementa pielāgojumi izvērtīsies attiecīgās izmaiņās kopējā rēķinā. Ja jauno uzaicināto lietotāju skaits pārsniedz abonementu vietas, nekavējoties tiks veikts atbilstošs maksājums par papildu lietotājiem līdz tiks sasniegts $MAX$ vietu ierobežojums.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Izveidot e-pastu aizstājvārdu ar ārēju pārvirzīšanas pakalpojumu." }, + "forwarderError": { + "message": "$SERVICENAME$ kļūda: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Tīmekļvietne: $WEBSITE$. Izveidoja Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nederīga $SERVICENAME$ API pilnvara", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nederīga $SERVICENAME$ API pilnvara: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Neizdevās iegūt $SERVICENAME$ aizsegta e-pasta konta Id.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nederīgs $SERVICENAME$ domēna vārds.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nederīgs $SERVICENAME$ URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Atgadījās nezināma $SERVICENAME$ kļūda.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Nezināms pārsūtītājs: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Resursdatora nosaukums", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Piešķirt piekļuvi krājumiem, pievienojot tos šai grupai." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Var piešķirt tikai pārvaldītos krājumus." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Atlasīt grupas" }, - "userPermissionOverrideHelper": { - "message": "Dalībniekam iestatītās atļaujas aizstās šī dalībnieka grupas noteiktās atļaujas" + "userPermissionOverrideHelperDesc": { + "message": "Dalībniekam iestatītās atļaujas aizstās šī dalībnieka kopas noteiktās atļaujas." }, "noMembersOrGroupsAdded": { "message": "Nav pievienotu dalībnieku vai grupu" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Jāatjaunina šifrēšanas iestatījumi, lai atbilstu jaunajiem drošības ieteikumiem un uzlabotu konta aizsardzību." }, - "changeKdfLoggedOutWarning": { - "message": "Turpinot notiks atteikšanās no visām esošajām sesijām. Būs atkārtoti jāpiesakās un jāpabeidz divpakāpju pieteikšanās uzstādīšana. Mēs iesakām pirms šifrēšanas iestatījumu mainīšanas izgūt glabātavas saturu, lai novērstu datu zudumu." + "kdfSettingsChangeLogoutWarning": { + "message": "Turpinot notiks atteikšanās no visām esošajām sesijām. Būs atkārtoti jāpiesakās un jāpabeidz divpakāpju pieteikšanās, ja tāda ir. Mēs iesakām pirms šifrēšanas iestatījumu mainīšanas izgūt glabātavas saturu, lai novērstu datu zudumu." }, "secretsManager": { "message": "Noslēpumu pārvaldnieks" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Nav piekļuves pārvaldīt šo krājumu." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Trūkst atļaujas \"Var pārvaldīt\"" + }, + "grantAddAccessCollectionWarning": { + "message": "Jānodrošina atļauja \"Var pārvaldīt\", lai ļautu pilnu krājuma pārvaldību, tajā skaitā krājuma izdzēšanu." + }, "grantCollectionAccess": { "message": "Piešķirt kopām vai dalībniekiem piekļuvi šim krājumam." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Izdevās" }, - "viewCollection": { - "message": "Skatīt krājumu" - }, "restrictedGroupAccess": { - "message": "Tu nevari sevi pievienot kopām." + "message": "Sevi nevar pievienot kopām." }, - "restrictedCollectionAccess": { - "message": "Tu nevari sevi pievienot krājumiem." + "cannotAddYourselfToCollections": { + "message": "Sevi nevar pievienot krājumiem." }, "assign": { "message": "Piešķirt" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Norēķinus var pārvaldīt Nodrošinātāju portālā" + }, + "viewInfo": { + "message": "Skatīt informāciju" + }, + "viewAccess": { + "message": "Skatīt piekļuvi" + }, + "noCollectionsSelected": { + "message": "Nav atlasīts neviens krājums." + }, + "updateName": { + "message": "Atjaunināt nosaukumu" + }, + "updatedOrganizationName": { + "message": "Atjaunināts apvienības nosaukums" + }, + "providerPlan": { + "message": "Pārvaldīts pakalpojuma nodrošinātājs" + }, + "orgSeats": { + "message": "Apvienības vietas" + }, + "providerDiscount": { + "message": "$AMOUNT$% atlaide", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Nodrošini savu infrastruktūru" + }, + "protectYourFamilyOrBusiness": { + "message": "Aizsargā savu ģimeni vai uzņēmumu" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Novērs drošības caurumus ar uzraudzības pārskatiem" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Apsteidz drošības ievainojamības ar pāriešanu uz maksas plānu pastiprinātai uzraudzībai." } } diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 9e67aebbcb5..3f79cf4c3eb 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index e670117cb42..54521094005 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Justeringer av ditt abonnement vil resultere i utsatt endring av dine faktureringsbeløp. Hvis nyinviterte brukere overstiger ditt abonnementssete, vil du umiddelbart få et betalt for ekstra brukere." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Justeringer av ditt abonnement vil resultere i utsatt endring av dine faktureringsbeløp. Om nyinviterte brukere overskrider ditt abonnementssete, umiddelbart vil du få en skattekostnad for tilleggsbrukerne inntil din plass på $MAX$ er nådd.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generer et e-postalias med en ekstern videresendingstjeneste." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Vertsnavn", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Gi tilgang til samlinger ved å legge dem til i denne gruppen." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Velg grupper" }, - "userPermissionOverrideHelper": { - "message": "Tilganger satt for et medlem vil erstatte tilganger satt av medlemmets gruppe" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Ingen medlemmer eller grupper er lagt til" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 03ba792a6e2..955ff2c20ac 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 6ef7fbae592..4e2846417f7 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Aanpassingen aan je abonnement leiden tot evenredige wijzigingen in je factuurtotaal. Als nieuwe gebruikers je gebruikersplaatsen overschrijden, ontvang je onmiddellijk een afschrijving voor de extra gebruikers." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Aanpassingen aan je abonnement leiden tot evenredige wijzigingen in je factuurtotaal. Als nieuwe gebruikers je gebruikersplaatsen overschrijden, ontvang je onmiddellijk een afschrijving voor de extra gebruikers tot het aantal van $MAX$ gebruikersplaatsen is bereikt.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Genereer een e-mailalias met een externe doorschakelservice." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostnaam", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Geef toegang tot collecties door ze aan deze groep toe te voegen." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Groepen selecteren" }, - "userPermissionOverrideHelper": { - "message": "Ingestelde rechten voor een lid vervangen ingestelde rechten door de groep van het lid" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Geen leden of groepen toegevoegd" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Werk je versleutelingsinstellingen bij om aan de nieuwe beveiligingsaanbevelingen te voldoen en de bescherming van je account te verbeteren." }, - "changeKdfLoggedOutWarning": { - "message": "Als u doorgaat zullen al uw actieve sessies word uitgelogd. U zult zich opnieuw aan moeten melden en 2 stappen verificatie moeten instellen. Wij raden u aan om uw gegevens eerst te exporteren voordat u uw encryptie instellingen aanpast om data verlies te voorkomen." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Je hebt geen toegang om deze collectie te beheren." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Groepen of mensen toegang tot deze collectie geven." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Succes" }, - "viewCollection": { - "message": "Collectie weergeven" - }, "restrictedGroupAccess": { "message": "Het is niet mogelijk om jezelf toe te voegen aan groepen." }, - "restrictedCollectionAccess": { - "message": "Het is niet mogelijk om jezelf toe te voegen aan collecties." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Toewijzen" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Naam bijwerken" + }, + "updatedOrganizationName": { + "message": "Organisatienaam bijgewerkt" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Beveilig je infrastructuur" + }, + "protectYourFamilyOrBusiness": { + "message": "Bescherm je gezin of bedrijf" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 08631216c8f..c461a3679ee 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 7b48a6a20c2..6d9147d42db 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Zmiany w subskrypcji spowodują proporcjonalne zmiany w rozliczeniach. Jeśli nowo zaproszeni członkowie przekroczą liczbę miejsc w subskrypcji, otrzymasz proporcjonalną opłatę za dodatkowych członków." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Korekty subskrypcji spowodują proporcjonalne zmiany w sumach rozliczeniowych. Jeśli nowo zaproszeni członkowie przekroczą liczbę miejsc objętych subskrypcją, natychmiast otrzymasz proporcjonalną opłatę za dodatkowych członków, aż do osiągnięcia limitu miejsc $MAX$.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Wygeneruj alias adresu e-mail z zewnętrznej usługi przekierowania." }, + "forwarderError": { + "message": "Błąd $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Wygenerowane przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Strona internetowa: $WEBSITE$. Wygenerowano przez Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Nieprawidłowy token API dla $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Nieprawidłowy token API dla $SERVICENAME$, błąd: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Nie można uzyskać ID maskowanego konta e-mail dla $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Nieprawidłowa domena $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Nieprawidłowy adres URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Wystąpił nieznany błąd w $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nazwa hosta", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Przyznaj dostęp do kolekcji, dodając je do tej grupy." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "You can only assign collections you manage." + "restrictedCollectionAssignmentDesc": { + "message": "Możesz przypisać tylko kolekcje, którymi zarządzasz." }, "accessAllCollectionsDesc": { "message": "Udziel dostępu do wszystkich bieżących i przyszłych kolekcji." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Wybierz grupy" }, - "userPermissionOverrideHelper": { - "message": "Uprawnienia ustawione dla użytkownika zastąpią uprawnienia ustawione przez grupę tego użytkownika" + "userPermissionOverrideHelperDesc": { + "message": "Uprawnienia ustawione dla członka zastąpią uprawnienia ustawione przez grupę tego członka." }, "noMembersOrGroupsAdded": { "message": "Nie dodano członków lub grup" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Zaktualizuj ustawienia szyfrowania, aby spełnić nowe zalecenia bezpieczeństwa i poprawić ochronę konta." }, - "changeKdfLoggedOutWarning": { - "message": "Kontynuowanie spowoduje wylogowanie ze wszystkich aktywnych sesji. Będzie trzeba zalogować się ponownie i ukończyć konfigurację logowania dwuetapowego. Zalecamy wyeksportowanie sejfu przed zmianą ustawień szyfrowania, aby zapobiec utracie danych." + "kdfSettingsChangeLogoutWarning": { + "message": "Kontynuowanie spowoduje wylogowanie ze wszystkich aktywnych sesji. Będzie trzeba zalogować się ponownie i wykonać logowanie dwuetapowe, jeśli jest włączone. Zalecamy wyeksportowanie sejfu przed zmianą ustawień szyfrowania, aby zapobiec utracie danych." }, "secretsManager": { "message": "Menedżer sekretów" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Nie masz dostępu do zarządzania tą kolekcją." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Przyznaj grupom lub członkom dostęp do tej kolekcji." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Sukces" }, - "viewCollection": { - "message": "Zobacz kolekcję" - }, "restrictedGroupAccess": { "message": "Nie możesz dodać siebie do grup." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Nie możesz dodać siebie do kolekcji." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Zarządzaj płatnościami z portalu dostawcy" + }, + "viewInfo": { + "message": "Wyświetl informacje" + }, + "viewAccess": { + "message": "Wyświetl dostęp" + }, + "noCollectionsSelected": { + "message": "Nie wybrano żadnej kolekcji." + }, + "updateName": { + "message": "Zaktualizuj nazwę" + }, + "updatedOrganizationName": { + "message": "Zaktualizowana nazwa organizacji" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Miejsca w organizacji" + }, + "providerDiscount": { + "message": "Zniżka $AMOUNT$%", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Zabezpiecz swoją infrastrukturę" + }, + "protectYourFamilyOrBusiness": { + "message": "Chroń swoją rodzinę lub firmę" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Zamyka luki bezpieczeństwa za pomocą sprawozdań z monitorowania" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Bądź na bieżąco z lukami bezpieczeństwa dzięki zmianie na płatny plan z bardziej rozbudowanym monitorowaniem." } } diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 29d7ebe4cc6..cc46b98b315 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -2789,10 +2789,10 @@ "message": "Todos" }, "addAccess": { - "message": "Add Access" + "message": "Adicionar Acesso" }, "addAccessFilter": { - "message": "Add Access Filter" + "message": "Adicionar Filtro de Acesso" }, "refresh": { "message": "Atualizar" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Ajustes em sua assinatura resultarão em alterações rateadas em seus totais de cobrança. Se os usuários recém-convidados excederem o número de vagas de sua assinatura, você receberá imediatamente uma cobrança proporcional pelos usuários adicionais." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Ajustes em sua assinatura resultarão em alterações rateadas em seus totais de cobrança. Se os usuários recém-convidados excederem o número de vagas de sua assinatura, você receberá imediatamente uma cobrança proporcional para os usuários adicionais até que seu limite de $MAX$ de vaga seja atingido.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Gere um alias de e-mail com um serviço externo de encaminhamento." }, + "forwarderError": { + "message": "Erro $SERVICENAME$ : $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token de API $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token de API $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter a máscara do ID da conta de email $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL $SERVICENAME$ inválida.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro $SERVICENAME$ desconhecido.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Encaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Conceder acesso às coleções adicionando-as a este grupo." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Você só pode atribuir coleções que você gerencia." + "restrictedCollectionAssignmentDesc": { + "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { "message": "Conceder acesso a todas as coleções atuais e futuras." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Selecione grupos" }, - "userPermissionOverrideHelper": { - "message": "Permissões definidas para um membro substituirão as permissões definidas pelo grupo desse membro" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Nenhum membro ou grupo adicionado" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Atualize suas configurações de criptografia para atender às novas recomendações de segurança e melhorar a proteção da conta." }, - "changeKdfLoggedOutWarning": { - "message": "O processo desconectará você de todas as sessões ativas. Você precisará iniciar a sessão novamente e concluir a configuração de login em duas etapas. Recomendamos exportar seu cofre antes de alterar suas configurações de criptografia para evitar perda de dados." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Gerenciador de Segredos" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Você não tem acesso para gerenciar esta coleção." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Falta conceder o Poder de Gerenciar Permissões" + }, + "grantAddAccessCollectionWarning": { + "message": "Conceda o poder de gerenciar permissões para habilitar o gerenciamento completo da coleção, incluindo a exclusão da coleção." + }, "grantCollectionAccess": { "message": "Conceder acesso de grupos ou membros a esta coleção." }, @@ -7540,13 +7654,13 @@ "message": "Conceder acesso a essa coleção." }, "adminCollectionAccess": { - "message": "Administrators can access and manage collections." + "message": "Os administradores podem acessar e gerenciar coleções." }, "serviceAccountAccessUpdated": { "message": "Acesso à conta de serviço atualizado" }, "commonImportFormats": { - "message": "Common formats", + "message": "Formatos comuns", "description": "Label indicating the most common import formats" }, "maintainYourSubscription": { @@ -7571,16 +7685,16 @@ "message": "Saiba mais sobre o gerenciamento de coleção" }, "organizationInformation": { - "message": "Organization information" + "message": "Informação da Organização" }, "confirmationDetails": { "message": "Detalhes da confirmação" }, "smFreeTrialThankYou": { - "message": "Thank you for signing up for Bitwarden Secrets Manager!" + "message": "Obrigado por se inscrever no Bitwarden Secrets Manager!" }, "smFreeTrialConfirmationEmail": { - "message": "We've sent a confirmation email to your email at " + "message": "Enviamos um e-mail de confirmação para seu e-mail em " }, "confirmCollectionEnhancementsDialogTitle": { "message": "Esta ação é irreversível" @@ -7636,16 +7750,13 @@ "message": "Portal do provedor" }, "success": { - "message": "Success" - }, - "viewCollection": { - "message": "Ver Coleção" + "message": "Sucesso" }, "restrictedGroupAccess": { "message": "Você não pode se adicionar aos grupos." }, - "restrictedCollectionAccess": { - "message": "Você não pode se adicionar às coleções." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Atribuir" @@ -7936,7 +8047,7 @@ "message": "Você não pode adicionar você mesmo a um grupo." }, "unassignedItemsBannerSelfHost": { - "message": "Notice: On May 2, 2024, unassigned organization items will no longer be visible in your All Vaults view across devices and will only be accessible via the Admin Console. Assign these items to a collection from the Admin Console to make them visible." + "message": "Aviso: Em 2 de maio de 2024, itens da organização não estarão mais visíveis em sua visualização de Todos os Cofres entre dispositivos e só serão acessíveis por meio do painel de administração. Atribuir estes itens a uma coleção do Console de Administração para torná-los visíveis." }, "unassignedItemsBannerNotice": { "message": "Aviso: Itens de organização não atribuídos não estão mais visíveis na sua tela Todos os Cofres através dos dispositivos e agora só são acessíveis por meio do Console de Administração." @@ -7968,7 +8079,7 @@ } }, "deleteProviderWarningDescription": { - "message": "You must unlink all clients before you can delete $ID$.", + "message": "Você deve desvincular todos os clientes antes de excluir $ID$.", "placeholders": { "id": { "content": "$1", @@ -7995,53 +8106,53 @@ "message": "Erro ao atribuir pasta de destino." }, "integrationsAndSdks": { - "message": "Integrations & SDKs", + "message": "Integrações e SDKs", "description": "The title for the section that deals with integrations and SDKs." }, "integrations": { - "message": "Integrations" + "message": "Integrações" }, "integrationsDesc": { - "message": "Automatically sync secrets from Bitwarden Secrets Manager to a third-party service." + "message": "Sincronize automaticamente segredos do Bitwarden Secrets Manager para um serviço de terceiros." }, "sdks": { "message": "SDKs" }, "sdksDesc": { - "message": "Use Bitwarden Secrets Manager SDK in the following programming languages to build your own applications." + "message": "Utilize o Bitwarden Secrets Manager SDK nas seguintes linguagens de programação para construir seus próprios aplicativos." }, "setUpGithubActions": { - "message": "Set up Github Actions" + "message": "Configurar ações do Github" }, "setUpGitlabCICD": { - "message": "Set up GitLab CI/CD" + "message": "Configurar GitLab CI/CD" }, "setUpAnsible": { - "message": "Set up Ansible" + "message": "Configurar Ansible" }, "cSharpSDKRepo": { - "message": "View C# repository" + "message": "Visualizar repositório C#" }, "cPlusPlusSDKRepo": { - "message": "View C++ repository" + "message": "Visualizar repositório C++" }, "jsWebAssemblySDKRepo": { - "message": "View JS WebAssembly repository" + "message": "Visualizar repositório WebAssembly JS" }, "javaSDKRepo": { - "message": "View Java repository" + "message": "Ver repositório Java" }, "pythonSDKRepo": { - "message": "View Python repository" + "message": "Ver repositório Python" }, "phpSDKRepo": { - "message": "View php repository" + "message": "Ver repositório PHP" }, "rubySDKRepo": { - "message": "View Ruby repository" + "message": "Ver repositório Ruby" }, "goSDKRepo": { - "message": "View Go repository" + "message": "Visualizar repositório Go" }, "createNewClientToManageAsProvider": { "message": "Crie uma nova organização de cliente para gerenciar como um Provedor. Posições adicionais serão refletidas no próximo ciclo de faturamento." @@ -8065,10 +8176,10 @@ "message": "Novo cliente criado com sucesso" }, "noAccess": { - "message": "No access" + "message": "Sem acesso" }, "collectionAdminConsoleManaged": { - "message": "This collection is only accessible from the admin console" + "message": "Esta coleção só é acessível a partir do console de administração" }, "organizationOptionsMenu": { "message": "Alternar Menu da Organização" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Gerenciar faturamento a partir do Portal do Provedor" + }, + "viewInfo": { + "message": "Ver informações" + }, + "viewAccess": { + "message": "Acesso à visualização" + }, + "noCollectionsSelected": { + "message": "Você não selecionou nenhuma coleção." + }, + "updateName": { + "message": "Atualizar nome" + }, + "updatedOrganizationName": { + "message": "Nome da organização atualizado" + }, + "providerPlan": { + "message": "Provedor de Serviços Gerenciados" + }, + "orgSeats": { + "message": "Lugares da Organização" + }, + "providerDiscount": { + "message": "Desconto de $AMOUNT$%", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index 936a8d4c9b3..d0211722be9 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Os ajustes à sua subscrição resultarão em alterações proporcionais aos seus totais de faturação. Se os novos utilizadores convidados excederem o número de licenças da sua subscrição, receberá imediatamente uma cobrança proporcional pelos utilizadores adicionais." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Se pretender adicionar mais" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "lugares sem a oferta agregada, por favor, contacte" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Os ajustes à sua subscrição resultarão em alterações proporcionais aos seus totais de faturação. Se os novos utilizadores convidados excederem o número de licenças da sua subscrição, receberá imediatamente uma cobrança proporcional pelos utilizadores adicionais até que o seu limite de $MAX$ licenças seja atingido.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Gerar um alias de e-mail com um serviço de reencaminhamento externo." }, + "forwarderError": { + "message": "Erro no $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Site: $WEBSITE$. Gerado pelo Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Token da API de $SERVICENAME$ inválido", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Token da API de $SERVICENAME$ inválido: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Não foi possível obter o ID da conta de e-mail mascarada de $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Domínio de $SERVICENAME$ inválido.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "URL de $SERVICENAME$ inválido.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Ocorreu um erro desconhecido de $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Reencaminhador desconhecido: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nome de domínio", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Conceder aos membros acesso às coleções adicionando-os a este grupo." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Só pode atribuir colecções que gere." + "restrictedCollectionAssignmentDesc": { + "message": "Só pode atribuir coleções que gere." }, "accessAllCollectionsDesc": { "message": "Conceder acesso a todas as coleções atuais e futuras." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Selecionar grupos" }, - "userPermissionOverrideHelper": { - "message": "As permissões definidas para um membro substituirão as permissões definidas pelo grupo desse membro" + "userPermissionOverrideHelperDesc": { + "message": "As permissões definidas para um membro substituirão as permissões definidas pelo grupo desse membro." }, "noMembersOrGroupsAdded": { "message": "Não foram adicionados membros ou grupos" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Atualize as suas definições de encriptação para cumprir as novas recomendações de segurança e melhorar a proteção da conta." }, - "changeKdfLoggedOutWarning": { - "message": "Ao prosseguir, terminará todas as sessões ativas. Terá de iniciar sessão novamente e concluir a configuração da verificação de dois passos. Recomendamos que exporte o seu cofre antes de alterar as definições de encriptação para evitar a perda de dados." + "kdfSettingsChangeLogoutWarning": { + "message": "Ao prosseguir, sairá de todas as sessões ativas. Terá de voltar a iniciar sessão e concluir a verificação de dois passos, caso exista. Recomendamos que exporte o seu cofre antes de alterar as definições de encriptação para evitar a perda de dados." }, "secretsManager": { "message": "Gestor de Segredos" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Não tem acesso para gerir esta coleção." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Faltam permissões Pode gerir" + }, + "grantAddAccessCollectionWarning": { + "message": "Conceda permissões Pode gerir para permitir a gestão completa da coleção, incluindo a eliminação da coleção." + }, "grantCollectionAccess": { "message": "Conceder a grupos ou membros acesso a esta coleção." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Com sucesso" }, - "viewCollection": { - "message": "Ver coleção" - }, "restrictedGroupAccess": { "message": "Não se pode adicionar a si próprio a grupos." }, - "restrictedCollectionAccess": { - "message": "Não se pode adicionar a si próprio a coleções." + "cannotAddYourselfToCollections": { + "message": "Não se pode adicionar a si próprio às coleções." }, "assign": { "message": "Atribuir" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Gira a faturação a partir do Portal do fornecedor" + }, + "viewInfo": { + "message": "Ver informações" + }, + "viewAccess": { + "message": "Ver acesso" + }, + "noCollectionsSelected": { + "message": "Não selecionou nenhuma coleção." + }, + "updateName": { + "message": "Atualizar nome" + }, + "updatedOrganizationName": { + "message": "Nome da organização atualizado" + }, + "providerPlan": { + "message": "Fornecedor de serviços geridos" + }, + "orgSeats": { + "message": "Lugares da organização" + }, + "providerDiscount": { + "message": "$AMOUNT$% de desconto", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Proteja a sua infraestrutura" + }, + "protectYourFamilyOrBusiness": { + "message": "Proteja a sua família ou empresa" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Colmatar as lacunas de segurança com relatórios de monitorização" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Mantenha-se à frente das vulnerabilidades de segurança atualizando para um plano pago para uma monitorização melhorada." } } diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 0a9f08e39d5..0583ac92f82 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Ajustările abonamentului dvs. vor avea ca rezultat modificări proporționale ale totalurilor dvs. de facturare. Dacă utilizatorii nou invitați depășesc numărul dvs. de licențe, veți primi imediat o taxă proporțională pentru utilizatorii suplimentari." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Ajustările abonamentului dvs. vor avea ca rezultat modificări proporționale ale totalurilor dvs. de facturare. Dacă utilizatorii nou invitați depășesc numărul dvs. de licențe, veți primi imediat o taxă proporțională pentru utilizatorii suplimentari, până când limita dvs. de $MAX$ licențe este atinsă.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generați un alias de e-mail cu un serviciu de redirecționare extern." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Nume gazdă", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 36cd7465cc1..64c547b1805 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Корректировка вашей подписки приведет к пропорциональным изменениям в сумме счетов. Если новых приглашенных пользователей будет больше, чем мест по подписке, вы сразу получите пропорциональную плату за дополнительных пользователей." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Корректировка вашей подписки приведет к пропорциональным изменениям в сумме счетов. Если новых приглашенных пользователей будет больше, чем мест по подписке, вы сразу получите пропорциональную плату за дополнительных пользователей, пока не будет достигнут лимит мест ($MAX$).", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Создать псевдоним электронной почты для внешней службы пересылки." }, + "forwarderError": { + "message": "Ошибка $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Сайт: $WEBSITE$. Создано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Неверный токен API $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Неверный токен $SERVICENAME$ API: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не удалось получить скрытый идентификатор email аккаунта $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Недопустимый домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Некорректный URL $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Произошла неизвестная ошибка $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Неизвестный форвардер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Имя хоста", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Предоставить доступ к коллекциям, при добавлении их в эту группу." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Вы можете назначать только те коллекции, которыми управляете." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Выбрать группы" }, - "userPermissionOverrideHelper": { - "message": "Разрешения, установленные для участника, заменят разрешения, установленные группой этого участника" + "userPermissionOverrideHelperDesc": { + "message": "Разрешения, установленные для участника, заменят разрешения, установленные группой этого участника." }, "noMembersOrGroupsAdded": { "message": "Не добавлены участники или группы" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Обновите настройки шифрования в соответствии с новыми рекомендациями по безопасности и улучшите защиту аккаунта." }, - "changeKdfLoggedOutWarning": { - "message": "При продолжении все активные сессии будут завершены. Вам потребуется авторизоваться повторно и выполнить настройку двухэтапной аутентификации. Мы рекомендуем экспортировать хранилище перед изменением настроек шифрования, чтобы предотвратить потерю данных." + "kdfSettingsChangeLogoutWarning": { + "message": "При продолжении все активные сессии будут завершены. Вам потребуется авторизоваться повторно и выполнить двухэтапную аутентификацию, если она включена. Мы рекомендуем экспортировать хранилище перед изменением настроек шифрования, чтобы предотвратить потерю данных." }, "secretsManager": { "message": "Менеджер секретов" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "У вас нет доступа к управлению этой коллекцией." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Недостаточно полномочий для управления" + }, + "grantAddAccessCollectionWarning": { + "message": "Предоставить возможность управлять разрешениями коллекций, включая их удаление." + }, "grantCollectionAccess": { "message": "Предоставить группам или участникам доступ к этой коллекции." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Успешно" }, - "viewCollection": { - "message": "Посмотреть коллекцию" - }, "restrictedGroupAccess": { "message": "Нельзя добавить самого себя в группы." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Нельзя добавить самого себя в коллекции." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Управление биллингом на портале провайдера" + }, + "viewInfo": { + "message": "Просмотр информации" + }, + "viewAccess": { + "message": "Просмотр доступа" + }, + "noCollectionsSelected": { + "message": "Вы не выбрали ни одной коллекции." + }, + "updateName": { + "message": "Обновить название" + }, + "updatedOrganizationName": { + "message": "Название организации обновлено" + }, + "providerPlan": { + "message": "Поставщик управляемых услуг" + }, + "orgSeats": { + "message": "Места организации" + }, + "providerDiscount": { + "message": "Скидка $AMOUNT$%", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Защитите вашу инфраструктуру" + }, + "protectYourFamilyOrBusiness": { + "message": "Защитите свою семью или бизнес" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index ece41d234cf..9397ac91399 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 7ed22b5a332..2c8a4802032 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Úprava predplatného bude mať za následok proporcionálnu zmenu celkového účtu. Ak počet nových odporúčaných používateľov presiahne počet miest vo vašom predplatnom, okamžite dostanete primeraný poplatok za ďalších používateľov." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Úprava predplatného bude mať za následok proporcionálnu zmenu celkového účtu. Ak počet nových odporúčaných používateľov presiahne počet miest vo vašom predplatnom, okamžite dostanete primeraný poplatok za ďalších používateľov, kým sa naplní obmedzenie $MAX$ miest.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Vytvoriť e-mailový alias pomocou externej služby preposielania." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Názov hostiteľa", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Povoľte prístup k zbierkam ich pridaním do tejto skupiny." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "You can only assign collections you manage." + "restrictedCollectionAssignmentDesc": { + "message": "Prideliť môžete iba zbierky ktoré spravujete." }, "accessAllCollectionsDesc": { "message": "Povoliť prístup k všetkým súčasným a budúcim zbierkam." @@ -6720,7 +6828,7 @@ "selectGroups": { "message": "Vyberte skupiny" }, - "userPermissionOverrideHelper": { + "userPermissionOverrideHelperDesc": { "message": "Povolenia nastavené pre člena nahradia povolenia nastavené skupinou, ktorej je členom" }, "noMembersOrGroupsAdded": { @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Aktualizujte vaše nastavenie šifrovania aby ste boli v súlade s bezpečnostnými odporúčaniami a vylepšili si tak ochranu vášho konta." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Nemáte prístup k spravovaniu tejto zbierky." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Povoľte skupinám, alebo jednotlivcom prístup k tejto zbierke." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "Pozrieť zbierku" - }, "restrictedGroupAccess": { "message": "Seba nemôžete pridať do skupín." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Seba nemôžete pridať do zbierok." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Spravujte fakturáciu cez portál poskytovateľa" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Upraviť názov" + }, + "updatedOrganizationName": { + "message": "Názov organizácie upravený" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Zľava", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Zabezpečte si infraštruktúru" + }, + "protectYourFamilyOrBusiness": { + "message": "Chráňte svoju rodinu alebo podnikanie" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 2b6fd699c28..ee22529b11d 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Ustvari psevdonim (alias) za elektronski naslov z uporabo zunanjega ponudnika posredovanja pošte." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Popravite svoje nastavitve šifriranja, da bodo v skladu z novimi priporočili za varnost, in izboljšajte zaščito svojega računa." }, - "changeKdfLoggedOutWarning": { - "message": "Po tem dejanju boste odjavljeni iz vseh aktivnih sej (na vseh napravah). Prijaviti se boste morali ponovno in zaključiti nastavitev dvostopenjske prijave. Priporočamo vam, da pred tem izvozite svoje podatke, da jih v tem procesu ne bi izgubili." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index e2ee1ad4d55..02a23946cf8 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -2789,10 +2789,10 @@ "message": "Све" }, "addAccess": { - "message": "Add Access" + "message": "Додај приступ" }, "addAccessFilter": { - "message": "Add Access Filter" + "message": "Додај филтер приступа" }, "refresh": { "message": "Освежи" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Подешавање ваше претплате резултираће прорисаним променама у вашим новчаним вредностима. Ако ново позвани корисници прелази ваше лиценце за претплату, одмах ћете добити прорисану накнаду за додатни корисник." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Ако желите да додате додатна" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "седишта без понуде у пакету, контактирајте" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Подешавање ваше претплате резултираће прорисаним променама у вашим новчаним вредностима. Ако ново позвани корисници прелази ваше лиценце за претплату, одмах ћете добити прорисану накнаду за додатни корисник док ваши лимит $MAX$ није достигнут.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Генеришите псеудоним е-поште помоћу екстерне услуге прослеђивања." }, + "forwarderError": { + "message": "$SERVICENAME$ грешка: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Вебсајт: $WEBSITE$. Генерисао Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Погрешан АПИ токен $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Погрешан АПИ токен $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Није могуће добити ИД налога маскираног имејла $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Погрешан домен $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Погрешан УРЛ $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Непозната грешка $SERVICENAME$-а.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Непознати шпедитер: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Име домаћина", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Можете да доделите само колекције којима управљате." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Изаберите групе" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Дозволе постављене за члана ће заменити дозволе које је поставила група тог члана." }, "noMembersOrGroupsAdded": { "message": "Нема додатих чланова или група" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Ажурирајте подешавања шифровања да бисте испунили нове безбедносне препоруке и побољшали заштиту налога." }, - "changeKdfLoggedOutWarning": { - "message": "Ако наставите, одјавићете се са свих активних сесија. Мораћете поново да се пријавите и завршите подешавање пријаве у два корака. Препоручујемо да извезете трезор пре него што промените подешавања шифровања да бисте спречили губитак података." + "kdfSettingsChangeLogoutWarning": { + "message": "Ако наставите, одјавићете се са свих активних сесија. Мораћете поново да се пријавите и завршитепријаве у два корака, ако имате. Препоручујемо да извезете трезор пре него што промените подешавања шифровања да бисте спречили губитак података." }, "secretsManager": { "message": "Менаџер тајни" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "Немате приступ за управљање овом колекцијом." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Фале дозволе „Може да управља“" + }, + "grantAddAccessCollectionWarning": { + "message": "Додатје дозволе „Може да управља“ да би се омогућило потпуно управљање наплатом укључујући брисање колекције." + }, "grantCollectionAccess": { "message": "Одобрите групама или члановима приступ овој колекцији." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Успех" }, - "viewCollection": { - "message": "Преглед колекције" - }, "restrictedGroupAccess": { "message": "Не можете да се додате у групе." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Не можете да се додате у колекције." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Управљајте наплатом из Provider Portal" + }, + "viewInfo": { + "message": "Прикажи информације" + }, + "viewAccess": { + "message": "Прикажи приступ" + }, + "noCollectionsSelected": { + "message": "Нисте изабрали ниједну колекцију." + }, + "updateName": { + "message": "Ажурирајте име" + }, + "updatedOrganizationName": { + "message": "Ажурирано име организације" + }, + "providerPlan": { + "message": "Управљени провајдери сервиса" + }, + "orgSeats": { + "message": "Седиста организације" + }, + "providerDiscount": { + "message": "$AMOUNT$% попуста", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Обезбедите своју инфраструктуру" + }, + "protectYourFamilyOrBusiness": { + "message": "Заштитите своју породицу или посао" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Затворите безбедносне празнине извештајима о надгледању" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Будите испред безбедносних пропуста надоградњом на плаћени план за побољшано праћење." } } diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index ce0ceac240c..257591256c3 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 871f27ec7fb..bdb9ab84b5d 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generera ett e-postalias med en extern vidarebefordranstjänst." }, + "forwarderError": { + "message": "$SERVICENAME$-fel: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Ogiltig $SERVICENAME$-domän.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Ogiltig $SERVICENAME$-URL.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,8 +6594,8 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { - "message": "Du kan bara tilldela samlingar som du hanterar." + "restrictedCollectionAssignmentDesc": { + "message": "Du kan endast tilldela samlingar som du hanterar." }, "accessAllCollectionsDesc": { "message": "Grant access to all current and future collections." @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Välj grupper" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Ge grupper eller medlemmar tillgång till denna samling." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "Visa samling" - }, "restrictedGroupAccess": { "message": "Du kan inte lägga till dig själv i grupper." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Du kan inte lägga till dig själv i samlingar." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Uppdatera namn" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% rabatt", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Säkra din infrastruktur" + }, + "protectYourFamilyOrBusiness": { + "message": "Skydda din familj eller ditt företag" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 8c37b919aff..96703c2a1fc 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index a5454461108..5646dc283db 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 6d22e31a5cd..783d452afdd 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Aboneliğinizde yapacağınız değişiklikler toplam faturanızın değişmesine yol açacaktır. Yeni davet edilen üyelerin sayısı abonelik paketinizdeki üye sayısını aşarsa ek üyeler için derhal ödeme alınır." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Aboneliğinizde yapacağınız değişiklikler toplam faturanızın değişmesine yol açacaktır. Yeni davet edilen üyelerin sayısı abonelik paketinizdeki üye sayısını aşarsa $MAX$ üye sınırınıza ulaşana dek ek üyeler için ödeme alınır.", "placeholders": { @@ -4441,7 +4447,7 @@ "message": "Kişisel kasayı kaldır" }, "personalOwnershipPolicyDesc": { - "message": "Kişisel sahiplik seçeneğini kapatarak kullanıcıların kasadaki kayıtlarını bir kuruluşa kaydetmesini zorunlu kılabilirsiniz." + "message": "Kişisel kasa seçeneğini kapatarak kullanıcıların kayıtlarını bir kuruluşa kaydetmesini zorunlu kılabilirsiniz." }, "personalOwnershipExemption": { "message": "Kuruluş sahipleri ve yöneticileri bu ilkenin uygulanmasından muaf tutulur." @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Harici bir yönlendirme servisiyle e-posta maskesi oluştur." }, + "forwarderError": { + "message": "$SERVICENAME$ hatası: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Web sitesi: $WEBSITE$. Bitwarden tarafından üretildi.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Sunucu", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Kullanıcıları bu gruba ekleyerek koleksiyonlara erişim izni verin." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Grupları seçin" }, - "userPermissionOverrideHelper": { - "message": "Bir üye için ayarlanan izinler, o üyenin grubu tarafından ayarlanan izinlerin yerini alacak" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "Hiç üye veya grup eklenmedi" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Yeni güvenlik önerilerini karşılamak ve hesap korumasını iyileştirmek için şifreleme ayarlarınızı güncelleyin." }, - "changeKdfLoggedOutWarning": { - "message": "Devam ettiğinizde tüm aktif oturumlarınız kapatılacaktır. Tekrar giriş yapmanız ve iki aşamalı giriş kurulumunu tamamlamanız gerekecektir. Veri kaybını önlemek için, şifreleme ayarlarınızı değiştirmeden önce kasanızı dışa aktarmanızı öneririz." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Sır Yöneticisi" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Gruplara veya üyelere bu koleksiyona erişim izni verin." }, @@ -7638,14 +7752,11 @@ "success": { "message": "Başarılı" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "Kendinizi gruplara ekleyemezsiniz." }, - "restrictedCollectionAccess": { - "message": "Kendinizi koleksiyonlara ekleyemezsiniz." + "cannotAddYourselfToCollections": { + "message": "You cannot add yourself to collections." }, "assign": { "message": "Ata" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index bf7c2b746de..5e250f3363b 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Коригування передплати призведе до відповідної зміни суми вашого рахунку. Якщо нові запрошені користувачі перевищать кількість передплачених місць, з вас негайно буде стягнуто пропорційну оплату за додаткових користувачів." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "Якщо ви хочете додати більше" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "місць без пропозиції комплекту, зв'яжіться з" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Коригування передплати призведе до відповідної зміни суми вашого рахунку. Якщо нові запрошені користувачі перевищать кількість передплачених місць, з вас негайно буде стягнуто пропорційну оплату за додаткових користувачів, доки не буде досягнуто встановленого вами обмеження $MAX$ місць.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Згенеруйте псевдонім е-пошти зі стороннім сервісом пересилання." }, + "forwarderError": { + "message": "Помилка $SERVICENAME$: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Згенеровано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Вебсайт: $WEBSITE$. Згенеровано Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Недійсний токен API для $SERVICENAME$", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Недійсний токен API для $SERVICENAME$: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Не вдалося отримати ідентифікатор замаскованої е-пошти облікового запису для $SERVICENAME$.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Недійсний домен для $SERVICENAME$.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Недійсна URL-адреса для $SERVICENAME$.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Сталася невідома помилка $SERVICENAME$.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Невідомий засіб переспрямування: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Ім'я вузла", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Надати доступ до збірок, додавши їх до цієї групи." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "Ви можете призначити лише збірки, якими керуєте." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Вибрати групи" }, - "userPermissionOverrideHelper": { - "message": "Дозволи, встановлені для учасника, вилучать дозволи, встановлені групою учасника" + "userPermissionOverrideHelperDesc": { + "message": "Дозволи, встановлені для учасника, вилучать дозволи, встановлені групою учасника." }, "noMembersOrGroupsAdded": { "message": "Не додано жодного учасника чи групи" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Оновіть свої налаштування шифрування згідно з новими рекомендаціями щодо безпеки для вдосконалення захисту облікового запису." }, - "changeKdfLoggedOutWarning": { - "message": "Продовжуючи, ви вийдете з усіх активних сеансів. Необхідно буде повторно виконати вхід і пройти двоетапну перевірку. Перед зміною налаштувань шифрування ми рекомендуємо експортувати ваше сховище, щоб запобігти можливій втраті даних." + "kdfSettingsChangeLogoutWarning": { + "message": "Продовжуючи, ви вийдете з усіх активних сеансів. Необхідно буде повторно виконати вхід і пройти двоетапну перевірку, якщо вона увімкнена. Перед зміною налаштувань шифрування ми рекомендуємо експортувати ваше сховище, щоб запобігти можливій втраті даних." }, "secretsManager": { "message": "Менеджер секретів" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "У вас немає доступу до керування цією збіркою." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Немає дозволу \"Може керувати\"" + }, + "grantAddAccessCollectionWarning": { + "message": "Надайте дозвіл \"Може керувати\" для можливості повноцінного керування збірками, включно з видаленням." + }, "grantCollectionAccess": { "message": "Надайте групам або учасникам доступ до цієї збірки." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Успішно" }, - "viewCollection": { - "message": "Переглянути збірку" - }, "restrictedGroupAccess": { "message": "Ви не можете додати себе до груп." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "Ви не можете додати себе до збірок." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Керування рахунками на порталі провайдера" + }, + "viewInfo": { + "message": "Переглянути інформацію" + }, + "viewAccess": { + "message": "Переглянути доступ" + }, + "noCollectionsSelected": { + "message": "Ви не вибрали жодної збірки." + }, + "updateName": { + "message": "Оновити назву" + }, + "updatedOrganizationName": { + "message": "Назву організації оновлено" + }, + "providerPlan": { + "message": "Керований постачальник послуг" + }, + "orgSeats": { + "message": "Місць в організації" + }, + "providerDiscount": { + "message": "$AMOUNT$% знижка", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Захистіть свою інфраструктуру" + }, + "protectYourFamilyOrBusiness": { + "message": "Захистіть свою сім'ю або бізнес" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Закрийте прогалини в безпеці зі звітами моніторингу" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Попереджайте вразливості безпеки, передплативши тарифний план для посиленого моніторингу." } } diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 806c98e9c11..c5008d2b133 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members." }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "Adjustments to your subscription will result in prorated changes to your billing totals. If newly invited members exceed your subscription seats, you will immediately receive a prorated charge for the additional members until your $MAX$ seat limit is reached.", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "Generate an email alias with an external forwarding service." }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "Hostname", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "Grant access to collections by adding them to this group." }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "Select groups" }, - "userPermissionOverrideHelper": { - "message": "Permissions set for a member will replace permissions set by that member's group" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "No members or groups added" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "Update your encryption settings to meet new security recommendations and improve account protection." }, - "changeKdfLoggedOutWarning": { - "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login setup. We recommend exporting your vault before changing your encryption settings to prevent data loss." + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "View info" + }, + "viewAccess": { + "message": "View access" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "Update name" + }, + "updatedOrganizationName": { + "message": "Updated organization name" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 5ff0721b443..59ff69500db 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -1355,7 +1355,7 @@ "description": "This will be part of a larger sentence, that will read like this: If you don't have any data to import, you can create a new item instead. (Optional second half: You may need to wait until your administrator confirms your organization membership.)" }, "onboardingImportDataDetailsLink": { - "message": "新项目", + "message": "新的项目", "description": "This will be part of a larger sentence, that will read like this: If you don't have any data to import, you can create a new item instead. (Optional second half: You may need to wait until your administrator confirms your organization membership.)" }, "onboardingImportDataDetailsPartTwoNoOrgs": { @@ -1863,7 +1863,7 @@ "message": "发现暴露的密码" }, "exposedPasswordsFoundReportDesc": { - "message": "We found $COUNT$ items in your $VAULT$ that have passwords that were exposed in known data breaches. You should change them to use a new password.", + "message": "我们在您的 $VAULT$ 中发现了 $COUNT$ 个在已知的数据泄露事件中暴露了密码的项目。您应更改它们以使用新的密码。", "placeholders": { "count": { "content": "$1", @@ -1900,7 +1900,7 @@ "message": "发现弱密码" }, "weakPasswordsFoundReportDesc": { - "message": "We found $COUNT$ items in your $VAULT$ with passwords that are not strong. You should update them to use stronger passwords.", + "message": "我们在您的 $VAULT$ 中发现了 $COUNT$ 个密码不够强的项目。您应更新它们以使用更强的密码。", "placeholders": { "count": { "content": "$1", @@ -3503,7 +3503,7 @@ "message": "账户类型" }, "bankAccountTypeCompany": { - "message": "公司(商业)" + "message": "公司(企业)" }, "bankAccountTypeIndividual": { "message": "个体(个人)" @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "调整订阅将导致按比例调整您的计费总金额。如果新邀请的成员超过了您的订阅席位,您将立即收到按比例的额外成员费用。" }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "如果您想要添加额外的" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "无捆绑优惠的座位,请联系" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "调整订阅将导致按比例调整您的计费总金额。如果新邀请的成员超过了您的订阅席位,您将立即收到按比例的额外成员费用,直到达到您的 $MAX$ 席位限制。", "placeholders": { @@ -3680,7 +3686,7 @@ "message": "退款" }, "nothingSelected": { - "message": "您没有选择任何内容。" + "message": "您尚未选择任何内容。" }, "acceptPolicies": { "message": "选中此框表示您同意:" @@ -4977,13 +4983,13 @@ "message": "创建一个新的客户组织,该组织将作为提供商与你关联。您将可以访问和管理这个组织。" }, "newClient": { - "message": "新客户端" + "message": "新增客户" }, "addExistingOrganization": { "message": "添加现有组织" }, "addNewOrganization": { - "message": "添加新组织" + "message": "添加新的组织" }, "myProvider": { "message": "我的提供商" @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "使用外部转发服务生成一个电子邮件别名。" }, + "forwarderError": { + "message": "$SERVICENAME$ 错误:$ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "网站:$WEBSITE$。由 Bitwarden 生成。", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "无效的 $SERVICENAME$ API 令牌", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "无效的 $SERVICENAME$ API 令牌:$ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "无法获取 $SERVICENAME$ 电子邮件账户 ID。", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "无效的 $SERVICENAME$ 域名。", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "无效的 $SERVICENAME$ URL。", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "发生未知的 $SERVICENAME$ 错误。", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "未知的转发服务:$SERVICENAME$。", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主机名", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "通过将集合添加到此群组来授予对集合的访问权限。" }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "您只能分配您管理的集合。" }, "accessAllCollectionsDesc": { @@ -6691,7 +6799,7 @@ "message": "无法完成生物识别。" }, "needADifferentMethod": { - "message": "Need a different method?" + "message": "尝试其他方式吗?" }, "useMasterPassword": { "message": "使用主密码" @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "选择群组" }, - "userPermissionOverrideHelper": { - "message": "为成员设置的权限将取代该成员所在群组设置的权限" + "userPermissionOverrideHelperDesc": { + "message": "为成员设置的权限将替换为该成员群组设置的权限。" }, "noMembersOrGroupsAdded": { "message": "未添加任何成员或群组" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "更新您的加密设置以满足新的安全建议以及增强账户保护。" }, - "changeKdfLoggedOutWarning": { - "message": "接下来将会注销您所有的活动会话。您将需要重新登录并完成两步登录设置。我们建议在更改您的加密设置之前导出您的密码库,以防数据丢失。" + "kdfSettingsChangeLogoutWarning": { + "message": "接下来将会注销您所有的活动会话。您需要重新登录并完成两步登录(如果有)。我们建议您在更改加密设置前导出密码库,以防止数据丢失。" }, "secretsManager": { "message": "机密管理器" @@ -6969,10 +7077,10 @@ "message": "创建账户" }, "createSecret": { - "message": "创建一个机密" + "message": "创建机密" }, "createProject": { - "message": "创建一个工程" + "message": "创建工程" }, "createServiceAccount": { "message": "创建服务账户" @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "您没有管理此集合的权限。" }, + "grantAddAccessCollectionWarningTitle": { + "message": "缺少「可以管理」权限" + }, + "grantAddAccessCollectionWarning": { + "message": "授予「可以管理」权限以允许完整的集合管理,包括删除集合。" + }, "grantCollectionAccess": { "message": "授予群组或成员对此集合的访问权限。" }, @@ -7636,15 +7750,12 @@ "message": "提供商门户" }, "success": { - "message": "Success" - }, - "viewCollection": { - "message": "查看集合" + "message": "成功" }, "restrictedGroupAccess": { "message": "您不能将自己添加到群组。" }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "您不能将自己添加到集合。" }, "assign": { @@ -7691,13 +7802,13 @@ "message": "已分配" }, "used": { - "message": "已用" + "message": "已使用" }, "remaining": { - "message": "余额:" + "message": "剩余" }, "unlinkOrganization": { - "message": "脱离组织" + "message": "取消链接组织" }, "manageSeats": { "message": "管理席位" @@ -7873,7 +7984,7 @@ "message": "从机器账户中移除人员并不会移除他们已创建的访问令牌。基于安全方面的最佳做法,建议吊销从机器账户中被移除的人员创建的访问令牌。" }, "smAccessRemovalWarningMaTitle": { - "message": "移除此机器账户的访问权限" + "message": "移除对此机器账户的访问权限" }, "smAccessRemovalWarningMaMessage": { "message": "此操作将移除您对此机器账户的访问权限。" @@ -7945,11 +8056,11 @@ "message": "注意:从 2024 年 5 月 2 日起,未分配的组织项目在您所有设备的「所有密码库」视图中将不再可见,只能通过管理控制台访问。" }, "unassignedItemsBannerCTAPartOne": { - "message": "Assign these items to a collection from the", + "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." }, "unassignedItemsBannerCTAPartTwo": { - "message": "以使其可见。", + "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." }, "deleteProvider": { @@ -7968,7 +8079,7 @@ } }, "deleteProviderWarningDescription": { - "message": "删除 $ID$ 之前,您必须取消链接所有的客户端。", + "message": "删除 $ID$ 之前,您必须取消链接所有的客户。", "placeholders": { "id": { "content": "$1", @@ -8047,7 +8158,7 @@ "message": "创建一个新的客户组织作为提供商来管理。附加席位将反映在下一个计费周期中。" }, "selectAPlan": { - "message": "选择套餐" + "message": "选择一个计划" }, "thirtyFivePercentDiscount": { "message": "35% 折扣" @@ -8065,7 +8176,7 @@ "message": "Successfully created new client" }, "noAccess": { - "message": "暂无权限" + "message": "无访问权限" }, "collectionAdminConsoleManaged": { "message": "此集合只能从管理控制台访问" @@ -8080,6 +8191,48 @@ "message": "选择集合项目" }, "manageBillingFromProviderPortalMessage": { - "message": "在供应商门户中管理账单" + "message": "从提供商门户管理账单" + }, + "viewInfo": { + "message": "查看信息" + }, + "viewAccess": { + "message": "查看访问权限" + }, + "noCollectionsSelected": { + "message": "您尚未选择任何集合。" + }, + "updateName": { + "message": "更新名称" + }, + "updatedOrganizationName": { + "message": "更新了组织名称" + }, + "providerPlan": { + "message": "托管服务提供商" + }, + "orgSeats": { + "message": "组织席位" + }, + "providerDiscount": { + "message": "$AMOUNT$ 折扣", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "保护您的基础设施" + }, + "protectYourFamilyOrBusiness": { + "message": "保护您的家庭或企业" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "通过监控报告弥补安全漏洞" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "升级到付费计划以加强监控,从而提前发现安全漏洞。" } } diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 781d2ed5400..8040d218fd7 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -2299,7 +2299,7 @@ "description": "Payment/credit transactions." }, "noTransactions": { - "message": "無交易記錄" + "message": "無交易記錄。" }, "chargeNoun": { "message": "費用", @@ -2696,7 +2696,7 @@ "message": "唯讀" }, "newCollection": { - "message": "新集合" + "message": "新增集合" }, "addCollection": { "message": "新增集合" @@ -2789,7 +2789,7 @@ "message": "全部" }, "addAccess": { - "message": "Add Access" + "message": "添加存取權限" }, "addAccessFilter": { "message": "Add Access Filter" @@ -3029,7 +3029,7 @@ } }, "deletedCollections": { - "message": "已刪除集合" + "message": "已刪除的集合" }, "deletedCollectionId": { "message": "已刪除集合 $ID$。", @@ -3565,6 +3565,12 @@ "subscriptionUserSeatsUnlimitedAutoscale": { "message": "調整訂閱將會依比例變更您的計費總額。若新邀請的成員超過您的訂閱席位,您將立即收到依比例收取的額外使用者費用。" }, + "smStandaloneTrialSeatCountUpdateMessageFragment1": { + "message": "If you want to add additional" + }, + "smStandaloneTrialSeatCountUpdateMessageFragment2": { + "message": "seats without the bundled offer, please contact" + }, "subscriptionUserSeatsLimitedAutoscale": { "message": "調整訂閱將會依比例變更您的計費總額。若新邀請的成員超過您的訂閱席位,您將立即收到依比例收取的額外使用者費用,直到您達到 $MAX$ 席位限制。", "placeholders": { @@ -5808,6 +5814,108 @@ "forwardedEmailDesc": { "message": "使用外部轉寄服務產生一個電子郵件別名。" }, + "forwarderError": { + "message": "$SERVICENAME$ error: $ERRORMESSAGE$", + "description": "Reports an error returned by a forwarding service to the user.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Invalid characters in domain name." + } + } + }, + "forwarderGeneratedBy": { + "message": "Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen." + }, + "forwarderGeneratedByWithWebsite": { + "message": "Website: $WEBSITE$. Generated by Bitwarden.", + "description": "Displayed with the address on the forwarding service's configuration screen.", + "placeholders": { + "WEBSITE": { + "content": "$1", + "example": "www.example.com" + } + } + }, + "forwaderInvalidToken": { + "message": "Invalid $SERVICENAME$ API token", + "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwaderInvalidTokenWithMessage": { + "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + }, + "errormessage": { + "content": "$2", + "example": "Please verify your email address to continue." + } + } + }, + "forwarderNoAccountId": { + "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "description": "Displayed when the forwarding service fails to return an account ID.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoDomain": { + "message": "Invalid $SERVICENAME$ domain.", + "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderNoUrl": { + "message": "Invalid $SERVICENAME$ url.", + "description": "Displayed when the url of the forwarding service wasn't supplied.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownError": { + "message": "Unknown $SERVICENAME$ error occurred.", + "description": "Displayed when the forwarding service failed due to an unknown error.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "SimpleLogin" + } + } + }, + "forwarderUnknownForwarder": { + "message": "Unknown forwarder: '$SERVICENAME$'.", + "description": "Displayed when the forwarding service is not supported.", + "placeholders": { + "servicename": { + "content": "$1", + "example": "JustTrust.us" + } + } + }, "hostname": { "message": "主機名稱", "description": "Part of a URL." @@ -6486,7 +6594,7 @@ "editGroupCollectionsDesc": { "message": "透過將他們添加到此群組,授予對集合的存取權限。" }, - "editGroupCollectionsRestrictionsDesc": { + "restrictedCollectionAssignmentDesc": { "message": "You can only assign collections you manage." }, "accessAllCollectionsDesc": { @@ -6720,8 +6828,8 @@ "selectGroups": { "message": "選擇群組" }, - "userPermissionOverrideHelper": { - "message": "為成員設定的權限將取代該成員所在群組設定的權限" + "userPermissionOverrideHelperDesc": { + "message": "Permissions set for a member will replace permissions set by that member's group." }, "noMembersOrGroupsAdded": { "message": "未新增任何成員或群組" @@ -6912,8 +7020,8 @@ "updateLowKdfIterationsDesc": { "message": "更新您的加密設定以滿足新的安全建議以及提升帳號保護。" }, - "changeKdfLoggedOutWarning": { - "message": "繼續操作會登出您所有活動工作階段。您需要重新登入並完成兩步驟登入設定。 我們建議在變更加密設定之前匯出您的密碼庫,以防止資料遺失。" + "kdfSettingsChangeLogoutWarning": { + "message": "Proceeding will log you out of all active sessions. You will need to log back in and complete two-step login, if any. We recommend exporting your vault before changing your encryption settings to prevent data loss." }, "secretsManager": { "message": "Secrets Manager" @@ -7431,7 +7539,7 @@ "message": "Owners and admins can manage all collections and items" }, "updatedCollectionManagement": { - "message": "Updated collection management setting" + "message": "更新了集合管理設定" }, "passwordManagerPlanPrice": { "message": "密碼管理器方案價格" @@ -7491,10 +7599,10 @@ "message": "密碼金鑰不會被複製" }, "passkeyNotCopiedAlert": { - "message": "密碼金鑰不會被複製到克隆的項目。您想繼續克隆該項目嗎?" + "message": "密碼金鑰不會被複製到新的項目中。您要繼續複製此項目嗎?" }, "modifiedCollectionManagement": { - "message": "Modified collection management setting $ID$.", + "message": "修改了集合管理設定 $ID$。", "placeholders": { "id": { "content": "$1", @@ -7533,6 +7641,12 @@ "readOnlyCollectionAccess": { "message": "You do not have access to manage this collection." }, + "grantAddAccessCollectionWarningTitle": { + "message": "Missing Can Manage Permissions" + }, + "grantAddAccessCollectionWarning": { + "message": "Grant Can manage permissions to allow full collection management including deletion of collection." + }, "grantCollectionAccess": { "message": "Grant groups or members access to this collection." }, @@ -7568,7 +7682,7 @@ "description": "This describes new features and improvements for user roles and collections" }, "collectionEnhancementsLearnMore": { - "message": "Learn more about collection management" + "message": "深入了解集合管理" }, "organizationInformation": { "message": "組織資訊" @@ -7583,7 +7697,7 @@ "message": "We've sent a confirmation email to your email at " }, "confirmCollectionEnhancementsDialogTitle": { - "message": "此操作是不可逆轉的" + "message": "此動作是不可逆轉的" }, "confirmCollectionEnhancementsDialogContent": { "message": "Turning on this feature will deprecate the manager role and replace it with a Can manage permission. This will take a few moments. Do not make any organization changes until it is complete. Are you sure you want to proceed?" @@ -7638,13 +7752,10 @@ "success": { "message": "Success" }, - "viewCollection": { - "message": "View collection" - }, "restrictedGroupAccess": { "message": "You cannot add yourself to groups." }, - "restrictedCollectionAccess": { + "cannotAddYourselfToCollections": { "message": "You cannot add yourself to collections." }, "assign": { @@ -7773,15 +7884,15 @@ "message": "Machine accounts cannot be created in suspended organizations. Please contact your organization owner for assistance." }, "machineAccount": { - "message": "Machine account", + "message": "機器帳戶", "description": "A machine user which can be used to automate processes and access secrets in the system." }, "machineAccounts": { - "message": "Machine accounts", + "message": "機器帳戶", "description": "The title for the section that deals with machine accounts." }, "newMachineAccount": { - "message": "New machine account", + "message": "新增機器賬戶", "description": "Title for creating a new machine account." }, "machineAccountsNoItemsMessage": { @@ -7789,19 +7900,19 @@ "description": "Message to encourage the user to start creating machine accounts." }, "machineAccountsNoItemsTitle": { - "message": "Nothing to show yet", + "message": "尚無要顯示的內容", "description": "Title to indicate that there are no machine accounts to display." }, "deleteMachineAccounts": { - "message": "Delete machine accounts", + "message": "刪除機器帳戶", "description": "Title for the action to delete one or multiple machine accounts." }, "deleteMachineAccount": { - "message": "Delete machine account", + "message": "刪除機器帳戶", "description": "Title for the action to delete a single machine account." }, "viewMachineAccount": { - "message": "View machine account", + "message": "檢視機器賬戶", "description": "Action to view the details of a machine account." }, "deleteMachineAccountDialogMessage": { @@ -7817,7 +7928,7 @@ "message": "Deleting machine accounts is permanent and irreversible." }, "deleteMachineAccountsConfirmMessage": { - "message": "Delete $COUNT$ machine accounts", + "message": "刪除 $COUNT$ 個機器賬戶", "placeholders": { "count": { "content": "$1", @@ -7826,29 +7937,29 @@ } }, "deleteMachineAccountToast": { - "message": "Machine account deleted" + "message": "機器帳戶已刪除" }, "deleteMachineAccountsToast": { - "message": "Machine accounts deleted" + "message": "機器帳戶已刪除" }, "searchMachineAccounts": { - "message": "Search machine accounts", + "message": "搜尋機器帳戶", "description": "Placeholder text for searching machine accounts." }, "editMachineAccount": { - "message": "Edit machine account", + "message": "編輯機器賬戶", "description": "Title for editing a machine account." }, "machineAccountName": { - "message": "Machine account name", + "message": "機器賬戶名稱", "description": "Label for the name of a machine account" }, "machineAccountCreated": { - "message": "Machine account created", + "message": "機器賬戶已建立", "description": "Notifies that a new machine account has been created" }, "machineAccountUpdated": { - "message": "Machine account updated", + "message": "機器賬戶已更新", "description": "Notifies that a machine account has been updated" }, "projectMachineAccountsDescription": { @@ -7867,16 +7978,16 @@ "message": "Assign projects to this machine account. " }, "createMachineAccount": { - "message": "Create a machine account" + "message": "建立機器賬戶" }, "maPeopleWarningMessage": { "message": "Removing people from a machine account does not remove the access tokens they created. For security best practice, it is recommended to revoke access tokens created by people removed from a machine account." }, "smAccessRemovalWarningMaTitle": { - "message": "Remove access to this machine account" + "message": "移除對此機器賬戶的存取權限" }, "smAccessRemovalWarningMaMessage": { - "message": "This action will remove your access to the machine account." + "message": "此動作將移除您對此機器賬戶的存取權限" }, "machineAccountsIncluded": { "message": "$COUNT$ machine accounts included", @@ -7930,7 +8041,7 @@ "message": "Max potential machine account cost" }, "machineAccountAccessUpdated": { - "message": "Machine account access updated" + "message": "機器賬戶存取權限已更新" }, "restrictedGroupAccessDesc": { "message": "You cannot add yourself to a group." @@ -7956,10 +8067,10 @@ "message": "Delete provider" }, "deleteProviderConfirmation": { - "message": "Deleting a provider is permanent and irreversible. Enter your master password to confirm the deletion of the provider and all associated data." + "message": "刪除提供者是永久性的且不可逆轉。輸入您的主密碼以確認刪除提供者和所有關聯資料。" }, "deleteProviderName": { - "message": "Cannot delete $ID$", + "message": "無法刪除 $ID$", "placeholders": { "id": { "content": "$1", @@ -8011,37 +8122,37 @@ "message": "Use Bitwarden Secrets Manager SDK in the following programming languages to build your own applications." }, "setUpGithubActions": { - "message": "Set up Github Actions" + "message": "設定 Github Actions" }, "setUpGitlabCICD": { - "message": "Set up GitLab CI/CD" + "message": "設定 GitLab CI/CD" }, "setUpAnsible": { - "message": "Set up Ansible" + "message": "設定 Ansible" }, "cSharpSDKRepo": { - "message": "View C# repository" + "message": "檢視 C# 儲存庫" }, "cPlusPlusSDKRepo": { - "message": "View C++ repository" + "message": "檢視 C++ 儲存庫" }, "jsWebAssemblySDKRepo": { - "message": "View JS WebAssembly repository" + "message": "檢視 JS WebAssembly 儲存庫" }, "javaSDKRepo": { - "message": "View Java repository" + "message": "檢視 Java 儲存庫" }, "pythonSDKRepo": { - "message": "View Python repository" + "message": "檢視 Python 儲存庫" }, "phpSDKRepo": { - "message": "View php repository" + "message": "檢視 PHP 儲存庫" }, "rubySDKRepo": { - "message": "View Ruby repository" + "message": "檢視 Ruby 儲存庫" }, "goSDKRepo": { - "message": "View Go repository" + "message": "檢視 Go 儲存庫" }, "createNewClientToManageAsProvider": { "message": "Create a new client organization to manage as a Provider. Additional seats will be reflected in the next billing cycle." @@ -8056,7 +8167,7 @@ "message": "month per member" }, "seats": { - "message": "Seats" + "message": "席位" }, "addOrganization": { "message": "Add organization" @@ -8065,7 +8176,7 @@ "message": "Successfully created new client" }, "noAccess": { - "message": "No access" + "message": "無存取權限" }, "collectionAdminConsoleManaged": { "message": "This collection is only accessible from the admin console" @@ -8081,5 +8192,47 @@ }, "manageBillingFromProviderPortalMessage": { "message": "Manage billing from the Provider Portal" + }, + "viewInfo": { + "message": "檢視資訊" + }, + "viewAccess": { + "message": "檢視存取權限" + }, + "noCollectionsSelected": { + "message": "You have not selected any collections." + }, + "updateName": { + "message": "更新名称" + }, + "updatedOrganizationName": { + "message": "更新了組織名稱" + }, + "providerPlan": { + "message": "Managed Service Provider" + }, + "orgSeats": { + "message": "Organization Seats" + }, + "providerDiscount": { + "message": "$AMOUNT$% Discount", + "placeholders": { + "amount": { + "content": "$1", + "example": "2" + } + } + }, + "secureYourInfrastructure": { + "message": "Secure your infrastructure" + }, + "protectYourFamilyOrBusiness": { + "message": "Protect your family or business" + }, + "upgradeOrganizationCloseSecurityGaps": { + "message": "Close security gaps with monitoring reports" + }, + "upgradeOrganizationCloseSecurityGapsDesc": { + "message": "Stay ahead of security vulnerabilities by upgrading to a paid plan for enhanced monitoring." } } diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index 543d7f25b12..07d244ee602 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -27,12 +27,7 @@ "strictTemplates": true, "preserveWhitespaces": true }, - "files": [ - "src/polyfills.ts", - "src/main.ts", - "../../bitwarden_license/bit-web/src/main.ts", - "src/theme.ts" - ], + "files": ["src/polyfills.ts", "src/main.ts", "src/theme.ts"], "include": [ "src/connectors/*.ts", "src/**/*.stories.ts", diff --git a/bitwarden_license/bit-common/jest.config.js b/bitwarden_license/bit-common/jest.config.js new file mode 100644 index 00000000000..d79f8ae6199 --- /dev/null +++ b/bitwarden_license/bit-common/jest.config.js @@ -0,0 +1,16 @@ +const { pathsToModuleNameMapper } = require("ts-jest"); + +const { compilerOptions } = require("./tsconfig"); + +const sharedConfig = require("../../libs/shared/jest.config.angular"); + +/** @type {import('jest').Config} */ +module.exports = { + ...sharedConfig, + displayName: "bit-common tests", + preset: "ts-jest", + testEnvironment: "jsdom", + moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { + prefix: "/", + }), +}; diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/admin-auth-request-update.request.ts similarity index 100% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/admin-auth-request-update.request.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/admin-auth-request-update.request.ts diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/bulk-deny-auth-requests.request.ts similarity index 100% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/bulk-deny-auth-requests.request.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/bulk-deny-auth-requests.request.ts diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/index.ts similarity index 100% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/index.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/index.ts diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request-api.service.ts similarity index 89% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request-api.service.ts index d9de9fe297b..9b8e4c246d8 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/organization-auth-request.service.ts +++ b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request-api.service.ts @@ -1,17 +1,13 @@ -import { Injectable } from "@angular/core"; - import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { PendingAuthRequestView } from "../../views/pending-auth-request.view"; - import { AdminAuthRequestUpdateRequest } from "./admin-auth-request-update.request"; import { BulkDenyAuthRequestsRequest } from "./bulk-deny-auth-requests.request"; +import { PendingAuthRequestView } from "./pending-auth-request.view"; import { PendingOrganizationAuthRequestResponse } from "./pending-organization-auth-request.response"; -@Injectable() -export class OrganizationAuthRequestService { +export class OrganizationAuthRequestApiService { constructor(private apiService: ApiService) {} async listPendingRequests(organizationId: string): Promise { diff --git a/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.spec.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.spec.ts new file mode 100644 index 00000000000..24c6f06be3c --- /dev/null +++ b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.spec.ts @@ -0,0 +1,132 @@ +import { MockProxy, mock } from "jest-mock-extended"; + +import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; +import { OrganizationUserResetPasswordDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; + +import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service"; +import { OrganizationAuthRequestService } from "./organization-auth-request.service"; +import { PendingAuthRequestView } from "./pending-auth-request.view"; + +describe("OrganizationAuthRequestService", () => { + let organizationAuthRequestApiService: MockProxy; + let cryptoService: MockProxy; + let organizationUserService: MockProxy; + let organizationAuthRequestService: OrganizationAuthRequestService; + + beforeEach(() => { + organizationAuthRequestApiService = mock(); + cryptoService = mock(); + organizationUserService = mock(); + organizationAuthRequestService = new OrganizationAuthRequestService( + organizationAuthRequestApiService, + cryptoService, + organizationUserService, + ); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + describe("listPendingRequests", () => { + it("should return a list of pending auth requests", async () => { + jest.spyOn(organizationAuthRequestApiService, "listPendingRequests"); + + const organizationId = "organizationId"; + + const pendingAuthRequest = new PendingAuthRequestView(); + pendingAuthRequest.id = "requestId1"; + pendingAuthRequest.userId = "userId1"; + pendingAuthRequest.organizationUserId = "userId1"; + pendingAuthRequest.email = "email1"; + pendingAuthRequest.publicKey = "publicKey1"; + pendingAuthRequest.requestDeviceIdentifier = "requestDeviceIdentifier1"; + pendingAuthRequest.requestDeviceType = "requestDeviceType1"; + pendingAuthRequest.requestIpAddress = "requestIpAddress1"; + pendingAuthRequest.creationDate = new Date(); + const mockPendingAuthRequests = [pendingAuthRequest]; + organizationAuthRequestApiService.listPendingRequests + .calledWith(organizationId) + .mockResolvedValue(mockPendingAuthRequests); + + const result = await organizationAuthRequestService.listPendingRequests(organizationId); + + expect(result).toHaveLength(1); + expect(result).toEqual(mockPendingAuthRequests); + expect(organizationAuthRequestApiService.listPendingRequests).toHaveBeenCalledWith( + organizationId, + ); + }); + + it("should return an empty list", async () => { + jest.spyOn(organizationAuthRequestApiService, "listPendingRequests"); + + const invalidOrganizationId = "invalidOrganizationId"; + const result = + await organizationAuthRequestService.listPendingRequests("invalidOrganizationId"); + + expect(result).toBeUndefined(); + expect(organizationAuthRequestApiService.listPendingRequests).toHaveBeenCalledWith( + invalidOrganizationId, + ); + }); + }); + + describe("denyPendingRequests", () => { + it("should deny the specified pending auth requests", async () => { + jest.spyOn(organizationAuthRequestApiService, "denyPendingRequests"); + + await organizationAuthRequestService.denyPendingRequests( + "organizationId", + "requestId1", + "requestId2", + ); + + expect(organizationAuthRequestApiService.denyPendingRequests).toHaveBeenCalledWith( + "organizationId", + "requestId1", + "requestId2", + ); + }); + }); + + describe("approvePendingRequest", () => { + it("should approve the specified pending auth request", async () => { + jest.spyOn(organizationAuthRequestApiService, "approvePendingRequest"); + + const organizationId = "organizationId"; + + const organizationUserResetPasswordDetailsResponse = + new OrganizationUserResetPasswordDetailsResponse({ + resetPasswordKey: "resetPasswordKey", + encryptedPrivateKey: "encryptedPrivateKey", + }); + + organizationUserService.getOrganizationUserResetPasswordDetails.mockResolvedValue( + organizationUserResetPasswordDetailsResponse, + ); + + const encryptedUserKey = new EncString("encryptedUserKey"); + cryptoService.rsaDecrypt.mockResolvedValue(new Uint8Array(32)); + cryptoService.rsaEncrypt.mockResolvedValue(encryptedUserKey); + + const mockPendingAuthRequest = new PendingAuthRequestView(); + mockPendingAuthRequest.id = "requestId1"; + mockPendingAuthRequest.organizationUserId = "organizationUserId1"; + mockPendingAuthRequest.publicKey = "publicKey1"; + + await organizationAuthRequestService.approvePendingRequest( + organizationId, + mockPendingAuthRequest, + ); + + expect(organizationAuthRequestApiService.approvePendingRequest).toHaveBeenCalledWith( + organizationId, + mockPendingAuthRequest.id, + encryptedUserKey, + ); + }); + }); +}); diff --git a/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.ts new file mode 100644 index 00000000000..efc2cdcedba --- /dev/null +++ b/bitwarden_license/bit-common/src/admin-console/auth-requests/organization-auth-request.service.ts @@ -0,0 +1,81 @@ +import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; +import { OrganizationUserResetPasswordDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; + +import { OrganizationAuthRequestApiService } from "./organization-auth-request-api.service"; +import { PendingAuthRequestView } from "./pending-auth-request.view"; + +export class OrganizationAuthRequestService { + constructor( + private organizationAuthRequestApiService: OrganizationAuthRequestApiService, + private cryptoService: CryptoService, + private organizationUserService: OrganizationUserService, + ) {} + + async listPendingRequests(organizationId: string): Promise { + return await this.organizationAuthRequestApiService.listPendingRequests(organizationId); + } + + async denyPendingRequests(organizationId: string, ...requestIds: string[]): Promise { + await this.organizationAuthRequestApiService.denyPendingRequests(organizationId, ...requestIds); + } + + async approvePendingRequest(organizationId: string, authRequest: PendingAuthRequestView) { + const details = await this.organizationUserService.getOrganizationUserResetPasswordDetails( + organizationId, + authRequest.organizationUserId, + ); + + if (details == null || details.resetPasswordKey == null) { + throw new Error( + "The user must be enrolled in account recovery (password reset) in order for the request to be approved.", + ); + } + + const encryptedKey = await this.getEncryptedUserKey( + organizationId, + authRequest.publicKey, + details, + ); + + await this.organizationAuthRequestApiService.approvePendingRequest( + organizationId, + authRequest.id, + encryptedKey, + ); + } + + /** + * Creates a copy of the user key that has been encrypted with the provided device's public key. + * @param organizationId + * @param devicePublicKey + * @param resetPasswordDetails + * @private + */ + private async getEncryptedUserKey( + organizationId: string, + devicePublicKey: string, + resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse, + ): Promise { + const encryptedUserKey = resetPasswordDetails.resetPasswordKey; + const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey; + const devicePubKey = Utils.fromB64ToArray(devicePublicKey); + + // Decrypt Organization's encrypted Private Key with org key + const orgSymKey = await this.cryptoService.getOrgKey(organizationId); + const decOrgPrivateKey = await this.cryptoService.decryptToBytes( + new EncString(encryptedOrgPrivateKey), + orgSymKey, + ); + + // Decrypt user key with decrypted org private key + const decValue = await this.cryptoService.rsaDecrypt(encryptedUserKey, decOrgPrivateKey); + const userKey = new SymmetricCryptoKey(decValue); + + // Re-encrypt user Key with the Device Public Key + return await this.cryptoService.rsaEncrypt(userKey.key, devicePubKey); + } +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/pending-auth-request.view.ts similarity index 87% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/pending-auth-request.view.ts index 8f3415a236b..d9f36013521 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/views/pending-auth-request.view.ts +++ b/bitwarden_license/bit-common/src/admin-console/auth-requests/pending-auth-request.view.ts @@ -1,6 +1,6 @@ import { View } from "@bitwarden/common/models/view/view"; -import { PendingOrganizationAuthRequestResponse } from "../services/auth-requests"; +import { PendingOrganizationAuthRequestResponse } from "."; export class PendingAuthRequestView implements View { id: string; diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts b/bitwarden_license/bit-common/src/admin-console/auth-requests/pending-organization-auth-request.response.ts similarity index 100% rename from bitwarden_license/bit-web/src/app/admin-console/organizations/core/services/auth-requests/pending-organization-auth-request.response.ts rename to bitwarden_license/bit-common/src/admin-console/auth-requests/pending-organization-auth-request.response.ts diff --git a/bitwarden_license/bit-common/tsconfig.json b/bitwarden_license/bit-common/tsconfig.json new file mode 100644 index 00000000000..6b40d447419 --- /dev/null +++ b/bitwarden_license/bit-common/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../libs/shared/tsconfig.libs", + "include": ["src", "spec"], + "exclude": ["node_modules", "dist"], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@bitwarden/admin-console": ["../../libs/admin-console/src"], + "@bitwarden/angular/*": ["../../libs/angular/src/*"], + "@bitwarden/auth": ["../../libs/auth/src"], + "@bitwarden/billing": ["../../libs/billing/src"], + "@bitwarden/common/*": ["../../libs/common/src/*"], + "@bitwarden/components": ["../../libs/components/src"], + "@bitwarden/vault-export-core": [ + "../../libs/tools/export/vault-export/vault-export-core/src" + ], + "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-core/src"], + "@bitwarden/platform": ["../../libs/platform/src"], + "@bitwarden/vault": ["../../libs/vault/src"], + "@bitwarden/web-vault/*": ["../../apps/web/src/*"], + "@bitwarden/bit-common/*": ["../bit-common/src/*"] + } + } +} diff --git a/bitwarden_license/bit-common/tsconfig.spec.json b/bitwarden_license/bit-common/tsconfig.spec.json new file mode 100644 index 00000000000..fc8520e7376 --- /dev/null +++ b/bitwarden_license/bit-common/tsconfig.spec.json @@ -0,0 +1,3 @@ +{ + "extends": "./tsconfig.json" +} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts deleted file mode 100644 index bba3bfce930..00000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/core-organization.module.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NgModule } from "@angular/core"; - -import { OrganizationAuthRequestService } from "./services/auth-requests"; - -@NgModule({ - providers: [OrganizationAuthRequestService], -}) -export class CoreOrganizationModule {} diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts deleted file mode 100644 index 4d758be8c6b..00000000000 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/core/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./core-organization.module"; diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts index dec65df9fb4..a1ffd91a1c5 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/manage/device-approvals/device-approvals.component.ts @@ -2,25 +2,37 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { BehaviorSubject, Subject, switchMap, takeUntil, tap } from "rxjs"; +import { SafeProvider, safeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; +import { OrganizationAuthRequestApiService } from "@bitwarden/bit-common/admin-console/auth-requests/organization-auth-request-api.service"; +import { OrganizationAuthRequestService } from "@bitwarden/bit-common/admin-console/auth-requests/organization-auth-request.service"; +import { PendingAuthRequestView } from "@bitwarden/bit-common/admin-console/auth-requests/pending-auth-request.view"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { OrganizationUserService } from "@bitwarden/common/admin-console/abstractions/organization-user/organization-user.service"; -import { OrganizationUserResetPasswordDetailsResponse } from "@bitwarden/common/admin-console/abstractions/organization-user/responses"; 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"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; -import { Utils } from "@bitwarden/common/platform/misc/utils"; -import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; -import { TableDataSource } from "@bitwarden/components"; +import { TableDataSource, NoItemsModule } from "@bitwarden/components"; import { Devices } from "@bitwarden/web-vault/app/admin-console/icons"; - -import { OrganizationAuthRequestService } from "../../core/services/auth-requests"; -import { PendingAuthRequestView } from "../../core/views/pending-auth-request.view"; +import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared"; +import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; @Component({ selector: "app-org-device-approvals", templateUrl: "./device-approvals.component.html", + standalone: true, + providers: [ + safeProvider({ + provide: OrganizationAuthRequestApiService, + deps: [ApiService], + }), + safeProvider({ + provide: OrganizationAuthRequestService, + deps: [OrganizationAuthRequestApiService, CryptoService, OrganizationUserService], + }), + ] satisfies SafeProvider[], + imports: [SharedModule, NoItemsModule, LooseComponentsModule], }) export class DeviceApprovalsComponent implements OnInit, OnDestroy { tableDataSource = new TableDataSource(); @@ -35,8 +47,6 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy { constructor( private organizationAuthRequestService: OrganizationAuthRequestService, - private organizationUserService: OrganizationUserService, - private cryptoService: CryptoService, private route: ActivatedRoute, private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, @@ -64,65 +74,26 @@ export class DeviceApprovalsComponent implements OnInit, OnDestroy { }); } - /** - * Creates a copy of the user key that has been encrypted with the provided device's public key. - * @param devicePublicKey - * @param resetPasswordDetails - * @private - */ - private async getEncryptedUserKey( - devicePublicKey: string, - resetPasswordDetails: OrganizationUserResetPasswordDetailsResponse, - ): Promise { - const encryptedUserKey = resetPasswordDetails.resetPasswordKey; - const encryptedOrgPrivateKey = resetPasswordDetails.encryptedPrivateKey; - const devicePubKey = Utils.fromB64ToArray(devicePublicKey); - - // Decrypt Organization's encrypted Private Key with org key - const orgSymKey = await this.cryptoService.getOrgKey(this.organizationId); - const decOrgPrivateKey = await this.cryptoService.decryptToBytes( - new EncString(encryptedOrgPrivateKey), - orgSymKey, - ); - - // Decrypt user key with decrypted org private key - const decValue = await this.cryptoService.rsaDecrypt(encryptedUserKey, decOrgPrivateKey); - const userKey = new SymmetricCryptoKey(decValue); - - // Re-encrypt user Key with the Device Public Key - return await this.cryptoService.rsaEncrypt(userKey.key, devicePubKey); - } - async approveRequest(authRequest: PendingAuthRequestView) { await this.performAsyncAction(async () => { - const details = await this.organizationUserService.getOrganizationUserResetPasswordDetails( - this.organizationId, - authRequest.organizationUserId, - ); + try { + await this.organizationAuthRequestService.approvePendingRequest( + this.organizationId, + authRequest, + ); - // The user must be enrolled in account recovery (password reset) in order for the request to be approved. - if (details == null || details.resetPasswordKey == null) { + this.platformUtilsService.showToast( + "success", + null, + this.i18nService.t("loginRequestApproved"), + ); + } catch (error) { this.platformUtilsService.showToast( "error", null, this.i18nService.t("resetPasswordDetailsError"), ); - return; } - - const encryptedKey = await this.getEncryptedUserKey(authRequest.publicKey, details); - - await this.organizationAuthRequestService.approvePendingRequest( - this.organizationId, - authRequest.id, - encryptedKey, - ); - - this.platformUtilsService.showToast( - "success", - null, - this.i18nService.t("loginRequestApproved"), - ); }); } diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts index a116d2244cd..ce97f54374e 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations-routing.module.ts @@ -9,7 +9,6 @@ import { OrganizationLayoutComponent } from "@bitwarden/web-vault/app/admin-cons import { SsoComponent } from "../../auth/sso/sso.component"; -import { DeviceApprovalsComponent } from "./manage/device-approvals/device-approvals.component"; import { DomainVerificationComponent } from "./manage/domain-verification/domain-verification.component"; import { ScimComponent } from "./manage/scim.component"; @@ -55,7 +54,10 @@ const routes: Routes = [ }, { path: "device-approvals", - component: DeviceApprovalsComponent, + loadComponent: () => + import("./manage/device-approvals/device-approvals.component").then( + (mod) => mod.DeviceApprovalsComponent, + ), canActivate: [OrganizationPermissionsGuard], data: { organizationPermissions: (org: Organization) => org.canManageDeviceApprovals, diff --git a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts index 98982dae24a..e19d028b007 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts +++ b/bitwarden_license/bit-web/src/app/admin-console/organizations/organizations.module.ts @@ -1,32 +1,22 @@ import { NgModule } from "@angular/core"; -import { NoItemsModule } from "@bitwarden/components"; import { LooseComponentsModule } from "@bitwarden/web-vault/app/shared"; import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module"; import { SsoComponent } from "../../auth/sso/sso.component"; -import { CoreOrganizationModule } from "./core"; -import { DeviceApprovalsComponent } from "./manage/device-approvals/device-approvals.component"; import { DomainAddEditDialogComponent } from "./manage/domain-verification/domain-add-edit-dialog/domain-add-edit-dialog.component"; import { DomainVerificationComponent } from "./manage/domain-verification/domain-verification.component"; import { ScimComponent } from "./manage/scim.component"; import { OrganizationsRoutingModule } from "./organizations-routing.module"; @NgModule({ - imports: [ - SharedModule, - CoreOrganizationModule, - OrganizationsRoutingModule, - NoItemsModule, - LooseComponentsModule, - ], + imports: [SharedModule, OrganizationsRoutingModule, LooseComponentsModule], declarations: [ SsoComponent, ScimComponent, DomainVerificationComponent, DomainAddEditDialogComponent, - DeviceApprovalsComponent, ], }) export class OrganizationsModule {} diff --git a/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html b/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html index 94f2e8a422d..e61b965ce6f 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/policies/activate-autofill.component.html @@ -6,6 +6,6 @@ - + {{ "turnOn" | i18n }} diff --git a/bitwarden_license/bit-web/tsconfig.json b/bitwarden_license/bit-web/tsconfig.json index 0f19c6736a3..27095e1da91 100644 --- a/bitwarden_license/bit-web/tsconfig.json +++ b/bitwarden_license/bit-web/tsconfig.json @@ -1,21 +1,43 @@ { "extends": "../../apps/web/tsconfig", "compilerOptions": { + "baseUrl": ".", + "module": "ES2020", + "resolveJsonModule": true, "paths": { "@bitwarden/admin-console": ["../../libs/admin-console/src"], "@bitwarden/angular/*": ["../../libs/angular/src/*"], - "@bitwarden/auth": ["../../libs/auth/src"], + "@bitwarden/auth/common": ["../../libs/auth/src/common"], + "@bitwarden/auth/angular": ["../../libs/auth/src/angular"], "@bitwarden/billing": ["../../libs/billing/src"], "@bitwarden/common/*": ["../../libs/common/src/*"], "@bitwarden/components": ["../../libs/components/src"], "@bitwarden/vault-export-core": [ "../../libs/tools/export/vault-export/vault-export-core/src" ], - "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-core/src"], + "@bitwarden/vault-export-ui": ["../../libs/tools/export/vault-export/vault-export-ui/src"], + "@bitwarden/importer/core": ["../../libs/importer/src"], + "@bitwarden/importer/ui": ["../../libs/importer/src/components"], "@bitwarden/platform": ["../../libs/platform/src"], "@bitwarden/vault": ["../../libs/vault/src"], - "@bitwarden/web-vault/*": ["../../apps/web/src/*"] + "@bitwarden/web-vault/*": ["../../apps/web/src/*"], + + "@bitwarden/bit-common/*": ["../bit-common/src/*"] } }, - "include": ["src/**/*.stories.ts"] + "files": [ + "../../apps/web/src/polyfills.ts", + "../../apps/web/src/main.ts", + "../../apps/web/src/theme.ts", + + "../../bitwarden_license/bit-web/src/main.ts" + ], + "include": [ + "../../apps/web/src/connectors/*.ts", + "../../apps/web/src/**/*.stories.ts", + "../../apps/web/src/**/*.spec.ts", + "../../libs/common/src/platform/services/**/*.worker.ts", + + "src/**/*.stories.ts" + ] } diff --git a/bitwarden_license/bit-web/webpack.config.js b/bitwarden_license/bit-web/webpack.config.js index 155b572b42d..bf192b5411a 100644 --- a/bitwarden_license/bit-web/webpack.config.js +++ b/bitwarden_license/bit-web/webpack.config.js @@ -4,7 +4,7 @@ const webpackConfig = require("../../apps/web/webpack.config"); webpackConfig.entry["app/main"] = "../../bitwarden_license/bit-web/src/main.ts"; webpackConfig.plugins[webpackConfig.plugins.length - 1] = new AngularWebpackPlugin({ - tsConfigPath: "tsconfig.json", + tsconfig: "../../bitwarden_license/bit-web/tsconfig.json", entryModule: "bitwarden_license/src/app/app.module#AppModule", sourceMap: true, }); diff --git a/clients.code-workspace b/clients.code-workspace index c7075c04ea3..a424f91eeb4 100644 --- a/clients.code-workspace +++ b/clients.code-workspace @@ -32,6 +32,10 @@ "name": "libs", "path": "libs", }, + { + "name": "common (bit)", + "path": "bitwarden_license/bit-common", + }, ], "settings": { "eslint.options": { diff --git a/jest.config.js b/jest.config.js index 1ff25c3bebb..e2c50553d8e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -22,6 +22,7 @@ module.exports = { "/apps/web/jest.config.js", "/bitwarden_license/bit-web/jest.config.js", "/bitwarden_license/bit-cli/jest.config.js", + "/bitwarden_license/bit-common/jest.config.js", "/libs/admin-console/jest.config.js", "/libs/angular/jest.config.js", diff --git a/libs/angular/src/auth/components/base-login-decryption-options.component.ts b/libs/angular/src/auth/components/base-login-decryption-options.component.ts index b5cc50d8473..0cc416a74bd 100644 --- a/libs/angular/src/auth/components/base-login-decryption-options.component.ts +++ b/libs/angular/src/auth/components/base-login-decryption-options.component.ts @@ -12,6 +12,9 @@ import { takeUntil, defer, throwError, + map, + Observable, + take, } from "rxjs"; import { @@ -67,6 +70,8 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy { protected data?: Data; protected loading = true; + private email$: Observable; + activeAccountId: UserId; // Remember device means for the user to trust the device @@ -104,6 +109,14 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy { async ngOnInit() { this.loading = true; this.activeAccountId = (await firstValueFrom(this.accountService.activeAccount$))?.id; + this.email$ = this.accountService.activeAccount$.pipe( + map((a) => a?.email), + catchError((err: unknown) => { + this.validationService.showError(err); + return of(undefined); + }), + takeUntil(this.destroy$), + ); this.setupRememberDeviceValueChanges(); @@ -193,16 +206,8 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy { }), ); - const email$ = from(this.stateService.getEmail()).pipe( - catchError((err: unknown) => { - this.validationService.showError(err); - return of(undefined); - }), - takeUntil(this.destroy$), - ); - const autoEnrollStatus = await firstValueFrom(autoEnrollStatus$); - const email = await firstValueFrom(email$); + const email = await firstValueFrom(this.email$); this.data = { state: State.NewUser, organizationId: autoEnrollStatus.id, userEmail: email }; this.loading = false; @@ -211,17 +216,9 @@ export class BaseLoginDecryptionOptionsComponent implements OnInit, OnDestroy { loadUntrustedDeviceData(userDecryptionOptions: UserDecryptionOptions) { this.loading = true; - const email$ = from(this.stateService.getEmail()).pipe( - catchError((err: unknown) => { - this.validationService.showError(err); - return of(undefined); - }), - takeUntil(this.destroy$), - ); - - email$ + this.email$ .pipe( - takeUntil(this.destroy$), + take(1), finalize(() => { this.loading = false; }), diff --git a/libs/angular/src/auth/components/change-password.component.ts b/libs/angular/src/auth/components/change-password.component.ts index 714c5f56d9c..975090b3896 100644 --- a/libs/angular/src/auth/components/change-password.component.ts +++ b/libs/angular/src/auth/components/change-password.component.ts @@ -1,8 +1,9 @@ import { Directive, OnDestroy, OnInit } from "@angular/core"; -import { Subject, takeUntil } from "rxjs"; +import { Subject, firstValueFrom, map, takeUntil } from "rxjs"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +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 { KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; @@ -47,10 +48,13 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { protected dialogService: DialogService, protected kdfConfigService: KdfConfigService, protected masterPasswordService: InternalMasterPasswordServiceAbstraction, + protected accountService: AccountService, ) {} async ngOnInit() { - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.policyService .masterPasswordPolicyOptions$() .pipe(takeUntil(this.destroy$)) @@ -74,7 +78,9 @@ export class ChangePasswordComponent implements OnInit, OnDestroy { return; } - const email = await this.stateService.getEmail(); + const email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); if (this.kdfConfig == null) { this.kdfConfig = await this.kdfConfigService.getKdfConfig(); } diff --git a/libs/angular/src/auth/components/lock.component.ts b/libs/angular/src/auth/components/lock.component.ts index fe4be9b5de4..a1c9e94fb0a 100644 --- a/libs/angular/src/auth/components/lock.component.ts +++ b/libs/angular/src/auth/components/lock.component.ts @@ -372,7 +372,9 @@ export class LockComponent implements OnInit, OnDestroy { (await this.vaultTimeoutSettingsService.isBiometricLockSet()) && ((await this.cryptoService.hasUserKeyStored(KeySuffixOptions.Biometric)) || !this.platformUtilsService.supportsSecureStorage()); - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.webVaultHostname = (await this.environmentService.getEnvironment()).getHostname(); } diff --git a/libs/angular/src/auth/components/login-via-auth-request.component.ts b/libs/angular/src/auth/components/login-via-auth-request.component.ts index a60468e244a..401abab3b19 100644 --- a/libs/angular/src/auth/components/login-via-auth-request.component.ts +++ b/libs/angular/src/auth/components/login-via-auth-request.component.ts @@ -1,6 +1,6 @@ import { Directive, OnDestroy, OnInit } from "@angular/core"; import { IsActiveMatchOptions, Router } from "@angular/router"; -import { Subject, firstValueFrom, takeUntil } from "rxjs"; +import { Subject, firstValueFrom, map, takeUntil } from "rxjs"; import { AuthRequestLoginCredentials, @@ -29,7 +29,6 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; @@ -84,12 +83,11 @@ export class LoginViaAuthRequestComponent platformUtilsService: PlatformUtilsService, private anonymousHubService: AnonymousHubService, private validationService: ValidationService, - private stateService: StateService, + private accountService: AccountService, private loginEmailService: LoginEmailServiceAbstraction, private deviceTrustService: DeviceTrustServiceAbstraction, private authRequestService: AuthRequestServiceAbstraction, private loginStrategyService: LoginStrategyServiceAbstraction, - private accountService: AccountService, ) { super(environmentService, i18nService, platformUtilsService); @@ -131,7 +129,9 @@ export class LoginViaAuthRequestComponent // Pull email from state for admin auth reqs b/c it is available // This also prevents it from being lost on refresh as the // login service email does not persist. - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); const userId = (await firstValueFrom(this.accountService.activeAccount$)).id; if (!this.email) { diff --git a/libs/angular/src/auth/components/remove-password.component.ts b/libs/angular/src/auth/components/remove-password.component.ts index 9a65728fa95..ddd494e31a3 100644 --- a/libs/angular/src/auth/components/remove-password.component.ts +++ b/libs/angular/src/auth/components/remove-password.component.ts @@ -1,12 +1,13 @@ import { Directive, OnInit } from "@angular/core"; import { Router } from "@angular/router"; +import { firstValueFrom, map } from "rxjs"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction"; import { DialogService } from "@bitwarden/components"; @@ -22,7 +23,7 @@ export class RemovePasswordComponent implements OnInit { constructor( private router: Router, - private stateService: StateService, + private accountService: AccountService, private syncService: SyncService, private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, @@ -33,7 +34,9 @@ export class RemovePasswordComponent implements OnInit { async ngOnInit() { this.organization = await this.keyConnectorService.getManagingOrganization(); - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); await this.syncService.fullSync(false); this.loading = false; } diff --git a/libs/angular/src/auth/components/set-password.component.ts b/libs/angular/src/auth/components/set-password.component.ts index a009e9f480c..73c38c8ddb9 100644 --- a/libs/angular/src/auth/components/set-password.component.ts +++ b/libs/angular/src/auth/components/set-password.component.ts @@ -51,7 +51,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { ForceSetPasswordReason = ForceSetPasswordReason; constructor( - private accountService: AccountService, + accountService: AccountService, masterPasswordService: InternalMasterPasswordServiceAbstraction, i18nService: I18nService, cryptoService: CryptoService, @@ -83,6 +83,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent { dialogService, kdfConfigService, masterPasswordService, + accountService, ); } diff --git a/libs/angular/src/auth/components/update-password.component.ts b/libs/angular/src/auth/components/update-password.component.ts index b2c37359f4c..3b709b3e7f7 100644 --- a/libs/angular/src/auth/components/update-password.component.ts +++ b/libs/angular/src/auth/components/update-password.component.ts @@ -4,6 +4,7 @@ import { Router } from "@angular/router"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +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 { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; @@ -48,6 +49,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { dialogService: DialogService, kdfConfigService: KdfConfigService, masterPasswordService: InternalMasterPasswordServiceAbstraction, + accountService: AccountService, ) { super( i18nService, @@ -60,6 +62,7 @@ export class UpdatePasswordComponent extends BaseChangePasswordComponent { dialogService, kdfConfigService, masterPasswordService, + accountService, ); } diff --git a/libs/angular/src/auth/components/update-temp-password.component.ts b/libs/angular/src/auth/components/update-temp-password.component.ts index d9a75496418..e797c93be1e 100644 --- a/libs/angular/src/auth/components/update-temp-password.component.ts +++ b/libs/angular/src/auth/components/update-temp-password.component.ts @@ -1,6 +1,6 @@ import { Directive } from "@angular/core"; import { Router } from "@angular/router"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -61,7 +61,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { protected router: Router, dialogService: DialogService, kdfConfigService: KdfConfigService, - private accountService: AccountService, + accountService: AccountService, masterPasswordService: InternalMasterPasswordServiceAbstraction, ) { super( @@ -75,6 +75,7 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { dialogService, kdfConfigService, masterPasswordService, + accountService, ); } @@ -107,7 +108,9 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent { } async setupSubmitActions(): Promise { - this.email = await this.stateService.getEmail(); + this.email = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.kdfConfig = await this.kdfConfigService.getKdfConfig(); return true; } diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index c812f5fbec2..1f7b714fc85 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -193,13 +193,11 @@ import { SearchService } from "@bitwarden/common/services/search.service"; import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service"; import { VaultTimeoutService } from "@bitwarden/common/services/vault-timeout/vault-timeout.service"; import { - PasswordGenerationService, - PasswordGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/password"; -import { - UsernameGenerationService, - UsernameGenerationServiceAbstraction, -} from "@bitwarden/common/tools/generator/username"; + legacyPasswordGenerationServiceFactory, + legacyUsernameGenerationServiceFactory, +} from "@bitwarden/common/tools/generator"; +import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password"; +import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username"; import { PasswordStrengthService, PasswordStrengthServiceAbstraction, @@ -559,13 +557,27 @@ const safeProviders: SafeProvider[] = [ }), safeProvider({ provide: PasswordGenerationServiceAbstraction, - useClass: PasswordGenerationService, - deps: [CryptoServiceAbstraction, PolicyServiceAbstraction, StateServiceAbstraction], + useFactory: legacyPasswordGenerationServiceFactory, + deps: [ + EncryptService, + CryptoServiceAbstraction, + PolicyServiceAbstraction, + AccountServiceAbstraction, + StateProvider, + ], }), safeProvider({ provide: UsernameGenerationServiceAbstraction, - useClass: UsernameGenerationService, - deps: [CryptoServiceAbstraction, StateServiceAbstraction, ApiServiceAbstraction], + useFactory: legacyUsernameGenerationServiceFactory, + deps: [ + ApiServiceAbstraction, + I18nServiceAbstraction, + CryptoServiceAbstraction, + EncryptService, + PolicyServiceAbstraction, + AccountServiceAbstraction, + StateProvider, + ], }), safeProvider({ provide: ApiServiceAbstraction, diff --git a/libs/angular/src/tools/generator/components/generator.component.ts b/libs/angular/src/tools/generator/components/generator.component.ts index d1857a88ad9..b94d9bc6f0e 100644 --- a/libs/angular/src/tools/generator/components/generator.component.ts +++ b/libs/angular/src/tools/generator/components/generator.component.ts @@ -1,14 +1,14 @@ -import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { Directive, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; -import { BehaviorSubject } from "rxjs"; -import { debounceTime, first, map } from "rxjs/operators"; +import { BehaviorSubject, combineLatest, firstValueFrom, Subject } from "rxjs"; +import { debounceTime, first, map, skipWhile, takeUntil } from "rxjs/operators"; import { PasswordGeneratorPolicyOptions } from "@bitwarden/common/admin-console/models/domain/password-generator-policy-options"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { GeneratorOptions } from "@bitwarden/common/tools/generator/generator-options"; +import { GeneratorType } from "@bitwarden/common/tools/generator/generator-type"; import { PasswordGenerationServiceAbstraction, PasswordGeneratorOptions, @@ -21,9 +21,9 @@ import { import { EmailForwarderOptions } from "@bitwarden/common/tools/models/domain/email-forwarder-options"; @Directive() -export class GeneratorComponent implements OnInit { +export class GeneratorComponent implements OnInit, OnDestroy { @Input() comingFromAddEdit = false; - @Input() type: string; + @Input() type: GeneratorType | ""; @Output() onSelected = new EventEmitter(); usernameGeneratingPromise: Promise; @@ -42,6 +42,9 @@ export class GeneratorComponent implements OnInit { enforcedPasswordPolicyOptions: PasswordGeneratorPolicyOptions; usernameWebsite: string = null; + private destroy$ = new Subject(); + private isInitialized$ = new BehaviorSubject(false); + // update screen reader minimum password length with 500ms debounce // so that the user isn't flooded with status updates private _passwordOptionsMinLengthForReader = new BehaviorSubject( @@ -52,14 +55,17 @@ export class GeneratorComponent implements OnInit { debounceTime(500), ); + private _password = new BehaviorSubject("-"); + constructor( protected passwordGenerationService: PasswordGenerationServiceAbstraction, protected usernameGenerationService: UsernameGenerationServiceAbstraction, protected platformUtilsService: PlatformUtilsService, - protected stateService: StateService, + protected accountService: AccountService, protected i18nService: I18nService, protected logService: LogService, protected route: ActivatedRoute, + protected ngZone: NgZone, private win: Window, ) { this.typeOptions = [ @@ -90,59 +96,115 @@ export class GeneratorComponent implements OnInit { ]; this.subaddressOptions = [{ name: i18nService.t("random"), value: "random" }]; this.catchallOptions = [{ name: i18nService.t("random"), value: "random" }]; - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.initForwardOptions(); - } - async ngOnInit() { - // eslint-disable-next-line rxjs/no-async-subscribe - this.route.queryParams.pipe(first()).subscribe(async (qParams) => { - const passwordOptionsResponse = await this.passwordGenerationService.getOptions(); - this.passwordOptions = passwordOptionsResponse[0]; - this.enforcedPasswordPolicyOptions = passwordOptionsResponse[1]; - this.avoidAmbiguous = !this.passwordOptions.ambiguous; - this.passwordOptions.type = - this.passwordOptions.type === "passphrase" ? "passphrase" : "password"; + this.forwardOptions = [ + { name: "", value: "", validForSelfHosted: false }, + { name: "addy.io", value: "anonaddy", validForSelfHosted: true }, + { name: "DuckDuckGo", value: "duckduckgo", validForSelfHosted: false }, + { name: "Fastmail", value: "fastmail", validForSelfHosted: true }, + { name: "Firefox Relay", value: "firefoxrelay", validForSelfHosted: false }, + { name: "SimpleLogin", value: "simplelogin", validForSelfHosted: true }, + { name: "Forward Email", value: "forwardemail", validForSelfHosted: true }, + ].sort((a, b) => a.name.localeCompare(b.name)); - this.usernameOptions = await this.usernameGenerationService.getOptions(); - if (this.usernameOptions.type == null) { - this.usernameOptions.type = "word"; - } - if ( - this.usernameOptions.subaddressEmail == null || - this.usernameOptions.subaddressEmail === "" - ) { - this.usernameOptions.subaddressEmail = await this.stateService.getEmail(); - } - if (this.usernameWebsite == null) { - this.usernameOptions.subaddressType = this.usernameOptions.catchallType = "random"; - } else { - this.usernameOptions.website = this.usernameWebsite; - const websiteOption = { name: this.i18nService.t("websiteName"), value: "website-name" }; - this.subaddressOptions.push(websiteOption); - this.catchallOptions.push(websiteOption); - } - - if (this.type !== "username" && this.type !== "password") { - if (qParams.type === "username" || qParams.type === "password") { - this.type = qParams.type; - } else { - const generatorOptions = await this.stateService.getGeneratorOptions(); - this.type = generatorOptions?.type ?? "password"; - } - } - if (this.regenerateWithoutButtonPress()) { - await this.regenerate(); - } + this._password.pipe(debounceTime(250)).subscribe((password) => { + ngZone.run(() => { + this.password = password; + }); + this.passwordGenerationService.addHistory(this.password).catch((e) => { + this.logService.error(e); + }); }); } - async typeChanged() { - await this.stateService.setGeneratorOptions({ type: this.type } as GeneratorOptions); - if (this.regenerateWithoutButtonPress()) { - await this.regenerate(); + cascadeOptions(navigationType: GeneratorType = undefined, accountEmail: string) { + this.avoidAmbiguous = !this.passwordOptions.ambiguous; + + if (!this.type) { + if (navigationType) { + this.type = navigationType; + } else { + this.type = this.passwordOptions.type === "username" ? "username" : "password"; + } } + + this.passwordOptions.type = + this.passwordOptions.type === "passphrase" ? "passphrase" : "password"; + + if (this.usernameOptions.type == null) { + this.usernameOptions.type = "word"; + } + if ( + this.usernameOptions.subaddressEmail == null || + this.usernameOptions.subaddressEmail === "" + ) { + this.usernameOptions.subaddressEmail = accountEmail; + } + if (this.usernameWebsite == null) { + this.usernameOptions.subaddressType = this.usernameOptions.catchallType = "random"; + } else { + this.usernameOptions.website = this.usernameWebsite; + const websiteOption = { name: this.i18nService.t("websiteName"), value: "website-name" }; + this.subaddressOptions.push(websiteOption); + this.catchallOptions.push(websiteOption); + } + } + + async ngOnInit() { + combineLatest([ + this.route.queryParams.pipe(first()), + this.accountService.activeAccount$.pipe(first()), + this.passwordGenerationService.getOptions$(), + this.usernameGenerationService.getOptions$(), + ]) + .pipe( + map(([qParams, account, [passwordOptions, passwordPolicy], usernameOptions]) => ({ + navigationType: qParams.type as GeneratorType, + accountEmail: account.email, + passwordOptions, + passwordPolicy, + usernameOptions, + })), + takeUntil(this.destroy$), + ) + .subscribe((options) => { + this.passwordOptions = options.passwordOptions; + this.enforcedPasswordPolicyOptions = options.passwordPolicy; + this.usernameOptions = options.usernameOptions; + + this.cascadeOptions(options.navigationType, options.accountEmail); + this._passwordOptionsMinLengthForReader.next(this.passwordOptions.minLength); + + if (this.regenerateWithoutButtonPress()) { + this.regenerate().catch((e) => { + this.logService.error(e); + }); + } + + this.isInitialized$.next(true); + }); + + // once initialization is complete, `ngOnInit` should return. + // + // FIXME(#6944): if a sync is in progress, wait to complete until after + // the sync completes. + await firstValueFrom( + this.isInitialized$.pipe( + skipWhile((initialized) => !initialized), + takeUntil(this.destroy$), + ), + ); + } + + ngOnDestroy() { + this.destroy$.next(); + this.destroy$.complete(); + this.isInitialized$.complete(); + this._passwordOptionsMinLengthForReader.complete(); + } + + async typeChanged() { + await this.savePasswordOptions(); } async regenerate() { @@ -156,7 +218,7 @@ export class GeneratorComponent implements OnInit { async sliderChanged() { // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.savePasswordOptions(false); + this.savePasswordOptions(); await this.passwordGenerationService.addHistory(this.password); } @@ -200,31 +262,34 @@ export class GeneratorComponent implements OnInit { async sliderInput() { await this.normalizePasswordOptions(); - this.password = await this.passwordGenerationService.generatePassword(this.passwordOptions); } - async savePasswordOptions(regenerate = true) { + async savePasswordOptions() { + // map navigation state into generator type + const restoreType = this.passwordOptions.type; + if (this.type === "username") { + this.passwordOptions.type = this.type; + } + + // save options await this.normalizePasswordOptions(); await this.passwordGenerationService.saveOptions(this.passwordOptions); - if (regenerate && this.regenerateWithoutButtonPress()) { - await this.regeneratePassword(); - } + // restore the original format + this.passwordOptions.type = restoreType; } - async saveUsernameOptions(regenerate = true) { + async saveUsernameOptions() { await this.usernameGenerationService.saveOptions(this.usernameOptions); if (this.usernameOptions.type === "forwarded") { this.username = "-"; } - if (regenerate && this.regenerateWithoutButtonPress()) { - await this.regenerateUsername(); - } } async regeneratePassword() { - this.password = await this.passwordGenerationService.generatePassword(this.passwordOptions); - await this.passwordGenerationService.addHistory(this.password); + this._password.next( + await this.passwordGenerationService.generatePassword(this.passwordOptions), + ); } regenerateUsername() { @@ -293,28 +358,5 @@ export class GeneratorComponent implements OnInit { await this.passwordGenerationService.enforcePasswordGeneratorPoliciesOnOptions( this.passwordOptions, ); - - this._passwordOptionsMinLengthForReader.next(this.passwordOptions.minLength); - } - - private async initForwardOptions() { - this.forwardOptions = [ - { name: "addy.io", value: "anonaddy", validForSelfHosted: true }, - { name: "DuckDuckGo", value: "duckduckgo", validForSelfHosted: false }, - { name: "Fastmail", value: "fastmail", validForSelfHosted: true }, - { name: "Firefox Relay", value: "firefoxrelay", validForSelfHosted: false }, - { name: "SimpleLogin", value: "simplelogin", validForSelfHosted: true }, - { name: "Forward Email", value: "forwardemail", validForSelfHosted: true }, - ]; - - this.usernameOptions = await this.usernameGenerationService.getOptions(); - if ( - this.usernameOptions.forwardedService == null || - this.usernameOptions.forwardedService === "" - ) { - this.forwardOptions.push({ name: "", value: null, validForSelfHosted: false }); - } - - this.forwardOptions = this.forwardOptions.sort((a, b) => a.name.localeCompare(b.name)); } } diff --git a/libs/angular/src/tools/generator/components/password-generator-history.component.ts b/libs/angular/src/tools/generator/components/password-generator-history.component.ts index 7197e9bf4c5..9ad0c0cbdbb 100644 --- a/libs/angular/src/tools/generator/components/password-generator-history.component.ts +++ b/libs/angular/src/tools/generator/components/password-generator-history.component.ts @@ -23,8 +23,7 @@ export class PasswordGeneratorHistoryComponent implements OnInit { } clear = async () => { - this.history = []; - await this.passwordGenerationService.clear(); + this.history = await this.passwordGenerationService.clear(); }; copy(password: string) { diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index 74c368d7262..ea659284ded 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -1,6 +1,6 @@ import { DatePipe } from "@angular/common"; import { Directive, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core"; -import { concatMap, firstValueFrom, Observable, Subject, takeUntil } from "rxjs"; +import { concatMap, firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; @@ -11,6 +11,7 @@ import { import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { EventType } from "@bitwarden/common/enums"; import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { UriMatchStrategy } from "@bitwarden/common/models/domain/domain-service"; @@ -19,7 +20,6 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.service.abstraction"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; @@ -108,7 +108,7 @@ export class AddEditComponent implements OnInit, OnDestroy { protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, protected auditService: AuditService, - protected stateService: StateService, + protected accountService: AccountService, protected collectionService: CollectionService, protected messagingService: MessagingService, protected eventCollectionService: EventCollectionService, @@ -215,7 +215,9 @@ export class AddEditComponent implements OnInit, OnDestroy { if (this.personalOwnershipPolicyAppliesToActiveUser) { this.allowPersonal = false; } else { - const myEmail = await this.stateService.getEmail(); + const myEmail = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ); this.ownershipOptions.push({ name: myEmail, value: null }); } diff --git a/apps/web/src/app/auth/anon-layout-wrapper.component.html b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.html similarity index 100% rename from apps/web/src/app/auth/anon-layout-wrapper.component.html rename to libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.html diff --git a/apps/web/src/app/auth/anon-layout-wrapper.component.ts b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts similarity index 89% rename from apps/web/src/app/auth/anon-layout-wrapper.component.ts rename to libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts index c89b05a3c65..fb98825b1b6 100644 --- a/apps/web/src/app/auth/anon-layout-wrapper.component.ts +++ b/libs/auth/src/angular/anon-layout/anon-layout-wrapper.component.ts @@ -5,6 +5,12 @@ import { AnonLayoutComponent } from "@bitwarden/auth/angular"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Icon } from "@bitwarden/components"; +export interface AnonLayoutWrapperData { + pageTitle?: string; + pageSubtitle?: string; + pageIcon?: Icon; +} + @Component({ standalone: true, templateUrl: "anon-layout-wrapper.component.html", diff --git a/libs/auth/src/angular/anon-layout/anon-layout.component.html b/libs/auth/src/angular/anon-layout/anon-layout.component.html index 6483048a238..1152d2efbbd 100644 --- a/libs/auth/src/angular/anon-layout/anon-layout.component.html +++ b/libs/auth/src/angular/anon-layout/anon-layout.component.html @@ -13,7 +13,7 @@

{{ subtitle }}

-
+
diff --git a/libs/auth/src/angular/anon-layout/anon-layout.mdx b/libs/auth/src/angular/anon-layout/anon-layout.mdx index c604c02f030..b98523bba18 100644 --- a/libs/auth/src/angular/anon-layout/anon-layout.mdx +++ b/libs/auth/src/angular/anon-layout/anon-layout.mdx @@ -31,14 +31,13 @@ writing: Instead the AnonLayoutComponent is implemented solely in the router via routable composition, which gives us the advantages of nested routes in Angular. -To allow for routable composition, Auth will also provide a wrapper component in each client, called -AnonLayout**Wrapper**Component. +To allow for routable composition, Auth also provides an AnonLayout**Wrapper**Component which embeds +the AnonLayoutComponent. For clarity: -- AnonLayoutComponent = the Auth-owned library component - `` -- AnonLayout**Wrapper**Component = the client-specific wrapper component to be used in a client - routing module +- AnonLayoutComponent = the base, Auth-owned library component - `` +- AnonLayout**Wrapper**Component = the wrapper to be used in client routing modules The AnonLayout**Wrapper**Component embeds the AnonLayoutComponent along with the router outlets: @@ -79,7 +78,7 @@ example) to construct the page via routable composition: pageTitle: "logIn", // example of a translation key from messages.json pageSubtitle: "loginWithMasterPassword", // example of a translation key from messages.json pageIcon: LockIcon, // example of an icon to pass in - }, + } satisfies AnonLayoutWrapperData, }, ], }, @@ -99,7 +98,7 @@ In the `oss-routing.module.ts` example above, notice the data properties being p All 3 of these properties are optional. ```javascript -import { LockIcon } from "@bitwarden/auth/angular"; +import { AnonLayoutWrapperData, LockIcon } from "@bitwarden/auth/angular"; // ... @@ -109,7 +108,7 @@ import { LockIcon } from "@bitwarden/auth/angular"; pageTitle: "logIn", pageSubtitle: "loginWithMasterPassword", pageIcon: LockIcon, - }, + } satisfies AnonLayoutWrapperData, } ``` diff --git a/libs/auth/src/angular/anon-layout/anon-layout.stories.ts b/libs/auth/src/angular/anon-layout/anon-layout.stories.ts index 61a395b1559..103098349a0 100644 --- a/libs/auth/src/angular/anon-layout/anon-layout.stories.ts +++ b/libs/auth/src/angular/anon-layout/anon-layout.stories.ts @@ -41,7 +41,7 @@ export const WithPrimaryContent: Story = { // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. ` -
+
Primary Projected Content Area (customizable)
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
@@ -58,12 +58,12 @@ export const WithSecondaryContent: Story = { // Notice that slot="secondary" is requred to project any secondary content. ` -
+
Primary Projected Content Area (customizable)
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
-
+
Secondary Projected Content (optional)
@@ -79,12 +79,12 @@ export const WithLongContent: Story = { // Projected content (the
's) and styling is just a sample and can be replaced with any content/styling. ` -
+
Primary Projected Content Area (customizable)
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam? Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit. Lorem ipsum dolor sit amet consectetur adipisicing elit.
-
+
Secondary Projected Content (optional)

Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias laborum nostrum natus. Lorem ipsum dolor sit amet consectetur adipisicing elit. Molestias laborum nostrum natus. Expedita, quod est?

@@ -101,7 +101,7 @@ export const WithIcon: Story = { // Projected content (the
) and styling is just a sample and can be replaced with any content/styling. ` -
+
Primary Projected Content Area (customizable)
Lorem ipsum dolor sit amet consectetur adipisicing elit. Necessitatibus illum vero, placeat recusandae esse ratione eius minima veniam nemo, quas beatae! Impedit molestiae alias sapiente explicabo. Sapiente corporis ipsa numquam?
diff --git a/libs/auth/src/angular/index.ts b/libs/auth/src/angular/index.ts index 067ed63b8ef..474ef17d932 100644 --- a/libs/auth/src/angular/index.ts +++ b/libs/auth/src/angular/index.ts @@ -6,6 +6,7 @@ export * from "./icons"; export * from "./anon-layout/anon-layout.component"; +export * from "./anon-layout/anon-layout-wrapper.component"; export * from "./fingerprint-dialog/fingerprint-dialog.component"; export * from "./password-callout/password-callout.component"; diff --git a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts index d2aac323bf3..36c572af852 100644 --- a/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.spec.ts @@ -97,6 +97,7 @@ describe("AuthRequestLoginStrategy", () => { authRequestLoginStrategy = new AuthRequestLoginStrategy( cache, + deviceTrustService, accountService, masterPasswordService, cryptoService, @@ -109,7 +110,6 @@ describe("AuthRequestLoginStrategy", () => { stateService, twoFactorService, userDecryptionOptions, - deviceTrustService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, diff --git a/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts b/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts index 54654e1d82a..c8fc066fe0e 100644 --- a/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/auth-request-login.strategy.ts @@ -1,28 +1,13 @@ import { firstValueFrom, Observable, map, BehaviorSubject } from "rxjs"; import { Jsonify } from "type-fest"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/src/auth/abstractions/device-trust.service.abstraction"; import { UserId } from "@bitwarden/common/types/guid"; -import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { AuthRequestLoginCredentials } from "../models/domain/login-credentials"; import { CacheData } from "../services/login-strategies/login-strategy.state"; @@ -51,40 +36,10 @@ export class AuthRequestLoginStrategy extends LoginStrategy { constructor( data: AuthRequestLoginStrategyData, - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - cryptoService: CryptoService, - apiService: ApiService, - tokenService: TokenService, - appIdService: AppIdService, - platformUtilsService: PlatformUtilsService, - messagingService: MessagingService, - logService: LogService, - stateService: StateService, - twoFactorService: TwoFactorService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, private deviceTrustService: DeviceTrustServiceAbstraction, - billingAccountProfileStateService: BillingAccountProfileStateService, - vaultTimeoutSettingsService: VaultTimeoutSettingsService, - kdfConfigService: KdfConfigService, + ...sharedDeps: ConstructorParameters ) { - super( - accountService, - masterPasswordService, - cryptoService, - apiService, - tokenService, - appIdService, - platformUtilsService, - messagingService, - logService, - stateService, - twoFactorService, - userDecryptionOptionsService, - billingAccountProfileStateService, - vaultTimeoutSettingsService, - kdfConfigService, - ); + super(...sharedDeps); this.cache = new BehaviorSubject(data); this.email$ = this.cache.pipe(map((data) => data.tokenRequest.email)); diff --git a/libs/auth/src/common/login-strategies/login.strategy.spec.ts b/libs/auth/src/common/login-strategies/login.strategy.spec.ts index 627c852076a..665857c1f47 100644 --- a/libs/auth/src/common/login-strategies/login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/login.strategy.spec.ts @@ -150,6 +150,9 @@ describe("LoginStrategy", () => { // The base class is abstract so we test it via PasswordLoginStrategy passwordLoginStrategy = new PasswordLoginStrategy( cache, + passwordStrengthService, + policyService, + loginStrategyService, accountService, masterPasswordService, cryptoService, @@ -162,9 +165,6 @@ describe("LoginStrategy", () => { stateService, twoFactorService, userDecryptionOptionsService, - passwordStrengthService, - policyService, - loginStrategyService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, @@ -461,6 +461,9 @@ describe("LoginStrategy", () => { passwordLoginStrategy = new PasswordLoginStrategy( cache, + passwordStrengthService, + policyService, + loginStrategyService, accountService, masterPasswordService, cryptoService, @@ -473,9 +476,6 @@ describe("LoginStrategy", () => { stateService, twoFactorService, userDecryptionOptionsService, - passwordStrengthService, - policyService, - loginStrategyService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts index b6d1e07a261..7ba58e1443a 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.spec.ts @@ -121,6 +121,9 @@ describe("PasswordLoginStrategy", () => { passwordLoginStrategy = new PasswordLoginStrategy( cache, + passwordStrengthService, + policyService, + loginStrategyService, accountService, masterPasswordService, cryptoService, @@ -133,9 +136,6 @@ describe("PasswordLoginStrategy", () => { stateService, twoFactorService, userDecryptionOptionsService, - passwordStrengthService, - policyService, - loginStrategyService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, diff --git a/libs/auth/src/common/login-strategies/password-login.strategy.ts b/libs/auth/src/common/login-strategies/password-login.strategy.ts index b855e25e1d2..7f73898ff6e 100644 --- a/libs/auth/src/common/login-strategies/password-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/password-login.strategy.ts @@ -1,15 +1,8 @@ import { BehaviorSubject, firstValueFrom, map, Observable } from "rxjs"; import { Jsonify } from "type-fest"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; -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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { PasswordTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/password-token.request"; @@ -17,13 +10,6 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide import { IdentityCaptchaResponse } from "@bitwarden/common/auth/models/response/identity-captcha.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; import { IdentityTwoFactorResponse } from "@bitwarden/common/auth/models/response/identity-two-factor.response"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { HashPurpose } from "@bitwarden/common/platform/enums"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; @@ -31,7 +17,6 @@ import { UserId } from "@bitwarden/common/types/guid"; import { MasterKey } from "@bitwarden/common/types/key"; import { LoginStrategyServiceAbstraction } from "../abstractions"; -import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { PasswordLoginCredentials } from "../models/domain/login-credentials"; import { CacheData } from "../services/login-strategies/login-strategy.state"; @@ -75,42 +60,12 @@ export class PasswordLoginStrategy extends LoginStrategy { constructor( data: PasswordLoginStrategyData, - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - cryptoService: CryptoService, - apiService: ApiService, - tokenService: TokenService, - appIdService: AppIdService, - platformUtilsService: PlatformUtilsService, - messagingService: MessagingService, - logService: LogService, - protected stateService: StateService, - twoFactorService: TwoFactorService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, private passwordStrengthService: PasswordStrengthServiceAbstraction, private policyService: PolicyService, private loginStrategyService: LoginStrategyServiceAbstraction, - billingAccountProfileStateService: BillingAccountProfileStateService, - vaultTimeoutSettingsService: VaultTimeoutSettingsService, - kdfConfigService: KdfConfigService, + ...sharedDeps: ConstructorParameters ) { - super( - accountService, - masterPasswordService, - cryptoService, - apiService, - tokenService, - appIdService, - platformUtilsService, - messagingService, - logService, - stateService, - twoFactorService, - userDecryptionOptionsService, - billingAccountProfileStateService, - vaultTimeoutSettingsService, - kdfConfigService, - ); + super(...sharedDeps); this.cache = new BehaviorSubject(data); this.email$ = this.cache.pipe(map((state) => state.tokenRequest.email)); diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts index b6290742be5..492772081d6 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.spec.ts @@ -118,6 +118,10 @@ describe("SsoLoginStrategy", () => { ssoLoginStrategy = new SsoLoginStrategy( null, + keyConnectorService, + deviceTrustService, + authRequestService, + i18nService, accountService, masterPasswordService, cryptoService, @@ -130,10 +134,6 @@ describe("SsoLoginStrategy", () => { stateService, twoFactorService, userDecryptionOptionsService, - keyConnectorService, - deviceTrustService, - authRequestService, - i18nService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index 414af4c1a3f..b7ed8906e70 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -1,36 +1,19 @@ import { firstValueFrom, Observable, map, BehaviorSubject } from "rxjs"; import { Jsonify } from "type-fest"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; +import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service"; -import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction"; -import { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { SsoTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/sso-token.request"; import { AuthRequestResponse } from "@bitwarden/common/auth/models/response/auth-request.response"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { HttpStatusCode } from "@bitwarden/common/enums"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.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"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; -import { DeviceTrustServiceAbstraction } from "@bitwarden/common/src/auth/abstractions/device-trust.service.abstraction"; import { UserId } from "@bitwarden/common/types/guid"; -import { - InternalUserDecryptionOptionsServiceAbstraction, - AuthRequestServiceAbstraction, -} from "../abstractions"; +import { AuthRequestServiceAbstraction } from "../abstractions"; import { SsoLoginCredentials } from "../models/domain/login-credentials"; import { CacheData } from "../services/login-strategies/login-strategy.state"; @@ -84,43 +67,13 @@ export class SsoLoginStrategy extends LoginStrategy { constructor( data: SsoLoginStrategyData, - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - cryptoService: CryptoService, - apiService: ApiService, - tokenService: TokenService, - appIdService: AppIdService, - platformUtilsService: PlatformUtilsService, - messagingService: MessagingService, - logService: LogService, - stateService: StateService, - twoFactorService: TwoFactorService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, private keyConnectorService: KeyConnectorService, private deviceTrustService: DeviceTrustServiceAbstraction, private authRequestService: AuthRequestServiceAbstraction, private i18nService: I18nService, - billingAccountProfileStateService: BillingAccountProfileStateService, - vaultTimeoutSettingsService: VaultTimeoutSettingsService, - kdfConfigService: KdfConfigService, + ...sharedDeps: ConstructorParameters ) { - super( - accountService, - masterPasswordService, - cryptoService, - apiService, - tokenService, - appIdService, - platformUtilsService, - messagingService, - logService, - stateService, - twoFactorService, - userDecryptionOptionsService, - billingAccountProfileStateService, - vaultTimeoutSettingsService, - kdfConfigService, - ); + super(...sharedDeps); this.cache = new BehaviorSubject(data); this.email$ = this.cache.pipe(map((state) => state.email)); diff --git a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts index 8120a5ad397..6b9cddd99c5 100644 --- a/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.spec.ts @@ -94,6 +94,8 @@ describe("UserApiLoginStrategy", () => { apiLogInStrategy = new UserApiLoginStrategy( cache, + environmentService, + keyConnectorService, accountService, masterPasswordService, cryptoService, @@ -106,8 +108,6 @@ describe("UserApiLoginStrategy", () => { stateService, twoFactorService, userDecryptionOptionsService, - environmentService, - keyConnectorService, billingAccountProfileStateService, vaultTimeoutSettingsService, kdfConfigService, diff --git a/libs/auth/src/common/login-strategies/user-api-login.strategy.ts b/libs/auth/src/common/login-strategies/user-api-login.strategy.ts index 86113d36550..1faac3f6c75 100644 --- a/libs/auth/src/common/login-strategies/user-api-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/user-api-login.strategy.ts @@ -1,28 +1,13 @@ import { firstValueFrom, BehaviorSubject } from "rxjs"; import { Jsonify } from "type-fest"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { UserApiTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/user-api-token.request"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { UserId } from "@bitwarden/common/types/guid"; -import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions/user-decryption-options.service.abstraction"; import { UserApiLoginCredentials } from "../models/domain/login-credentials"; import { CacheData } from "../services/login-strategies/login-strategy.state"; @@ -44,41 +29,12 @@ export class UserApiLoginStrategy extends LoginStrategy { constructor( data: UserApiLoginStrategyData, - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - cryptoService: CryptoService, - apiService: ApiService, - tokenService: TokenService, - appIdService: AppIdService, - platformUtilsService: PlatformUtilsService, - messagingService: MessagingService, - logService: LogService, - stateService: StateService, - twoFactorService: TwoFactorService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, private environmentService: EnvironmentService, private keyConnectorService: KeyConnectorService, - billingAccountProfileStateService: BillingAccountProfileStateService, - vaultTimeoutSettingsService: VaultTimeoutSettingsService, - protected kdfConfigService: KdfConfigService, + ...sharedDeps: ConstructorParameters ) { - super( - accountService, - masterPasswordService, - cryptoService, - apiService, - tokenService, - appIdService, - platformUtilsService, - messagingService, - logService, - stateService, - twoFactorService, - userDecryptionOptionsService, - billingAccountProfileStateService, - vaultTimeoutSettingsService, - kdfConfigService, - ); + super(...sharedDeps); + this.cache = new BehaviorSubject(data); } diff --git a/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts b/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts index 226ab1799ad..d283d163da1 100644 --- a/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/webauthn-login.strategy.ts @@ -1,28 +1,13 @@ import { BehaviorSubject } from "rxjs"; import { Jsonify } from "type-fest"; -import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service"; -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 { TokenService } from "@bitwarden/common/auth/abstractions/token.service"; -import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { WebAuthnLoginTokenRequest } from "@bitwarden/common/auth/models/request/identity-token/webauthn-login-token.request"; import { IdentityTokenResponse } from "@bitwarden/common/auth/models/response/identity-token.response"; -import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service"; -import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; -import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; import { UserKey } from "@bitwarden/common/types/key"; -import { InternalUserDecryptionOptionsServiceAbstraction } from "../abstractions"; import { WebAuthnLoginCredentials } from "../models/domain/login-credentials"; import { CacheData } from "../services/login-strategies/login-strategy.state"; @@ -46,39 +31,9 @@ export class WebAuthnLoginStrategy extends LoginStrategy { constructor( data: WebAuthnLoginStrategyData, - accountService: AccountService, - masterPasswordService: InternalMasterPasswordServiceAbstraction, - cryptoService: CryptoService, - apiService: ApiService, - tokenService: TokenService, - appIdService: AppIdService, - platformUtilsService: PlatformUtilsService, - messagingService: MessagingService, - logService: LogService, - stateService: StateService, - twoFactorService: TwoFactorService, - userDecryptionOptionsService: InternalUserDecryptionOptionsServiceAbstraction, - billingAccountProfileStateService: BillingAccountProfileStateService, - vaultTimeoutSettingsService: VaultTimeoutSettingsService, - kdfConfigService: KdfConfigService, + ...sharedDeps: ConstructorParameters ) { - super( - accountService, - masterPasswordService, - cryptoService, - apiService, - tokenService, - appIdService, - platformUtilsService, - messagingService, - logService, - stateService, - twoFactorService, - userDecryptionOptionsService, - billingAccountProfileStateService, - vaultTimeoutSettingsService, - kdfConfigService, - ); + super(...sharedDeps); this.cache = new BehaviorSubject(data); } diff --git a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts index 46d785f9b5b..f425bc697c5 100644 --- a/libs/auth/src/common/services/login-strategies/login-strategy.service.ts +++ b/libs/auth/src/common/services/login-strategies/login-strategy.service.ts @@ -48,6 +48,7 @@ import { MasterKey } from "@bitwarden/common/types/key"; import { AuthRequestServiceAbstraction, LoginStrategyServiceAbstraction } from "../../abstractions"; import { InternalUserDecryptionOptionsServiceAbstraction } from "../../abstractions/user-decryption-options.service.abstraction"; import { AuthRequestLoginStrategy } from "../../login-strategies/auth-request-login.strategy"; +import { LoginStrategy } from "../../login-strategies/login.strategy"; import { PasswordLoginStrategy } from "../../login-strategies/password-login.strategy"; import { SsoLoginStrategy } from "../../login-strategies/sso-login.strategy"; import { UserApiLoginStrategy } from "../../login-strategies/user-api-login.strategy"; @@ -338,6 +339,24 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { private initializeLoginStrategy( source: Observable<[AuthenticationType | null, CacheData | null]>, ) { + const sharedDeps: ConstructorParameters = [ + this.accountService, + this.masterPasswordService, + this.cryptoService, + this.apiService, + this.tokenService, + this.appIdService, + this.platformUtilsService, + this.messagingService, + this.logService, + this.stateService, + this.twoFactorService, + this.userDecryptionOptionsService, + this.billingAccountProfileStateService, + this.vaultTimeoutSettingsService, + this.kdfConfigService, + ]; + return source.pipe( map(([strategy, data]) => { if (strategy == null) { @@ -347,108 +366,35 @@ export class LoginStrategyService implements LoginStrategyServiceAbstraction { case AuthenticationType.Password: return new PasswordLoginStrategy( data?.password, - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.userDecryptionOptionsService, this.passwordStrengthService, this.policyService, this, - this.billingAccountProfileStateService, - this.vaultTimeoutSettingsService, - this.kdfConfigService, + ...sharedDeps, ); case AuthenticationType.Sso: return new SsoLoginStrategy( data?.sso, - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.userDecryptionOptionsService, this.keyConnectorService, this.deviceTrustService, this.authRequestService, this.i18nService, - this.billingAccountProfileStateService, - this.vaultTimeoutSettingsService, - this.kdfConfigService, + ...sharedDeps, ); case AuthenticationType.UserApiKey: return new UserApiLoginStrategy( data?.userApiKey, - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.userDecryptionOptionsService, this.environmentService, this.keyConnectorService, - this.billingAccountProfileStateService, - this.vaultTimeoutSettingsService, - this.kdfConfigService, + ...sharedDeps, ); case AuthenticationType.AuthRequest: return new AuthRequestLoginStrategy( data?.authRequest, - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.userDecryptionOptionsService, this.deviceTrustService, - this.billingAccountProfileStateService, - this.vaultTimeoutSettingsService, - this.kdfConfigService, + ...sharedDeps, ); case AuthenticationType.WebAuthn: - return new WebAuthnLoginStrategy( - data?.webAuthn, - this.accountService, - this.masterPasswordService, - this.cryptoService, - this.apiService, - this.tokenService, - this.appIdService, - this.platformUtilsService, - this.messagingService, - this.logService, - this.stateService, - this.twoFactorService, - this.userDecryptionOptionsService, - this.billingAccountProfileStateService, - this.vaultTimeoutSettingsService, - this.kdfConfigService, - ); + return new WebAuthnLoginStrategy(data?.webAuthn, ...sharedDeps); } }), ); diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index c1a0e1f9cd9..73e4f74e63f 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -123,6 +123,7 @@ import { CollectionDetailsResponse, CollectionResponse, } from "../vault/models/response/collection.response"; +import { OptionalCipherResponse } from "../vault/models/response/optional-cipher.response"; import { SyncResponse } from "../vault/models/response/sync.response"; /** @@ -218,7 +219,10 @@ export abstract class ApiService { putMoveCiphers: (request: CipherBulkMoveRequest) => Promise; putShareCipher: (id: string, request: CipherShareRequest) => Promise; putShareCiphers: (request: CipherBulkShareRequest) => Promise; - putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise; + putCipherCollections: ( + id: string, + request: CipherCollectionsRequest, + ) => Promise; putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise; postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise; putDeleteCipher: (id: string) => Promise; diff --git a/libs/common/src/admin-console/models/domain/password-generator-policy-options.ts b/libs/common/src/admin-console/models/domain/password-generator-policy-options.ts index 9d2e7eadd59..c52962a0a1b 100644 --- a/libs/common/src/admin-console/models/domain/password-generator-policy-options.ts +++ b/libs/common/src/admin-console/models/domain/password-generator-policy-options.ts @@ -70,7 +70,7 @@ export class PasswordGeneratorPolicyOptions extends Domain { */ inEffect() { return ( - this.defaultType !== "" || + this.defaultType || this.minLength > 0 || this.numberCount > 0 || this.specialCount > 0 || diff --git a/libs/common/src/auth/services/user-verification/user-verification.service.ts b/libs/common/src/auth/services/user-verification/user-verification.service.ts index d59d675a8d6..7561023a277 100644 --- a/libs/common/src/auth/services/user-verification/user-verification.service.ts +++ b/libs/common/src/auth/services/user-verification/user-verification.service.ts @@ -1,4 +1,4 @@ -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { UserDecryptionOptionsServiceAbstraction } from "@bitwarden/auth/common"; @@ -115,12 +115,14 @@ export class UserVerificationService implements UserVerificationServiceAbstracti if (verification.type === VerificationType.OTP) { request.otp = verification.secret; } else { - const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; + const [userId, email] = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])), + ); let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId)); if (!masterKey && !alreadyHashed) { masterKey = await this.cryptoService.makeMasterKey( verification.secret, - await this.stateService.getEmail(), + email, await this.kdfConfigService.getKdfConfig(), ); } @@ -138,7 +140,9 @@ export class UserVerificationService implements UserVerificationServiceAbstracti * @param verification User-supplied verification data (OTP, MP, PIN, or biometrics) */ async verifyUser(verification: Verification): Promise { - const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; + const [userId, email] = await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => [a?.id, a?.email])), + ); if (verificationHasSecret(verification)) { this.validateSecretInput(verification); @@ -148,7 +152,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti case VerificationType.OTP: return this.verifyUserByOTP(verification); case VerificationType.MasterPassword: - return this.verifyUserByMasterPassword(verification, userId); + return this.verifyUserByMasterPassword(verification, userId, email); case VerificationType.PIN: return this.verifyUserByPIN(verification, userId); case VerificationType.Biometrics: @@ -174,6 +178,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti private async verifyUserByMasterPassword( verification: MasterPasswordVerification, userId: UserId, + email: string, ): Promise { if (!userId) { throw new Error("User ID is required. Cannot verify user by master password."); @@ -183,7 +188,7 @@ export class UserVerificationService implements UserVerificationServiceAbstracti if (!masterKey) { masterKey = await this.cryptoService.makeMasterKey( verification.secret, - await this.stateService.getEmail(), + email, await this.kdfConfigService.getKdfConfig(), ); } diff --git a/libs/common/src/platform/abstractions/state.service.ts b/libs/common/src/platform/abstractions/state.service.ts index 0f678a6bf38..b2ea27ecb05 100644 --- a/libs/common/src/platform/abstractions/state.service.ts +++ b/libs/common/src/platform/abstractions/state.service.ts @@ -82,8 +82,6 @@ export abstract class StateService { ) => Promise; getDuckDuckGoSharedKey: (options?: StorageOptions) => Promise; setDuckDuckGoSharedKey: (value: string, options?: StorageOptions) => Promise; - getEmail: (options?: StorageOptions) => Promise; - setEmail: (value: string, options?: StorageOptions) => Promise; getEnableBrowserIntegration: (options?: StorageOptions) => Promise; setEnableBrowserIntegration: (value: boolean, options?: StorageOptions) => Promise; getEnableBrowserIntegrationFingerprint: (options?: StorageOptions) => Promise; diff --git a/libs/common/src/platform/services/crypto.service.ts b/libs/common/src/platform/services/crypto.service.ts index 2813bfb9608..7595d5a3e32 100644 --- a/libs/common/src/platform/services/crypto.service.ts +++ b/libs/common/src/platform/services/crypto.service.ts @@ -1,5 +1,5 @@ import * as bigInt from "big-integer"; -import { Observable, filter, firstValueFrom, map, zip } from "rxjs"; +import { Observable, combineLatest, filter, firstValueFrom, map, zip } from "rxjs"; import { PinServiceAbstraction } from "../../../../auth/src/common/abstractions"; import { EncryptedOrganizationKeyData } from "../../admin-console/models/data/encrypted-organization-key.data"; @@ -174,7 +174,7 @@ export class CryptoService implements CryptoServiceAbstraction { userId ??= await firstValueFrom(this.stateProvider.activeUserId$); masterKey ??= await firstValueFrom(this.masterPasswordService.masterKey$(userId)); - return await this.validateUserKey(masterKey as unknown as UserKey); + return await this.validateUserKey(masterKey as unknown as UserKey, userId); } // TODO: legacy support for user key is no longer needed since we require users to migrate on login @@ -193,9 +193,10 @@ export class CryptoService implements CryptoServiceAbstraction { } async getUserKeyFromStorage(keySuffix: KeySuffixOptions, userId?: UserId): Promise { + userId ??= await firstValueFrom(this.stateProvider.activeUserId$); const userKey = await this.getKeyFromStorage(keySuffix, userId); if (userKey) { - if (!(await this.validateUserKey(userKey))) { + if (!(await this.validateUserKey(userKey, userId))) { this.logService.warning("Invalid key, throwing away stored keys"); await this.clearAllStoredUserKeys(userId); } @@ -280,11 +281,18 @@ export class CryptoService implements CryptoServiceAbstraction { // TODO: Move to MasterPasswordService async getOrDeriveMasterKey(password: string, userId?: UserId) { - userId ??= await firstValueFrom(this.stateProvider.activeUserId$); - let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(userId)); + const [resolvedUserId, email] = await firstValueFrom( + combineLatest([this.accountService.activeAccount$, this.accountService.accounts$]).pipe( + map(([activeAccount, accounts]) => { + userId ??= activeAccount?.id; + return [userId, accounts[userId]?.email]; + }), + ), + ); + let masterKey = await firstValueFrom(this.masterPasswordService.masterKey$(resolvedUserId)); return (masterKey ||= await this.makeMasterKey( password, - await this.stateService.getEmail({ userId: userId }), + email, await this.kdfConfigService.getKdfConfig(), )); } @@ -656,13 +664,15 @@ export class CryptoService implements CryptoServiceAbstraction { } // ---HELPERS--- - protected async validateUserKey(key: UserKey): Promise { + protected async validateUserKey(key: UserKey, userId: UserId): Promise { if (!key) { return false; } try { - const encPrivateKey = await firstValueFrom(this.activeUserEncryptedPrivateKeyState.state$); + const encPrivateKey = await firstValueFrom( + this.stateProvider.getUserState$(USER_ENCRYPTED_PRIVATE_KEY, userId), + ); if (encPrivateKey == null) { return false; } diff --git a/libs/common/src/platform/services/cryptography/multithread-encrypt.service.implementation.ts b/libs/common/src/platform/services/cryptography/multithread-encrypt.service.implementation.ts index 75a571fef23..6ac343bcb6a 100644 --- a/libs/common/src/platform/services/cryptography/multithread-encrypt.service.implementation.ts +++ b/libs/common/src/platform/services/cryptography/multithread-encrypt.service.implementation.ts @@ -19,36 +19,17 @@ export class MultithreadEncryptServiceImplementation extends EncryptServiceImple private clear$ = new Subject(); /** - * Decrypts items using a web worker if the environment supports it. - * Will fall back to the main thread if the window object is not available. + * Sends items to a web worker to decrypt them. + * This utilises multithreading to decrypt items faster without interrupting other operations (e.g. updating UI). */ async decryptItems( items: Decryptable[], key: SymmetricCryptoKey, ): Promise { - if (typeof window === "undefined") { - return super.decryptItems(items, key); - } - if (items == null || items.length < 1) { return []; } - const decryptedItems = await this.getDecryptedItemsFromWorker(items, key); - const parsedItems = JSON.parse(decryptedItems); - - return this.initializeItems(parsedItems); - } - - /** - * Sends items to a web worker to decrypt them. This utilizes multithreading to decrypt items - * faster without interrupting other operations (e.g. updating UI). This method returns values - * prior to deserialization to support forwarding results to another party - */ - async getDecryptedItemsFromWorker( - items: Decryptable[], - key: SymmetricCryptoKey, - ): Promise { this.logService.info("Starting decryption using multithreading"); this.worker ??= new Worker( @@ -72,20 +53,19 @@ export class MultithreadEncryptServiceImplementation extends EncryptServiceImple return await firstValueFrom( fromEvent(this.worker, "message").pipe( filter((response: MessageEvent) => response.data?.id === request.id), - map((response) => response.data.items), + map((response) => JSON.parse(response.data.items)), + map((items) => + items.map((jsonItem: Jsonify) => { + const initializer = getClassInitializer(jsonItem.initializerKey); + return initializer(jsonItem); + }), + ), takeUntil(this.clear$), - defaultIfEmpty("[]"), + defaultIfEmpty([]), ), ); } - protected initializeItems(items: Jsonify[]): T[] { - return items.map((jsonItem: Jsonify) => { - const initializer = getClassInitializer(jsonItem.initializerKey); - return initializer(jsonItem); - }); - } - private clear() { this.clear$.next(); this.worker?.terminate(); diff --git a/libs/common/src/platform/services/state.service.ts b/libs/common/src/platform/services/state.service.ts index 497e6e67034..0339baa3fa3 100644 --- a/libs/common/src/platform/services/state.service.ts +++ b/libs/common/src/platform/services/state.service.ts @@ -347,23 +347,6 @@ export class StateService< : await this.secureStorageService.save(DDG_SHARED_KEY, value, options); } - async getEmail(options?: StorageOptions): Promise { - return ( - await this.getAccount(this.reconcileOptions(options, await this.defaultInMemoryOptions())) - )?.profile?.email; - } - - async setEmail(value: string, options?: StorageOptions): Promise { - const account = await this.getAccount( - this.reconcileOptions(options, await this.defaultInMemoryOptions()), - ); - account.profile.email = value; - await this.saveAccount( - account, - this.reconcileOptions(options, await this.defaultInMemoryOptions()), - ); - } - async getEnableBrowserIntegration(options?: StorageOptions): Promise { return ( (await this.getGlobals(this.reconcileOptions(options, await this.defaultOnDiskOptions()))) diff --git a/libs/common/src/platform/state/state-definitions.ts b/libs/common/src/platform/state/state-definitions.ts index 6f225f6c2fc..986c51f4b7d 100644 --- a/libs/common/src/platform/state/state-definitions.ts +++ b/libs/common/src/platform/state/state-definitions.ts @@ -160,3 +160,7 @@ export const CIPHERS_DISK_LOCAL = new StateDefinition("ciphersLocal", "disk", { export const CIPHERS_MEMORY = new StateDefinition("ciphersMemory", "memory", { browser: "memory-large-object", }); +export const PREMIUM_BANNER_DISK_LOCAL = new StateDefinition("premiumBannerReprompt", "disk", { + web: "disk-local", +}); +export const BANNERS_DISMISSED_DISK = new StateDefinition("bannersDismissed", "disk"); diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 4620a2ccdee..8d7a53ec0e4 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -138,6 +138,7 @@ import { CollectionDetailsResponse, CollectionResponse, } from "../vault/models/response/collection.response"; +import { OptionalCipherResponse } from "../vault/models/response/optional-cipher.response"; import { SyncResponse } from "../vault/models/response/sync.response"; /** @@ -566,9 +567,15 @@ export class ApiService implements ApiServiceAbstraction { async putCipherCollections( id: string, request: CipherCollectionsRequest, - ): Promise { - const response = await this.send("PUT", "/ciphers/" + id + "/collections", request, true, true); - return new CipherResponse(response); + ): Promise { + const response = await this.send( + "PUT", + "/ciphers/" + id + "/collections_v2", + request, + true, + true, + ); + return new OptionalCipherResponse(response); } putCipherCollectionsAdmin(id: string, request: CipherCollectionsRequest): Promise { diff --git a/libs/common/src/state-migrations/migrate.ts b/libs/common/src/state-migrations/migrate.ts index ed438cda88d..d0543fb8c3a 100644 --- a/libs/common/src/state-migrations/migrate.ts +++ b/libs/common/src/state-migrations/migrate.ts @@ -60,13 +60,16 @@ import { RemoveLegacyEtmKeyMigrator } from "./migrations/6-remove-legacy-etm-key import { KnownAccountsMigrator } from "./migrations/60-known-accounts"; import { PinStateMigrator } from "./migrations/61-move-pin-state-to-providers"; import { VaultTimeoutSettingsServiceStateProviderMigrator } from "./migrations/62-migrate-vault-timeout-settings-svc-to-state-provider"; +import { PasswordOptionsMigrator } from "./migrations/63-migrate-password-settings"; +import { GeneratorHistoryMigrator } from "./migrations/64-migrate-generator-history"; +import { ForwarderOptionsMigrator } from "./migrations/65-migrate-forwarder-settings"; import { MoveBiometricAutoPromptToAccount } from "./migrations/7-move-biometric-auto-prompt-to-account"; import { MoveStateVersionMigrator } from "./migrations/8-move-state-version"; import { MoveBrowserSettingsToGlobal } from "./migrations/9-move-browser-settings-to-global"; import { MinVersionMigrator } from "./migrations/min-version"; export const MIN_VERSION = 3; -export const CURRENT_VERSION = 62; +export const CURRENT_VERSION = 65; export type MinVersion = typeof MIN_VERSION; export function createMigrationBuilder() { @@ -130,7 +133,10 @@ export function createMigrationBuilder() { .with(KdfConfigMigrator, 58, 59) .with(KnownAccountsMigrator, 59, 60) .with(PinStateMigrator, 60, 61) - .with(VaultTimeoutSettingsServiceStateProviderMigrator, 61, CURRENT_VERSION); + .with(VaultTimeoutSettingsServiceStateProviderMigrator, 61, 62) + .with(PasswordOptionsMigrator, 62, 63) + .with(GeneratorHistoryMigrator, 63, 64) + .with(ForwarderOptionsMigrator, 64, CURRENT_VERSION); } export async function currentVersion( diff --git a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.spec.ts b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.spec.ts index 1a736c1623a..aa715c3c06a 100644 --- a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.spec.ts +++ b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.spec.ts @@ -13,6 +13,10 @@ import { // Represents data in state service pre-migration function preMigrationJson() { return { + // desktop only global data format + "global.vaultTimeout": -1, + "global.vaultTimeoutAction": "lock", + global: { vaultTimeout: 30, vaultTimeoutAction: "lock", @@ -267,6 +271,10 @@ describe("VaultTimeoutSettingsServiceStateProviderMigrator", () => { otherStuff: "otherStuff", }); + // Expect we removed desktop specially formatted global data + expect(helper.remove).toHaveBeenCalledWith("global\\.vaultTimeout"); + expect(helper.remove).toHaveBeenCalledWith("global\\.vaultTimeoutAction"); + // User data expect(helper.set).toHaveBeenCalledWith("user1", { settings: { diff --git a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts index ee9ee4c9ea3..7451fd37514 100644 --- a/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts +++ b/libs/common/src/state-migrations/migrations/62-migrate-vault-timeout-settings-svc-to-state-provider.ts @@ -122,10 +122,15 @@ export class VaultTimeoutSettingsServiceStateProviderMigrator extends Migrator<6 await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]); - // Delete global data + // Delete global data (works for browser extension and web; CLI doesn't have these as global settings). delete globalData?.vaultTimeout; delete globalData?.vaultTimeoutAction; await helper.set("global", globalData); + + // Remove desktop only settings. These aren't found by the above global key removal b/c of + // the different storage key format. This removal does not cause any issues on migrating for other clients. + await helper.remove("global\\.vaultTimeout"); + await helper.remove("global\\.vaultTimeoutAction"); } async rollback(helper: MigrationHelper): Promise { diff --git a/libs/common/src/state-migrations/migrations/63-migrate-password-settings.spec.ts b/libs/common/src/state-migrations/migrations/63-migrate-password-settings.spec.ts new file mode 100644 index 00000000000..adbe8a999f3 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/63-migrate-password-settings.spec.ts @@ -0,0 +1,123 @@ +import { MigrationHelper } from "../migration-helper"; +import { mockMigrationHelper } from "../migration-helper.spec"; + +import { + ExpectedOptions, + PasswordOptionsMigrator, + NAVIGATION, + PASSWORD, + PASSPHRASE, +} from "./63-migrate-password-settings"; + +function migrationHelper(passwordGenerationOptions: ExpectedOptions) { + const helper = mockMigrationHelper( + { + global_account_accounts: { + SomeAccount: { + email: "SomeAccount", + name: "SomeAccount", + emailVerified: true, + }, + }, + SomeAccount: { + settings: { + passwordGenerationOptions, + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }, + }, + 62, + ); + + return helper; +} + +function expectOtherSettingsRemain(helper: MigrationHelper) { + expect(helper.set).toHaveBeenCalledWith("SomeAccount", { + settings: { + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }); +} + +describe("PasswordOptionsMigrator", () => { + describe("migrate", () => { + it("migrates generator type", async () => { + const helper = migrationHelper({ + type: "password", + }); + helper.getFromUser.mockResolvedValue({ some: { other: "data" } }); + const migrator = new PasswordOptionsMigrator(62, 63); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", NAVIGATION, { + type: "password", + some: { other: "data" }, + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates password settings", async () => { + const helper = migrationHelper({ + length: 20, + ambiguous: true, + uppercase: false, + minUppercase: 4, + lowercase: true, + minLowercase: 3, + number: false, + minNumber: 2, + special: true, + minSpecial: 1, + }); + const migrator = new PasswordOptionsMigrator(62, 63); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", PASSWORD, { + length: 20, + ambiguous: true, + uppercase: false, + minUppercase: 4, + lowercase: true, + minLowercase: 3, + number: false, + minNumber: 2, + special: true, + minSpecial: 1, + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates passphrase settings", async () => { + const helper = migrationHelper({ + numWords: 5, + wordSeparator: "4", + capitalize: true, + includeNumber: false, + }); + const migrator = new PasswordOptionsMigrator(62, 63); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", PASSPHRASE, { + numWords: 5, + wordSeparator: "4", + capitalize: true, + includeNumber: false, + }); + expectOtherSettingsRemain(helper); + }); + }); +}); diff --git a/libs/common/src/state-migrations/migrations/63-migrate-password-settings.ts b/libs/common/src/state-migrations/migrations/63-migrate-password-settings.ts new file mode 100644 index 00000000000..a0849fd5988 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/63-migrate-password-settings.ts @@ -0,0 +1,150 @@ +import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; +import { Migrator } from "../migrator"; + +/** settings targeted by migrator */ +export type AccountType = { + settings?: { + passwordGenerationOptions?: ExpectedOptions; + }; +}; + +export type GeneratorType = "password" | "passphrase" | "username"; + +/** username generation options prior to refactoring */ +export type ExpectedOptions = { + type?: GeneratorType; + length?: number; + minLength?: number; + ambiguous?: boolean; + uppercase?: boolean; + minUppercase?: number; + lowercase?: boolean; + minLowercase?: number; + number?: boolean; + minNumber?: number; + special?: boolean; + minSpecial?: number; + numWords?: number; + wordSeparator?: string; + capitalize?: boolean; + includeNumber?: boolean; +}; + +/** username generation options after refactoring */ +type ConvertedOptions = { + generator: GeneratorNavigation; + password: PasswordGenerationOptions; + passphrase: PassphraseGenerationOptions; +}; + +export const NAVIGATION: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "generatorSettings", +}; + +export const PASSWORD: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "passwordGeneratorSettings", +}; + +export const PASSPHRASE: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "passphraseGeneratorSettings", +}; + +export type GeneratorNavigation = { + type?: string; +}; + +export type PassphraseGenerationOptions = { + numWords?: number; + wordSeparator?: string; + capitalize?: boolean; + includeNumber?: boolean; +}; + +export type PasswordGenerationOptions = { + length?: number; + minLength?: number; + ambiguous?: boolean; + uppercase?: boolean; + minUppercase?: number; + lowercase?: boolean; + minLowercase?: number; + number?: boolean; + minNumber?: number; + special?: boolean; + minSpecial?: number; +}; + +export class PasswordOptionsMigrator extends Migrator<62, 63> { + async migrate(helper: MigrationHelper): Promise { + const accounts = await helper.getAccounts(); + + async function migrateAccount(userId: string, account: AccountType) { + const legacyOptions = account?.settings?.passwordGenerationOptions; + + if (legacyOptions) { + const converted = convertSettings(legacyOptions); + await storeSettings(helper, userId, converted); + await deleteSettings(helper, userId, account); + } + } + + await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]); + } + + async rollback(helper: MigrationHelper): Promise { + // not supported + } +} + +function convertSettings(options: ExpectedOptions): ConvertedOptions { + const password = { + length: options.length, + ambiguous: options.ambiguous, + uppercase: options.uppercase, + minUppercase: options.minUppercase, + lowercase: options.lowercase, + minLowercase: options.minLowercase, + number: options.number, + minNumber: options.minNumber, + special: options.special, + minSpecial: options.minSpecial, + }; + + const generator = { + type: options.type, + }; + + const passphrase = { + numWords: options.numWords, + wordSeparator: options.wordSeparator, + capitalize: options.capitalize, + includeNumber: options.includeNumber, + }; + + return { generator, password, passphrase }; +} + +async function storeSettings(helper: MigrationHelper, userId: string, converted: ConvertedOptions) { + const existing = (await helper.getFromUser(userId, NAVIGATION)) ?? {}; + const updated = Object.assign(existing, converted.generator); + + await Promise.all([ + helper.setToUser(userId, NAVIGATION, updated), + helper.setToUser(userId, PASSPHRASE, converted.passphrase), + helper.setToUser(userId, PASSWORD, converted.password), + ]); +} + +async function deleteSettings(helper: MigrationHelper, userId: string, account: AccountType) { + delete account?.settings?.passwordGenerationOptions; + await helper.set(userId, account); +} diff --git a/libs/common/src/state-migrations/migrations/64-migrate-generator-history.spec.ts b/libs/common/src/state-migrations/migrations/64-migrate-generator-history.spec.ts new file mode 100644 index 00000000000..3bcf15ceb33 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/64-migrate-generator-history.spec.ts @@ -0,0 +1,68 @@ +import { MigrationHelper } from "../migration-helper"; +import { mockMigrationHelper } from "../migration-helper.spec"; + +import { + EncryptedHistory, + GeneratorHistoryMigrator, + HISTORY, +} from "./64-migrate-generator-history"; + +function migrationHelper(encrypted: EncryptedHistory) { + const helper = mockMigrationHelper( + { + global_account_accounts: { + SomeAccount: { + email: "SomeAccount", + name: "SomeAccount", + emailVerified: true, + }, + }, + SomeAccount: { + data: { + passwordGenerationHistory: { + encrypted, + }, + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }, + }, + 63, + ); + + return helper; +} + +function expectOtherSettingsRemain(helper: MigrationHelper) { + expect(helper.set).toHaveBeenCalledWith("SomeAccount", { + data: { + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }); +} + +describe("PasswordOptionsMigrator", () => { + describe("migrate", () => { + it("migrates generator type", async () => { + const helper = migrationHelper([{ this: "should be copied" }, { this: "too" }]); + const migrator = new GeneratorHistoryMigrator(63, 64); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", HISTORY, [ + { this: "should be copied" }, + { this: "too" }, + ]); + expectOtherSettingsRemain(helper); + }); + }); +}); diff --git a/libs/common/src/state-migrations/migrations/64-migrate-generator-history.ts b/libs/common/src/state-migrations/migrations/64-migrate-generator-history.ts new file mode 100644 index 00000000000..3ca4c643184 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/64-migrate-generator-history.ts @@ -0,0 +1,42 @@ +import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; +import { Migrator } from "../migrator"; + +/** settings targeted by migrator */ +export type AccountType = { + data?: { + passwordGenerationHistory?: { + encrypted: EncryptedHistory; + }; + }; +}; + +/** the actual data stored in the history is opaque to the migrator */ +export type EncryptedHistory = Array; + +export const HISTORY: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "localGeneratorHistoryBuffer", +}; + +export class GeneratorHistoryMigrator extends Migrator<63, 64> { + async migrate(helper: MigrationHelper): Promise { + const accounts = await helper.getAccounts(); + + async function migrateAccount(userId: string, account: AccountType) { + const data = account?.data?.passwordGenerationHistory; + if (data && data.encrypted) { + await helper.setToUser(userId, HISTORY, data.encrypted); + delete account.data.passwordGenerationHistory; + await helper.set(userId, account); + } + } + + await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]); + } + + async rollback(helper: MigrationHelper): Promise { + // not supported + } +} diff --git a/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.spec.ts b/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.spec.ts new file mode 100644 index 00000000000..3fca95ada8b --- /dev/null +++ b/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.spec.ts @@ -0,0 +1,218 @@ +import { MigrationHelper } from "../migration-helper"; +import { mockMigrationHelper } from "../migration-helper.spec"; + +import { + ADDY_IO, + CATCHALL, + DUCK_DUCK_GO, + EFF_USERNAME, + ExpectedOptions, + FASTMAIL, + FIREFOX_RELAY, + FORWARD_EMAIL, + ForwarderOptionsMigrator, + NAVIGATION, + SIMPLE_LOGIN, + SUBADDRESS, +} from "./65-migrate-forwarder-settings"; + +function migrationHelper(usernameGenerationOptions: ExpectedOptions) { + const helper = mockMigrationHelper( + { + global_account_accounts: { + SomeAccount: { + email: "SomeAccount", + name: "SomeAccount", + emailVerified: true, + }, + }, + SomeAccount: { + settings: { + usernameGenerationOptions, + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }, + }, + 64, + ); + + return helper; +} + +function expectOtherSettingsRemain(helper: MigrationHelper) { + expect(helper.set).toHaveBeenCalledWith("SomeAccount", { + settings: { + this: { + looks: "important", + }, + }, + cant: { + touch: "this", + }, + }); +} + +describe("ForwarderOptionsMigrator", () => { + describe("migrate", () => { + it("migrates generator settings", async () => { + const helper = migrationHelper({ + type: "catchall", + forwardedService: "simplelogin", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", NAVIGATION, { + username: "catchall", + forwarder: "simplelogin", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates catchall settings", async () => { + const helper = migrationHelper({ + catchallType: "random", + catchallDomain: "example.com", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", CATCHALL, { + catchallType: "random", + catchallDomain: "example.com", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates EFF username settings", async () => { + const helper = migrationHelper({ + wordCapitalize: true, + wordIncludeNumber: false, + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", EFF_USERNAME, { + wordCapitalize: true, + wordIncludeNumber: false, + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates subaddress settings", async () => { + const helper = migrationHelper({ + subaddressType: "random", + subaddressEmail: "j.d@example.com", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", SUBADDRESS, { + subaddressType: "random", + subaddressEmail: "j.d@example.com", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates addyIo settings", async () => { + const helper = migrationHelper({ + forwardedAnonAddyBaseUrl: "some_addyio_base", + forwardedAnonAddyApiToken: "some_addyio_token", + forwardedAnonAddyDomain: "some_addyio_domain", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", ADDY_IO, { + baseUrl: "some_addyio_base", + token: "some_addyio_token", + domain: "some_addyio_domain", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates DuckDuckGo settings", async () => { + const helper = migrationHelper({ + forwardedDuckDuckGoToken: "some_duckduckgo_token", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", DUCK_DUCK_GO, { + token: "some_duckduckgo_token", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates Firefox Relay settings", async () => { + const helper = migrationHelper({ + forwardedFirefoxApiToken: "some_firefox_token", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", FIREFOX_RELAY, { + token: "some_firefox_token", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates Fastmail settings", async () => { + const helper = migrationHelper({ + forwardedFastmailApiToken: "some_fastmail_token", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", FASTMAIL, { + token: "some_fastmail_token", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates ForwardEmail settings", async () => { + const helper = migrationHelper({ + forwardedForwardEmailApiToken: "some_forwardemail_token", + forwardedForwardEmailDomain: "some_forwardemail_domain", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", FORWARD_EMAIL, { + token: "some_forwardemail_token", + domain: "some_forwardemail_domain", + }); + expectOtherSettingsRemain(helper); + }); + + it("migrates SimpleLogin settings", async () => { + const helper = migrationHelper({ + forwardedSimpleLoginApiKey: "some_simplelogin_token", + forwardedSimpleLoginBaseUrl: "some_simplelogin_baseurl", + }); + const migrator = new ForwarderOptionsMigrator(64, 65); + + await migrator.migrate(helper); + + expect(helper.setToUser).toHaveBeenCalledWith("SomeAccount", SIMPLE_LOGIN, { + token: "some_simplelogin_token", + baseUrl: "some_simplelogin_baseurl", + }); + expectOtherSettingsRemain(helper); + }); + }); +}); diff --git a/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.ts b/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.ts new file mode 100644 index 00000000000..6dad7ae3420 --- /dev/null +++ b/libs/common/src/state-migrations/migrations/65-migrate-forwarder-settings.ts @@ -0,0 +1,245 @@ +import { KeyDefinitionLike, MigrationHelper } from "../migration-helper"; +import { Migrator } from "../migrator"; + +/** settings targeted by migrator */ +export type AccountType = { + settings?: { + usernameGenerationOptions?: ExpectedOptions; + }; +}; + +/** username generation options prior to refactoring */ +export type ExpectedOptions = { + type?: "word" | "subaddress" | "catchall" | "forwarded"; + wordCapitalize?: boolean; + wordIncludeNumber?: boolean; + subaddressType?: "random" | "website-name"; + subaddressEmail?: string; + catchallType?: "random" | "website-name"; + catchallDomain?: string; + forwardedService?: string; + forwardedAnonAddyApiToken?: string; + forwardedAnonAddyDomain?: string; + forwardedAnonAddyBaseUrl?: string; + forwardedDuckDuckGoToken?: string; + forwardedFirefoxApiToken?: string; + forwardedFastmailApiToken?: string; + forwardedForwardEmailApiToken?: string; + forwardedForwardEmailDomain?: string; + forwardedSimpleLoginApiKey?: string; + forwardedSimpleLoginBaseUrl?: string; +}; + +/** username generation options after refactoring */ +type ConvertedOptions = { + generator: GeneratorNavigation; + algorithms: { + catchall: CatchallGenerationOptions; + effUsername: EffUsernameGenerationOptions; + subaddress: SubaddressGenerationOptions; + }; + forwarders: { + addyIo: SelfHostedApiOptions & EmailDomainOptions; + duckDuckGo: ApiOptions; + fastmail: ApiOptions; + firefoxRelay: ApiOptions; + forwardEmail: ApiOptions & EmailDomainOptions; + simpleLogin: SelfHostedApiOptions; + }; +}; + +export const NAVIGATION: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "generatorSettings", +}; + +export const CATCHALL: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "catchallGeneratorSettings", +}; + +export const EFF_USERNAME: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "effUsernameGeneratorSettings", +}; + +export const SUBADDRESS: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "subaddressGeneratorSettings", +}; + +export const ADDY_IO: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "addyIoBuffer", +}; + +export const DUCK_DUCK_GO: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "duckDuckGoBuffer", +}; + +export const FASTMAIL: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "fastmailBuffer", +}; + +export const FIREFOX_RELAY: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "firefoxRelayBuffer", +}; + +export const FORWARD_EMAIL: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "forwardEmailBuffer", +}; + +export const SIMPLE_LOGIN: KeyDefinitionLike = { + stateDefinition: { + name: "generator", + }, + key: "simpleLoginBuffer", +}; + +export type GeneratorNavigation = { + type?: string; + username?: string; + forwarder?: string; +}; + +type UsernameGenerationMode = "random" | "website-name"; + +type CatchallGenerationOptions = { + catchallType?: UsernameGenerationMode; + catchallDomain?: string; +}; + +type EffUsernameGenerationOptions = { + wordCapitalize?: boolean; + wordIncludeNumber?: boolean; +}; + +type SubaddressGenerationOptions = { + subaddressType?: UsernameGenerationMode; + subaddressEmail?: string; +}; + +type ApiOptions = { + token?: string; +}; + +type SelfHostedApiOptions = ApiOptions & { + baseUrl: string; +}; + +type EmailDomainOptions = { + domain: string; +}; + +export class ForwarderOptionsMigrator extends Migrator<64, 65> { + async migrate(helper: MigrationHelper): Promise { + const accounts = await helper.getAccounts(); + + async function migrateAccount(userId: string, account: AccountType) { + const legacyOptions = account?.settings?.usernameGenerationOptions; + + if (legacyOptions) { + const converted = convertSettings(legacyOptions); + await storeSettings(helper, userId, converted); + await deleteSettings(helper, userId, account); + } + } + + await Promise.all([...accounts.map(({ userId, account }) => migrateAccount(userId, account))]); + } + + async rollback(helper: MigrationHelper): Promise { + // not supported + } +} + +function convertSettings(options: ExpectedOptions): ConvertedOptions { + const forwarders = { + addyIo: { + baseUrl: options.forwardedAnonAddyBaseUrl, + token: options.forwardedAnonAddyApiToken, + domain: options.forwardedAnonAddyDomain, + }, + duckDuckGo: { + token: options.forwardedDuckDuckGoToken, + }, + fastmail: { + token: options.forwardedFastmailApiToken, + }, + firefoxRelay: { + token: options.forwardedFirefoxApiToken, + }, + forwardEmail: { + token: options.forwardedForwardEmailApiToken, + domain: options.forwardedForwardEmailDomain, + }, + simpleLogin: { + token: options.forwardedSimpleLoginApiKey, + baseUrl: options.forwardedSimpleLoginBaseUrl, + }, + }; + + const generator = { + username: options.type, + forwarder: options.forwardedService, + }; + + const algorithms = { + effUsername: { + wordCapitalize: options.wordCapitalize, + wordIncludeNumber: options.wordIncludeNumber, + }, + subaddress: { + subaddressType: options.subaddressType, + subaddressEmail: options.subaddressEmail, + }, + catchall: { + catchallType: options.catchallType, + catchallDomain: options.catchallDomain, + }, + }; + + return { generator, algorithms, forwarders }; +} + +async function storeSettings(helper: MigrationHelper, userId: string, converted: ConvertedOptions) { + await Promise.all([ + helper.setToUser(userId, NAVIGATION, converted.generator), + helper.setToUser(userId, CATCHALL, converted.algorithms.catchall), + helper.setToUser(userId, EFF_USERNAME, converted.algorithms.effUsername), + helper.setToUser(userId, SUBADDRESS, converted.algorithms.subaddress), + helper.setToUser(userId, ADDY_IO, converted.forwarders.addyIo), + helper.setToUser(userId, DUCK_DUCK_GO, converted.forwarders.duckDuckGo), + helper.setToUser(userId, FASTMAIL, converted.forwarders.fastmail), + helper.setToUser(userId, FIREFOX_RELAY, converted.forwarders.firefoxRelay), + helper.setToUser(userId, FORWARD_EMAIL, converted.forwarders.forwardEmail), + helper.setToUser(userId, SIMPLE_LOGIN, converted.forwarders.simpleLogin), + ]); +} + +async function deleteSettings(helper: MigrationHelper, userId: string, account: AccountType) { + delete account?.settings?.usernameGenerationOptions; + await helper.set(userId, account); +} diff --git a/libs/common/src/tools/generator/abstractions/generator-history.abstraction.ts b/libs/common/src/tools/generator/abstractions/generator-history.abstraction.ts index edda0dcb2ba..a1d358a13f8 100644 --- a/libs/common/src/tools/generator/abstractions/generator-history.abstraction.ts +++ b/libs/common/src/tools/generator/abstractions/generator-history.abstraction.ts @@ -38,6 +38,12 @@ export abstract class GeneratorHistoryService { */ take: (userId: UserId, credential: string) => Promise; + /** Deletes a user's credential history. + * @param userId identifies the user taking the credential. + * @returns A promise that completes when the history is cleared. + */ + clear: (userId: UserId) => Promise; + /** Lists all credentials for a user. * @param userId identifies the user listing the credential. * @remarks This field is eventually consistent with `track` and `take` operations. diff --git a/libs/common/src/tools/generator/abstractions/generator-strategy.abstraction.ts b/libs/common/src/tools/generator/abstractions/generator-strategy.abstraction.ts index 7cfe320abec..7bc0f21739f 100644 --- a/libs/common/src/tools/generator/abstractions/generator-strategy.abstraction.ts +++ b/libs/common/src/tools/generator/abstractions/generator-strategy.abstraction.ts @@ -23,9 +23,6 @@ export abstract class GeneratorStrategy { /** Identifies the policy enforced by the generator. */ policy: PolicyType; - /** Length of time in milliseconds to cache the evaluator */ - cache_ms: number; - /** Operator function that converts a policy collection observable to a single * policy evaluator observable. * @param policy The policy being evaluated. diff --git a/libs/common/src/tools/generator/abstractions/index.ts b/libs/common/src/tools/generator/abstractions/index.ts index 13dce17d170..ef40dfd434f 100644 --- a/libs/common/src/tools/generator/abstractions/index.ts +++ b/libs/common/src/tools/generator/abstractions/index.ts @@ -1,3 +1,4 @@ +export { GeneratorHistoryService } from "./generator-history.abstraction"; export { GeneratorNavigationService } from "./generator-navigation.service.abstraction"; export { GeneratorService } from "./generator.service.abstraction"; export { GeneratorStrategy } from "./generator-strategy.abstraction"; diff --git a/libs/common/src/tools/generator/abstractions/password-generation.service.abstraction.ts b/libs/common/src/tools/generator/abstractions/password-generation.service.abstraction.ts index b3bd30be5c7..f6b5ca9cabe 100644 --- a/libs/common/src/tools/generator/abstractions/password-generation.service.abstraction.ts +++ b/libs/common/src/tools/generator/abstractions/password-generation.service.abstraction.ts @@ -1,3 +1,5 @@ +import { Observable } from "rxjs"; + import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; import { GeneratedPasswordHistory } from "../password/generated-password-history"; import { PasswordGeneratorOptions } from "../password/password-generator-options"; @@ -7,11 +9,12 @@ export abstract class PasswordGenerationServiceAbstraction { generatePassword: (options: PasswordGeneratorOptions) => Promise; generatePassphrase: (options: PasswordGeneratorOptions) => Promise; getOptions: () => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>; + getOptions$: () => Observable<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>; enforcePasswordGeneratorPoliciesOnOptions: ( options: PasswordGeneratorOptions, ) => Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]>; saveOptions: (options: PasswordGeneratorOptions) => Promise; getHistory: () => Promise; addHistory: (password: string) => Promise; - clear: (userId?: string) => Promise; + clear: (userId?: string) => Promise; } diff --git a/libs/common/src/tools/generator/abstractions/username-generation.service.abstraction.ts b/libs/common/src/tools/generator/abstractions/username-generation.service.abstraction.ts index 02b25e6113a..f11cbf02ed2 100644 --- a/libs/common/src/tools/generator/abstractions/username-generation.service.abstraction.ts +++ b/libs/common/src/tools/generator/abstractions/username-generation.service.abstraction.ts @@ -1,3 +1,5 @@ +import { Observable } from "rxjs"; + import { UsernameGeneratorOptions } from "../username/username-generation-options"; /** @deprecated Use {@link GeneratorService} with a username {@link GeneratorStrategy} instead. */ @@ -8,5 +10,6 @@ export abstract class UsernameGenerationServiceAbstraction { generateCatchall: (options: UsernameGeneratorOptions) => Promise; generateForwarded: (options: UsernameGeneratorOptions) => Promise; getOptions: () => Promise; + getOptions$: () => Observable; saveOptions: (options: UsernameGeneratorOptions) => Promise; } diff --git a/libs/common/src/tools/generator/default-generator.service.spec.ts b/libs/common/src/tools/generator/default-generator.service.spec.ts index c93aec44d95..94d7d62fa8f 100644 --- a/libs/common/src/tools/generator/default-generator.service.spec.ts +++ b/libs/common/src/tools/generator/default-generator.service.spec.ts @@ -23,13 +23,9 @@ import { DefaultGeneratorService } from "."; function mockPolicyService(config?: { state?: BehaviorSubject }) { const service = mock(); - // FIXME: swap out the mock return value when `getAll$` becomes available const stateValue = config?.state ?? new BehaviorSubject([null]); service.getAll$.mockReturnValue(stateValue); - // const stateValue = config?.state ?? new BehaviorSubject(null); - // service.getAll$.mockReturnValue(stateValue); - return service; } diff --git a/libs/common/src/tools/generator/default-generator.service.ts b/libs/common/src/tools/generator/default-generator.service.ts index 7fd794472c3..cec8b75f0cb 100644 --- a/libs/common/src/tools/generator/default-generator.service.ts +++ b/libs/common/src/tools/generator/default-generator.service.ts @@ -7,6 +7,13 @@ import { UserId } from "../../types/guid"; import { GeneratorStrategy, GeneratorService, PolicyEvaluator } from "./abstractions"; +type DefaultGeneratorServiceTuning = { + /* amount of time to keep the most recent policy after a subscription ends. Once the + * cache expires, the ignoreQty and timeoutMs settings apply to the next lookup. + */ + policyCacheMs: number; +}; + /** {@link GeneratorServiceAbstraction} */ export class DefaultGeneratorService implements GeneratorService { /** Instantiates the generator service @@ -17,8 +24,18 @@ export class DefaultGeneratorService implements GeneratorServic constructor( private strategy: GeneratorStrategy, private policy: PolicyService, - ) {} + tuning: Partial = {}, + ) { + this.tuning = Object.assign( + { + // a minute + policyCacheMs: 60000, + }, + tuning, + ); + } + private tuning: DefaultGeneratorServiceTuning; private _evaluators$ = new Map>>(); /** {@link GeneratorService.options$} */ @@ -57,7 +74,7 @@ export class DefaultGeneratorService implements GeneratorServic // and reduce GC pressure. share({ connector: () => new ReplaySubject(1), - resetOnRefCountZero: () => timer(this.strategy.cache_ms), + resetOnRefCountZero: () => timer(this.tuning.policyCacheMs), }), ); diff --git a/libs/common/src/tools/generator/history/legacy-password-history-decryptor.ts b/libs/common/src/tools/generator/history/legacy-password-history-decryptor.ts new file mode 100644 index 00000000000..6c59ca837cd --- /dev/null +++ b/libs/common/src/tools/generator/history/legacy-password-history-decryptor.ts @@ -0,0 +1,29 @@ +import { CryptoService } from "../../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../../platform/abstractions/encrypt.service"; +import { EncString } from "../../../platform/models/domain/enc-string"; +import { UserId } from "../../../types/guid"; +import { GeneratedPasswordHistory } from "../password/generated-password-history"; + +/** Strategy that decrypts a password history */ +export class LegacyPasswordHistoryDecryptor { + constructor( + private userId: UserId, + private cryptoService: CryptoService, + private encryptService: EncryptService, + ) {} + + /** Decrypts a password history. */ + async decrypt(history: GeneratedPasswordHistory[]): Promise { + const key = await this.cryptoService.getUserKey(this.userId); + + const promises = (history ?? []).map(async (item) => { + const encrypted = new EncString(item.password); + const decrypted = await this.encryptService.decryptToUtf8(encrypted, key); + return new GeneratedPasswordHistory(decrypted, item.date); + }); + + const decrypted = await Promise.all(promises); + + return decrypted; + } +} diff --git a/libs/common/src/tools/generator/history/local-generator-history.service.spec.ts b/libs/common/src/tools/generator/history/local-generator-history.service.spec.ts index 57dde51fc13..9640016584a 100644 --- a/libs/common/src/tools/generator/history/local-generator-history.service.spec.ts +++ b/libs/common/src/tools/generator/history/local-generator-history.service.spec.ts @@ -1,5 +1,5 @@ import { mock } from "jest-mock-extended"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, of } from "rxjs"; import { FakeStateProvider, awaitAsync, mockAccountServiceWith } from "../../../../spec"; import { CryptoService } from "../../../platform/abstractions/crypto.service"; @@ -24,6 +24,7 @@ describe("LocalGeneratorHistoryService", () => { encryptService.encrypt.mockImplementation((p) => Promise.resolve(p as unknown as EncString)); encryptService.decryptToUtf8.mockImplementation((c) => Promise.resolve(c.encryptedString)); keyService.getUserKey.mockImplementation(() => Promise.resolve(userKey)); + keyService.getInMemoryUserKeyFor$.mockImplementation(() => of(true as unknown as UserKey)); }); afterEach(() => { diff --git a/libs/common/src/tools/generator/history/local-generator-history.service.ts b/libs/common/src/tools/generator/history/local-generator-history.service.ts index 3a65890c50d..dd93e630cab 100644 --- a/libs/common/src/tools/generator/history/local-generator-history.service.ts +++ b/libs/common/src/tools/generator/history/local-generator-history.service.ts @@ -5,12 +5,14 @@ import { EncryptService } from "../../../platform/abstractions/encrypt.service"; import { SingleUserState, StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { GeneratorHistoryService } from "../abstractions/generator-history.abstraction"; -import { GENERATOR_HISTORY } from "../key-definitions"; +import { GENERATOR_HISTORY, GENERATOR_HISTORY_BUFFER } from "../key-definitions"; +import { BufferedState } from "../state/buffered-state"; import { PaddedDataPacker } from "../state/padded-data-packer"; import { SecretState } from "../state/secret-state"; import { UserKeyEncryptor } from "../state/user-key-encryptor"; import { GeneratedCredential } from "./generated-credential"; +import { LegacyPasswordHistoryDecryptor } from "./legacy-password-history-decryptor"; import { GeneratorCategory, HistoryServiceOptions } from "./options"; const OPTIONS_FRAME_SIZE = 2048; @@ -51,7 +53,7 @@ export class LocalGeneratorHistoryService extends GeneratorHistoryService { }, { shouldUpdate: (credentials) => - credentials?.some((f) => f.credential !== credential) ?? true, + !(credentials?.some((f) => f.credential === credential) ?? false), }, ); @@ -82,6 +84,13 @@ export class LocalGeneratorHistoryService extends GeneratorHistoryService { return result; }; + /** {@link GeneratorHistoryService.take} */ + clear = async (userId: UserId) => { + const state = this.getCredentialState(userId); + const result = (await state.update(() => null)) ?? []; + return result; + }; + /** {@link GeneratorHistoryService.credentials$} */ credentials$ = (userId: UserId) => { return this.getCredentialState(userId).state$.pipe(map((credentials) => credentials ?? [])); @@ -98,11 +107,12 @@ export class LocalGeneratorHistoryService extends GeneratorHistoryService { return state; } - private createSecretState(userId: UserId) { + private createSecretState(userId: UserId): SingleUserState { // construct the encryptor const packer = new PaddedDataPacker(OPTIONS_FRAME_SIZE); const encryptor = new UserKeyEncryptor(this.encryptService, this.keyService, packer); + // construct the durable state const state = SecretState.from< GeneratedCredential[], number, @@ -111,6 +121,25 @@ export class LocalGeneratorHistoryService extends GeneratorHistoryService { GeneratedCredential >(userId, GENERATOR_HISTORY, this.stateProvider, encryptor); - return state; + // decryptor is just an algorithm, but it can't run until the key is available; + // providing it via an observable makes running it early impossible + const decryptor = new LegacyPasswordHistoryDecryptor( + userId, + this.keyService, + this.encryptService, + ); + const decryptor$ = this.keyService + .getInMemoryUserKeyFor$(userId) + .pipe(map((key) => key && decryptor)); + + // move data from the old password history once decryptor is available + const buffer = new BufferedState( + this.stateProvider, + GENERATOR_HISTORY_BUFFER, + state, + decryptor$, + ); + + return buffer; } } diff --git a/libs/common/src/tools/generator/index.ts b/libs/common/src/tools/generator/index.ts index ae35c9ce0a1..9df054a502b 100644 --- a/libs/common/src/tools/generator/index.ts +++ b/libs/common/src/tools/generator/index.ts @@ -2,3 +2,5 @@ export * from "./abstractions/index"; export * from "./password/index"; export { DefaultGeneratorService } from "./default-generator.service"; +export { legacyPasswordGenerationServiceFactory } from "./legacy-password-generation.service"; +export { legacyUsernameGenerationServiceFactory } from "./legacy-username-generation.service"; diff --git a/libs/common/src/tools/generator/key-definition.spec.ts b/libs/common/src/tools/generator/key-definition.spec.ts index 9cbbc44e148..d4992af0b11 100644 --- a/libs/common/src/tools/generator/key-definition.spec.ts +++ b/libs/common/src/tools/generator/key-definition.spec.ts @@ -1,3 +1,7 @@ +import { mock } from "jest-mock-extended"; + +import { GeneratedCredential } from "./history"; +import { LegacyPasswordHistoryDecryptor } from "./history/legacy-password-history-decryptor"; import { EFF_USERNAME_SETTINGS, CATCHALL_SETTINGS, @@ -11,7 +15,15 @@ import { DUCK_DUCK_GO_FORWARDER, ADDY_IO_FORWARDER, GENERATOR_SETTINGS, + ADDY_IO_BUFFER, + DUCK_DUCK_GO_BUFFER, + FASTMAIL_BUFFER, + FIREFOX_RELAY_BUFFER, + FORWARD_EMAIL_BUFFER, + SIMPLE_LOGIN_BUFFER, + GENERATOR_HISTORY_BUFFER, } from "./key-definitions"; +import { GeneratedPasswordHistory } from "./password"; describe("Key definitions", () => { describe("GENERATOR_SETTINGS", () => { @@ -109,4 +121,121 @@ describe("Key definitions", () => { expect(result).toBe(value); }); }); + + describe("ADDY_IO_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = ADDY_IO_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("DUCK_DUCK_GO_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = DUCK_DUCK_GO_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("FASTMAIL_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = FASTMAIL_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("FIREFOX_RELAY_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = FIREFOX_RELAY_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("FORWARD_EMAIL_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = FORWARD_EMAIL_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("SIMPLE_LOGIN_BUFFER", () => { + it("should pass through deserialization", () => { + const value: any = {}; + + const result = SIMPLE_LOGIN_BUFFER.options.deserializer(value); + + expect(result).toBe(value); + }); + }); + + describe("GENERATOR_HISTORY_BUFFER", () => { + describe("options.deserializer", () => { + it("should deserialize generated password history", () => { + const value: any = [{ password: "foo", date: 1 }]; + + const [result] = GENERATOR_HISTORY_BUFFER.options.deserializer(value); + + expect(result).toEqual(value[0]); + expect(result).toBeInstanceOf(GeneratedPasswordHistory); + }); + + it.each([[undefined], [null]])("should ignore nullish (= %p) history", (value: any) => { + const result = GENERATOR_HISTORY_BUFFER.options.deserializer(value); + + expect(result).toEqual(undefined); + }); + }); + + it("should map generated password history to generated credentials", async () => { + const value: any = [new GeneratedPasswordHistory("foo", 1)]; + const decryptor = mock({ + decrypt(value) { + return Promise.resolve(value); + }, + }); + + const [result] = await GENERATOR_HISTORY_BUFFER.map(value, decryptor); + + expect(result).toEqual({ + credential: "foo", + category: "password", + generationDate: new Date(1), + }); + expect(result).toBeInstanceOf(GeneratedCredential); + }); + + describe("isValid", () => { + it("should accept histories with at least one entry", async () => { + const value: any = [new GeneratedPasswordHistory("foo", 1)]; + const decryptor = {} as any; + + const result = await GENERATOR_HISTORY_BUFFER.isValid(value, decryptor); + + expect(result).toEqual(true); + }); + + it("should reject histories with no entries", async () => { + const value: any = []; + const decryptor = {} as any; + + const result = await GENERATOR_HISTORY_BUFFER.isValid(value, decryptor); + + expect(result).toEqual(false); + }); + }); + }); }); diff --git a/libs/common/src/tools/generator/key-definitions.ts b/libs/common/src/tools/generator/key-definitions.ts index 074df484682..1ce2ec8ad12 100644 --- a/libs/common/src/tools/generator/key-definitions.ts +++ b/libs/common/src/tools/generator/key-definitions.ts @@ -1,9 +1,14 @@ -import { GENERATOR_DISK, GENERATOR_MEMORY, UserKeyDefinition } from "../../platform/state"; +import { Jsonify } from "type-fest"; + +import { GENERATOR_DISK, UserKeyDefinition } from "../../platform/state"; import { GeneratedCredential } from "./history/generated-credential"; +import { LegacyPasswordHistoryDecryptor } from "./history/legacy-password-history-decryptor"; import { GeneratorNavigation } from "./navigation/generator-navigation"; import { PassphraseGenerationOptions } from "./passphrase/passphrase-generation-options"; +import { GeneratedPasswordHistory } from "./password/generated-password-history"; import { PasswordGenerationOptions } from "./password/password-generation-options"; +import { BufferedKeyDefinition } from "./state/buffered-key-definition"; import { SecretClassifier } from "./state/secret-classifier"; import { SecretKeyDefinition } from "./state/secret-key-definition"; import { CatchallGenerationOptions } from "./username/catchall-generator-options"; @@ -18,11 +23,11 @@ import { SubaddressGenerationOptions } from "./username/subaddress-generator-opt /** plaintext password generation options */ export const GENERATOR_SETTINGS = new UserKeyDefinition( - GENERATOR_MEMORY, + GENERATOR_DISK, "generatorSettings", { deserializer: (value) => value, - clearOn: ["lock", "logout"], + clearOn: ["logout"], }, ); @@ -136,6 +141,66 @@ export const SIMPLE_LOGIN_FORWARDER = new UserKeyDefinition( + GENERATOR_DISK, + "addyIoBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + +/** backing store configuration for {@link Forwarders.DuckDuckGo} */ +export const DUCK_DUCK_GO_BUFFER = new BufferedKeyDefinition( + GENERATOR_DISK, + "duckDuckGoBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + +/** backing store configuration for {@link Forwarders.FastMail} */ +export const FASTMAIL_BUFFER = new BufferedKeyDefinition( + GENERATOR_DISK, + "fastmailBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + +/** backing store configuration for {@link Forwarders.FireFoxRelay} */ +export const FIREFOX_RELAY_BUFFER = new BufferedKeyDefinition( + GENERATOR_DISK, + "firefoxRelayBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + +/** backing store configuration for {@link Forwarders.ForwardEmail} */ +export const FORWARD_EMAIL_BUFFER = new BufferedKeyDefinition( + GENERATOR_DISK, + "forwardEmailBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + +/** backing store configuration for {@link forwarders.SimpleLogin} */ +export const SIMPLE_LOGIN_BUFFER = new BufferedKeyDefinition( + GENERATOR_DISK, + "simpleLoginBuffer", + { + deserializer: (value) => value, + clearOn: ["logout"], + }, +); + /** encrypted password generation history */ export const GENERATOR_HISTORY = SecretKeyDefinition.array( GENERATOR_DISK, @@ -146,3 +211,24 @@ export const GENERATOR_HISTORY = SecretKeyDefinition.array( clearOn: ["logout"], }, ); + +/** encrypted password generation history subject to migration */ +export const GENERATOR_HISTORY_BUFFER = new BufferedKeyDefinition< + GeneratedPasswordHistory[], + GeneratedCredential[], + LegacyPasswordHistoryDecryptor +>(GENERATOR_DISK, "localGeneratorHistoryBuffer", { + deserializer(history) { + const items = history as Jsonify[]; + return items?.map((h) => new GeneratedPasswordHistory(h.password, h.date)); + }, + async isValid(history) { + return history.length ? true : false; + }, + async map(history, decryptor) { + const credentials = await decryptor.decrypt(history); + const mapped = credentials.map((c) => new GeneratedCredential(c.password, "password", c.date)); + return mapped; + }, + clearOn: ["logout"], +}); diff --git a/libs/common/src/tools/generator/legacy-password-generation.service.spec.ts b/libs/common/src/tools/generator/legacy-password-generation.service.spec.ts index 093c68b3e83..c86bb9f8b04 100644 --- a/libs/common/src/tools/generator/legacy-password-generation.service.spec.ts +++ b/libs/common/src/tools/generator/legacy-password-generation.service.spec.ts @@ -8,7 +8,12 @@ import { of } from "rxjs"; import { mockAccountServiceWith } from "../../../spec"; import { UserId } from "../../types/guid"; -import { GeneratorNavigationService, GeneratorService } from "./abstractions"; +import { + GeneratorHistoryService, + GeneratorNavigationService, + GeneratorService, +} from "./abstractions"; +import { GeneratedCredential } from "./history"; import { LegacyPasswordGenerationService } from "./legacy-password-generation.service"; import { DefaultGeneratorNavigation, GeneratorNavigation } from "./navigation/generator-navigation"; import { GeneratorNavigationEvaluator } from "./navigation/generator-navigation-evaluator"; @@ -22,6 +27,7 @@ import { import { DisabledPassphraseGeneratorPolicy } from "./passphrase/passphrase-generator-policy"; import { DefaultPasswordGenerationOptions, + GeneratedPasswordHistory, PasswordGenerationOptions, PasswordGeneratorOptions, PasswordGeneratorOptionsEvaluator, @@ -97,10 +103,10 @@ function createNavigationGenerator( defaults$(id: UserId) { return of(DefaultGeneratorNavigation); }, - saveOptions(userId, options) { + saveOptions: jest.fn((userId, options) => { savedOptions = options; return Promise.resolve(); - }, + }), }); return generator; @@ -113,7 +119,7 @@ describe("LegacyPasswordGenerationService", () => { describe("generatePassword", () => { it("invokes the inner password generator to generate passwords", async () => { const innerPassword = createPasswordGenerator(); - const generator = new LegacyPasswordGenerationService(null, null, innerPassword, null); + const generator = new LegacyPasswordGenerationService(null, null, innerPassword, null, null); const options = { type: "password" } as PasswordGeneratorOptions; await generator.generatePassword(options); @@ -123,7 +129,13 @@ describe("LegacyPasswordGenerationService", () => { it("invokes the inner passphrase generator to generate passphrases", async () => { const innerPassphrase = createPassphraseGenerator(); - const generator = new LegacyPasswordGenerationService(null, null, null, innerPassphrase); + const generator = new LegacyPasswordGenerationService( + null, + null, + null, + innerPassphrase, + null, + ); const options = { type: "passphrase" } as PasswordGeneratorOptions; await generator.generatePassword(options); @@ -135,7 +147,13 @@ describe("LegacyPasswordGenerationService", () => { describe("generatePassphrase", () => { it("invokes the inner passphrase generator", async () => { const innerPassphrase = createPassphraseGenerator(); - const generator = new LegacyPasswordGenerationService(null, null, null, innerPassphrase); + const generator = new LegacyPasswordGenerationService( + null, + null, + null, + innerPassphrase, + null, + ); const options = {} as PasswordGeneratorOptions; await generator.generatePassphrase(options); @@ -157,7 +175,7 @@ describe("LegacyPasswordGenerationService", () => { number: true, minNumber: 3, special: false, - minSpecial: 4, + minSpecial: 0, }); const innerPassphrase = createPassphraseGenerator({ numWords: 10, @@ -176,29 +194,29 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [result] = await generator.getOptions(); expect(result).toEqual({ type: "passphrase", - username: "word", - forwarder: "simplelogin", length: 29, - minLength: 20, + minLength: 5, ambiguous: false, uppercase: true, minUppercase: 1, lowercase: false, - minLowercase: 2, + minLowercase: 0, number: true, minNumber: 3, special: false, - minSpecial: 4, + minSpecial: 0, numWords: 10, wordSeparator: "-", capitalize: true, includeNumber: false, + policyUpdated: true, }); }); @@ -212,14 +230,18 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [result] = await generator.getOptions(); expect(result).toEqual({ - ...DefaultGeneratorNavigation, + type: DefaultGeneratorNavigation.type, ...DefaultPassphraseGenerationOptions, ...DefaultPasswordGenerationOptions, + minLowercase: 1, + minUppercase: 1, + policyUpdated: true, }); }); @@ -256,6 +278,7 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [, policy] = await generator.getOptions(); @@ -301,6 +324,7 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [result] = await generator.enforcePasswordGeneratorPoliciesOnOptions(options); @@ -340,6 +364,7 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [result] = await generator.enforcePasswordGeneratorPoliciesOnOptions(options); @@ -385,6 +410,7 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const [, policy] = await generator.enforcePasswordGeneratorPoliciesOnOptions({}); @@ -416,22 +442,21 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const options = { type: "password" as const, - username: "word" as const, - forwarder: "simplelogin" as const, length: 29, - minLength: 20, + minLength: 5, ambiguous: false, uppercase: true, minUppercase: 1, lowercase: false, - minLowercase: 2, + minLowercase: 0, number: true, minNumber: 3, special: false, - minSpecial: 4, + minSpecial: 0, }; await generator.saveOptions(options); @@ -450,11 +475,10 @@ describe("LegacyPasswordGenerationService", () => { navigation, innerPassword, innerPassphrase, + null, ); const options = { type: "passphrase" as const, - username: "word" as const, - forwarder: "simplelogin" as const, numWords: 10, wordSeparator: "-", capitalize: true, @@ -466,5 +490,78 @@ describe("LegacyPasswordGenerationService", () => { expect(result).toMatchObject(options); }); + + it("preserves saved navigation options", async () => { + const innerPassword = createPasswordGenerator(); + const innerPassphrase = createPassphraseGenerator(); + const navigation = createNavigationGenerator({ + type: "password", + username: "forwarded", + forwarder: "firefoxrelay", + }); + const accountService = mockAccountServiceWith(SomeUser); + const generator = new LegacyPasswordGenerationService( + accountService, + navigation, + innerPassword, + innerPassphrase, + null, + ); + const options = { + type: "passphrase" as const, + numWords: 10, + wordSeparator: "-", + capitalize: true, + includeNumber: false, + }; + + await generator.saveOptions(options); + + expect(navigation.saveOptions).toHaveBeenCalledWith(SomeUser, { + type: "passphrase", + username: "forwarded", + forwarder: "firefoxrelay", + }); + }); + }); + + describe("getHistory", () => { + it("gets the active user's history from the history service", async () => { + const history = mock(); + history.credentials$.mockReturnValue( + of([new GeneratedCredential("foo", "password", new Date(100))]), + ); + const accountService = mockAccountServiceWith(SomeUser); + const generator = new LegacyPasswordGenerationService( + accountService, + null, + null, + null, + history, + ); + + const result = await generator.getHistory(); + + expect(history.credentials$).toHaveBeenCalledWith(SomeUser); + expect(result).toEqual([new GeneratedPasswordHistory("foo", 100)]); + }); + }); + + describe("addHistory", () => { + it("adds a history item as a password credential", async () => { + const history = mock(); + const accountService = mockAccountServiceWith(SomeUser); + const generator = new LegacyPasswordGenerationService( + accountService, + null, + null, + null, + history, + ); + + await generator.addHistory("foo"); + + expect(history.track).toHaveBeenCalledWith(SomeUser, "foo", "password"); + }); }); }); diff --git a/libs/common/src/tools/generator/legacy-password-generation.service.ts b/libs/common/src/tools/generator/legacy-password-generation.service.ts index 0b429b356bc..74b2ab46e6b 100644 --- a/libs/common/src/tools/generator/legacy-password-generation.service.ts +++ b/libs/common/src/tools/generator/legacy-password-generation.service.ts @@ -1,21 +1,42 @@ -import { concatMap, zip, map, firstValueFrom } from "rxjs"; +import { + concatMap, + zip, + map, + firstValueFrom, + combineLatest, + pairwise, + of, + concat, + Observable, +} from "rxjs"; import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; import { PasswordGeneratorPolicyOptions } from "../../admin-console/models/domain/password-generator-policy-options"; import { AccountService } from "../../auth/abstractions/account.service"; import { CryptoService } from "../../platform/abstractions/crypto.service"; +import { EncryptService } from "../../platform/abstractions/encrypt.service"; import { StateProvider } from "../../platform/state"; -import { GeneratorService, GeneratorNavigationService } from "./abstractions"; +import { + GeneratorHistoryService, + GeneratorService, + GeneratorNavigationService, + PolicyEvaluator, +} from "./abstractions"; import { PasswordGenerationServiceAbstraction } from "./abstractions/password-generation.service.abstraction"; import { DefaultGeneratorService } from "./default-generator.service"; +import { GeneratedCredential } from "./history"; +import { LocalGeneratorHistoryService } from "./history/local-generator-history.service"; +import { GeneratorNavigation } from "./navigation"; import { DefaultGeneratorNavigationService } from "./navigation/default-generator-navigation.service"; +import { GeneratorNavigationPolicy } from "./navigation/generator-navigation-policy"; import { PassphraseGenerationOptions, PassphraseGeneratorPolicy, PassphraseGeneratorStrategy, } from "./passphrase"; import { + GeneratedPasswordHistory, PasswordGenerationOptions, PasswordGenerationService, PasswordGeneratorOptions, @@ -23,7 +44,15 @@ import { PasswordGeneratorStrategy, } from "./password"; +type MappedOptions = { + generator: GeneratorNavigation; + password: PasswordGenerationOptions; + passphrase: PassphraseGenerationOptions; + policyUpdated: boolean; +}; + export function legacyPasswordGenerationServiceFactory( + encryptService: EncryptService, cryptoService: CryptoService, policyService: PolicyService, accountService: AccountService, @@ -45,7 +74,15 @@ export function legacyPasswordGenerationServiceFactory( const navigation = new DefaultGeneratorNavigationService(stateProvider, policyService); - return new LegacyPasswordGenerationService(accountService, navigation, passwords, passphrases); + const history = new LocalGeneratorHistoryService(encryptService, cryptoService, stateProvider); + + return new LegacyPasswordGenerationService( + accountService, + navigation, + passwords, + passphrases, + history, + ); } /** Adapts the generator 2.0 design to 1.0 angular services. */ @@ -61,6 +98,7 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic PassphraseGenerationOptions, PassphraseGeneratorPolicy >, + private readonly history: GeneratorHistoryService, ) {} generatePassword(options: PasswordGeneratorOptions) { @@ -75,21 +113,112 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic return this.passphrases.generate(options); } - async getOptions() { - const options$ = this.accountService.activeAccount$.pipe( + private getRawOptions$() { + // give the typechecker a nudge to avoid "implicit any" errors + type RawOptionsIntermediateType = [ + PasswordGenerationOptions, + PasswordGenerationOptions, + [PolicyEvaluator, number], + PassphraseGenerationOptions, + PassphraseGenerationOptions, + [PolicyEvaluator, number], + GeneratorNavigation, + GeneratorNavigation, + [PolicyEvaluator, number], + ]; + + function withSequenceNumber(observable$: Observable) { + return observable$.pipe(map((evaluator, i) => [evaluator, i] as const)); + } + + // initial array ensures that destructuring never fails; sequence numbers + // set to `-1` so that the first update reflects that the policy changed from + // "unknown" to "whatever was provided by the service". This needs to be called + // each time the active user changes or the `concat` will block. + function initial$() { + const initial: RawOptionsIntermediateType = [ + null, + null, + [null, -1], + null, + null, + [null, -1], + null, + null, + [null, -1], + ]; + + return of(initial); + } + + function intermediatePairsToRawOptions([previous, current]: [ + RawOptionsIntermediateType, + RawOptionsIntermediateType, + ]) { + const [, , [, passwordPrevious], , , [, passphrasePrevious], , , [, generatorPrevious]] = + previous; + const [ + passwordOptions, + passwordDefaults, + [passwordEvaluator, passwordCurrent], + passphraseOptions, + passphraseDefaults, + [passphraseEvaluator, passphraseCurrent], + generatorOptions, + generatorDefaults, + [generatorEvaluator, generatorCurrent], + ] = current; + + // when any of the sequence numbers change, the emission occurs as the result of + // a policy update + const policyEmitted = + passwordPrevious < passwordCurrent || + passphrasePrevious < passphraseCurrent || + generatorPrevious < generatorCurrent; + + const result = [ + passwordOptions, + passwordDefaults, + passwordEvaluator, + passphraseOptions, + passphraseDefaults, + passphraseEvaluator, + generatorOptions, + generatorDefaults, + generatorEvaluator, + policyEmitted, + ] as const; + + return result; + } + + // look upon my works, ye mighty, and despair! + const rawOptions$ = this.accountService.activeAccount$.pipe( concatMap((activeUser) => - zip( - this.passwords.options$(activeUser.id), - this.passwords.defaults$(activeUser.id), - this.passwords.evaluator$(activeUser.id), - this.passphrases.options$(activeUser.id), - this.passphrases.defaults$(activeUser.id), - this.passphrases.evaluator$(activeUser.id), - this.navigation.options$(activeUser.id), - this.navigation.defaults$(activeUser.id), - this.navigation.evaluator$(activeUser.id), + concat( + initial$(), + combineLatest([ + this.passwords.options$(activeUser.id), + this.passwords.defaults$(activeUser.id), + withSequenceNumber(this.passwords.evaluator$(activeUser.id)), + this.passphrases.options$(activeUser.id), + this.passphrases.defaults$(activeUser.id), + withSequenceNumber(this.passphrases.evaluator$(activeUser.id)), + this.navigation.options$(activeUser.id), + this.navigation.defaults$(activeUser.id), + withSequenceNumber(this.navigation.evaluator$(activeUser.id)), + ]), ), ), + pairwise(), + map(intermediatePairsToRawOptions), + ); + + return rawOptions$; + } + + getOptions$() { + const options$ = this.getRawOptions$().pipe( map( ([ passwordOptions, @@ -101,14 +230,25 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic generatorOptions, generatorDefaults, generatorEvaluator, + policyUpdated, ]) => { - const options: PasswordGeneratorOptions = Object.assign( - {}, + const passwordOptionsWithPolicy = passwordEvaluator.applyPolicy( passwordOptions ?? passwordDefaults, + ); + const passphraseOptionsWithPolicy = passphraseEvaluator.applyPolicy( passphraseOptions ?? passphraseDefaults, + ); + const generatorOptionsWithPolicy = generatorEvaluator.applyPolicy( generatorOptions ?? generatorDefaults, ); + const options = this.toPasswordGeneratorOptions({ + password: passwordEvaluator.sanitize(passwordOptionsWithPolicy), + passphrase: passphraseEvaluator.sanitize(passphraseOptionsWithPolicy), + generator: generatorEvaluator.sanitize(generatorOptionsWithPolicy), + policyUpdated, + }); + const policy = Object.assign( new PasswordGeneratorPolicyOptions(), passwordEvaluator.policy, @@ -116,13 +256,16 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic generatorEvaluator.policy, ); - return [options, policy] as [PasswordGenerationOptions, PasswordGeneratorPolicyOptions]; + return [options, policy] as [PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]; }, ), ); - const options = await firstValueFrom(options$); - return options; + return options$; + } + + async getOptions() { + return await firstValueFrom(this.getOptions$()); } async enforcePasswordGeneratorPoliciesOnOptions(options: PasswordGeneratorOptions) { @@ -164,21 +307,103 @@ export class LegacyPasswordGenerationService implements PasswordGenerationServic // callers assume this function updates the options parameter Object.assign(options, sanitized), policy, - ] as [PasswordGenerationOptions, PasswordGeneratorPolicyOptions]; + ] as [PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]; } async saveOptions(options: PasswordGeneratorOptions) { + const stored = this.toStoredOptions(options); const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - await this.navigation.saveOptions(activeAccount.id, options); - if (options.type === "password") { - await this.passwords.saveOptions(activeAccount.id, options); - } else { - await this.passphrases.saveOptions(activeAccount.id, options); - } + // generator settings needs to preserve whether password or passphrase is selected, + // so `navigationOptions` is mutated. + const navigationOptions$ = zip( + this.navigation.options$(activeAccount.id), + this.navigation.defaults$(activeAccount.id), + ).pipe(map(([options, defaults]) => options ?? defaults)); + let navigationOptions = await firstValueFrom(navigationOptions$); + navigationOptions = Object.assign(navigationOptions, stored.generator); + await this.navigation.saveOptions(activeAccount.id, navigationOptions); + + // overwrite all other settings with latest values + await this.passwords.saveOptions(activeAccount.id, stored.password); + await this.passphrases.saveOptions(activeAccount.id, stored.passphrase); } - getHistory: () => Promise; - addHistory: (password: string) => Promise; - clear: (userId?: string) => Promise; + private toStoredOptions(options: PasswordGeneratorOptions): MappedOptions { + return { + generator: { + type: options.type, + }, + password: { + length: options.length, + minLength: options.minLength, + ambiguous: options.ambiguous, + uppercase: options.uppercase, + minUppercase: options.minUppercase, + lowercase: options.lowercase, + minLowercase: options.minLowercase, + number: options.number, + minNumber: options.minNumber, + special: options.special, + minSpecial: options.minSpecial, + }, + passphrase: { + numWords: options.numWords, + wordSeparator: options.wordSeparator, + capitalize: options.capitalize, + includeNumber: options.includeNumber, + }, + policyUpdated: false, + }; + } + + private toPasswordGeneratorOptions(options: MappedOptions): PasswordGeneratorOptions { + return { + type: options.generator.type, + length: options.password.length, + minLength: options.password.minLength, + ambiguous: options.password.ambiguous, + uppercase: options.password.uppercase, + minUppercase: options.password.minUppercase, + lowercase: options.password.lowercase, + minLowercase: options.password.minLowercase, + number: options.password.number, + minNumber: options.password.minNumber, + special: options.password.special, + minSpecial: options.password.minSpecial, + numWords: options.passphrase.numWords, + wordSeparator: options.passphrase.wordSeparator, + capitalize: options.passphrase.capitalize, + includeNumber: options.passphrase.includeNumber, + policyUpdated: options.policyUpdated, + }; + } + + getHistory() { + const history = this.accountService.activeAccount$.pipe( + concatMap((account) => this.history.credentials$(account.id)), + map((history) => history.map(toGeneratedPasswordHistory)), + ); + + return firstValueFrom(history); + } + + async addHistory(password: string) { + const account = await firstValueFrom(this.accountService.activeAccount$); + // legacy service doesn't distinguish credential types + await this.history.track(account.id, password, "password"); + } + + clear() { + const history$ = this.accountService.activeAccount$.pipe( + concatMap((account) => this.history.clear(account.id)), + map((history) => history.map(toGeneratedPasswordHistory)), + ); + + return firstValueFrom(history$); + } +} + +function toGeneratedPasswordHistory(value: GeneratedCredential) { + return new GeneratedPasswordHistory(value.credential, value.generationDate.valueOf()); } diff --git a/libs/common/src/tools/generator/legacy-username-generation.service.spec.ts b/libs/common/src/tools/generator/legacy-username-generation.service.spec.ts index 41d9c78dd2b..8b5c8b81e5a 100644 --- a/libs/common/src/tools/generator/legacy-username-generation.service.spec.ts +++ b/libs/common/src/tools/generator/legacy-username-generation.service.spec.ts @@ -94,7 +94,7 @@ describe("LegacyUsernameGenerationService", () => { it("should generate a catchall username", async () => { const options = { type: "catchall" } as UsernameGeneratorOptions; const catchall = createGenerator(null, null); - catchall.generate.mockReturnValue(Promise.resolve("catchall@example.com")); + catchall.generate.mockResolvedValue("catchall@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -118,7 +118,7 @@ describe("LegacyUsernameGenerationService", () => { it("should generate an EFF word username", async () => { const options = { type: "word" } as UsernameGeneratorOptions; const effWord = createGenerator(null, null); - effWord.generate.mockReturnValue(Promise.resolve("eff word")); + effWord.generate.mockResolvedValue("eff word"); const generator = new LegacyUsernameGenerationService( null, null, @@ -142,7 +142,7 @@ describe("LegacyUsernameGenerationService", () => { it("should generate a subaddress username", async () => { const options = { type: "subaddress" } as UsernameGeneratorOptions; const subaddress = createGenerator(null, null); - subaddress.generate.mockReturnValue(Promise.resolve("subaddress@example.com")); + subaddress.generate.mockResolvedValue("subaddress@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -170,7 +170,7 @@ describe("LegacyUsernameGenerationService", () => { forwardedService: Forwarders.AddyIo.id, } as UsernameGeneratorOptions; const addyIo = createGenerator(null, null); - addyIo.generate.mockReturnValue(Promise.resolve("addyio@example.com")); + addyIo.generate.mockResolvedValue("addyio@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -196,7 +196,7 @@ describe("LegacyUsernameGenerationService", () => { it("should generate a catchall username", async () => { const options = { type: "catchall" } as UsernameGeneratorOptions; const catchall = createGenerator(null, null); - catchall.generate.mockReturnValue(Promise.resolve("catchall@example.com")); + catchall.generate.mockResolvedValue("catchall@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -222,7 +222,7 @@ describe("LegacyUsernameGenerationService", () => { it("should generate a subaddress username", async () => { const options = { type: "subaddress" } as UsernameGeneratorOptions; const subaddress = createGenerator(null, null); - subaddress.generate.mockReturnValue(Promise.resolve("subaddress@example.com")); + subaddress.generate.mockResolvedValue("subaddress@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -254,7 +254,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const addyIo = createGenerator(null, null); - addyIo.generate.mockReturnValue(Promise.resolve("addyio@example.com")); + addyIo.generate.mockResolvedValue("addyio@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -287,7 +287,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const duckDuckGo = createGenerator(null, null); - duckDuckGo.generate.mockReturnValue(Promise.resolve("ddg@example.com")); + duckDuckGo.generate.mockResolvedValue("ddg@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -318,7 +318,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const fastmail = createGenerator(null, null); - fastmail.generate.mockReturnValue(Promise.resolve("fastmail@example.com")); + fastmail.generate.mockResolvedValue("fastmail@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -349,7 +349,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const firefoxRelay = createGenerator(null, null); - firefoxRelay.generate.mockReturnValue(Promise.resolve("firefoxrelay@example.com")); + firefoxRelay.generate.mockResolvedValue("firefoxrelay@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -381,7 +381,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const forwardEmail = createGenerator(null, null); - forwardEmail.generate.mockReturnValue(Promise.resolve("forwardemail@example.com")); + forwardEmail.generate.mockResolvedValue("forwardemail@example.com"); const generator = new LegacyUsernameGenerationService( null, null, @@ -414,7 +414,7 @@ describe("LegacyUsernameGenerationService", () => { website: "example.com", } as UsernameGeneratorOptions; const simpleLogin = createGenerator(null, null); - simpleLogin.generate.mockReturnValue(Promise.resolve("simplelogin@example.com")); + simpleLogin.generate.mockResolvedValue("simplelogin@example.com"); const generator = new LegacyUsernameGenerationService( null, null, diff --git a/libs/common/src/tools/generator/legacy-username-generation.service.ts b/libs/common/src/tools/generator/legacy-username-generation.service.ts index 7611a86c274..61c19ee3144 100644 --- a/libs/common/src/tools/generator/legacy-username-generation.service.ts +++ b/libs/common/src/tools/generator/legacy-username-generation.service.ts @@ -1,4 +1,4 @@ -import { zip, firstValueFrom, map, concatMap } from "rxjs"; +import { zip, firstValueFrom, map, concatMap, combineLatest } from "rxjs"; import { ApiService } from "../../abstractions/api.service"; import { PolicyService } from "../../admin-console/abstractions/policy/policy.service.abstraction"; @@ -56,7 +56,7 @@ type MappedOptions = { }; }; -export function legacyPasswordGenerationServiceFactory( +export function legacyUsernameGenerationServiceFactory( apiService: ApiService, i18nService: I18nService, cryptoService: CryptoService, @@ -205,10 +205,11 @@ export class LegacyUsernameGenerationService implements UsernameGenerationServic } } - getOptions() { + getOptions$() { + // look upon my works, ye mighty, and despair! const options$ = this.accountService.activeAccount$.pipe( concatMap((account) => - zip( + combineLatest([ this.navigation.options$(account.id), this.navigation.defaults$(account.id), this.catchall.options$(account.id), @@ -229,7 +230,7 @@ export class LegacyUsernameGenerationService implements UsernameGenerationServic this.forwardEmail.defaults$(account.id), this.simpleLogin.options$(account.id), this.simpleLogin.defaults$(account.id), - ), + ]), ), map( ([ @@ -273,30 +274,38 @@ export class LegacyUsernameGenerationService implements UsernameGenerationServic ), ); - return firstValueFrom(options$); + return options$; + } + + getOptions() { + return firstValueFrom(this.getOptions$()); } async saveOptions(options: UsernameGeneratorOptions) { const stored = this.toStoredOptions(options); - const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a.id))); + const activeAccount = await firstValueFrom(this.accountService.activeAccount$); // generator settings needs to preserve whether password or passphrase is selected, // so `navigationOptions` is mutated. - let navigationOptions = await firstValueFrom(this.navigation.options$(userId)); + const navigationOptions$ = zip( + this.navigation.options$(activeAccount.id), + this.navigation.defaults$(activeAccount.id), + ).pipe(map(([options, defaults]) => options ?? defaults)); + let navigationOptions = await firstValueFrom(navigationOptions$); navigationOptions = Object.assign(navigationOptions, stored.generator); - await this.navigation.saveOptions(userId, navigationOptions); + await this.navigation.saveOptions(activeAccount.id, navigationOptions); // overwrite all other settings with latest values await Promise.all([ - this.catchall.saveOptions(userId, stored.algorithms.catchall), - this.effUsername.saveOptions(userId, stored.algorithms.effUsername), - this.subaddress.saveOptions(userId, stored.algorithms.subaddress), - this.addyIo.saveOptions(userId, stored.forwarders.addyIo), - this.duckDuckGo.saveOptions(userId, stored.forwarders.duckDuckGo), - this.fastmail.saveOptions(userId, stored.forwarders.fastmail), - this.firefoxRelay.saveOptions(userId, stored.forwarders.firefoxRelay), - this.forwardEmail.saveOptions(userId, stored.forwarders.forwardEmail), - this.simpleLogin.saveOptions(userId, stored.forwarders.simpleLogin), + this.catchall.saveOptions(activeAccount.id, stored.algorithms.catchall), + this.effUsername.saveOptions(activeAccount.id, stored.algorithms.effUsername), + this.subaddress.saveOptions(activeAccount.id, stored.algorithms.subaddress), + this.addyIo.saveOptions(activeAccount.id, stored.forwarders.addyIo), + this.duckDuckGo.saveOptions(activeAccount.id, stored.forwarders.duckDuckGo), + this.fastmail.saveOptions(activeAccount.id, stored.forwarders.fastmail), + this.firefoxRelay.saveOptions(activeAccount.id, stored.forwarders.firefoxRelay), + this.forwardEmail.saveOptions(activeAccount.id, stored.forwarders.forwardEmail), + this.simpleLogin.saveOptions(activeAccount.id, stored.forwarders.simpleLogin), ]); } diff --git a/libs/common/src/tools/generator/navigation/default-generator-navigation.service.ts b/libs/common/src/tools/generator/navigation/default-generator-navigation.service.ts index 3199efc8c3f..e5c259d841b 100644 --- a/libs/common/src/tools/generator/navigation/default-generator-navigation.service.ts +++ b/libs/common/src/tools/generator/navigation/default-generator-navigation.service.ts @@ -6,7 +6,7 @@ import { StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { GeneratorNavigationService } from "../abstractions/generator-navigation.service.abstraction"; import { GENERATOR_SETTINGS } from "../key-definitions"; -import { reduceCollection } from "../reduce-collection.operator"; +import { distinctIfShallowMatch, reduceCollection } from "../rx-operators"; import { DefaultGeneratorNavigation, GeneratorNavigation } from "./generator-navigation"; import { GeneratorNavigationEvaluator } from "./generator-navigation-evaluator"; @@ -42,6 +42,7 @@ export class DefaultGeneratorNavigationService implements GeneratorNavigationSer evaluator$(userId: UserId) { const evaluator$ = this.policy.getAll$(PolicyType.PasswordGenerator, userId).pipe( reduceCollection(preferPassword, DisabledGeneratorNavigationPolicy), + distinctIfShallowMatch(), map((policy) => new GeneratorNavigationEvaluator(policy)), ); diff --git a/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.spec.ts b/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.spec.ts index adcfc395273..6ad1bd90dd4 100644 --- a/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.spec.ts @@ -84,15 +84,6 @@ describe("Password generation strategy", () => { }); }); - describe("cache_ms", () => { - it("should be a positive non-zero number", () => { - const legacy = mock(); - const strategy = new PassphraseGeneratorStrategy(legacy, null); - - expect(strategy.cache_ms).toBeGreaterThan(0); - }); - }); - describe("policy", () => { it("should use password generator policy", () => { const legacy = mock(); diff --git a/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.ts b/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.ts index 1a7c24082f3..c7b5ff8b787 100644 --- a/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.ts +++ b/libs/common/src/tools/generator/passphrase/passphrase-generator-strategy.ts @@ -6,7 +6,7 @@ import { StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { PasswordGenerationServiceAbstraction } from "../abstractions/password-generation.service.abstraction"; import { PASSPHRASE_SETTINGS } from "../key-definitions"; -import { reduceCollection } from "../reduce-collection.operator"; +import { distinctIfShallowMatch, reduceCollection } from "../rx-operators"; import { PassphraseGenerationOptions, @@ -19,8 +19,6 @@ import { leastPrivilege, } from "./passphrase-generator-policy"; -const ONE_MINUTE = 60 * 1000; - /** {@link GeneratorStrategy} */ export class PassphraseGeneratorStrategy implements GeneratorStrategy @@ -49,15 +47,11 @@ export class PassphraseGeneratorStrategy return PolicyType.PasswordGenerator; } - /** {@link GeneratorStrategy.cache_ms} */ - get cache_ms() { - return ONE_MINUTE; - } - /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator() { return pipe( reduceCollection(leastPrivilege, DisabledPassphraseGeneratorPolicy), + distinctIfShallowMatch(), map((policy) => new PassphraseGeneratorOptionsEvaluator(policy)), ); } diff --git a/libs/common/src/tools/generator/password/password-generation.service.ts b/libs/common/src/tools/generator/password/password-generation.service.ts index fced2dfe43f..e193b0fd33e 100644 --- a/libs/common/src/tools/generator/password/password-generation.service.ts +++ b/libs/common/src/tools/generator/password/password-generation.service.ts @@ -1,3 +1,5 @@ +import { from } from "rxjs"; + import { PolicyService } from "../../../admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "../../../admin-console/enums"; import { PasswordGeneratorPolicyOptions } from "../../../admin-console/models/domain/password-generator-policy-options"; @@ -171,6 +173,10 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr return wordList.join(o.wordSeparator); } + getOptions$() { + return from(this.getOptions()); + } + async getOptions(): Promise<[PasswordGeneratorOptions, PasswordGeneratorPolicyOptions]> { let options = await this.stateService.getPasswordGenerationOptions(); if (options == null) { @@ -336,9 +342,10 @@ export class PasswordGenerationService implements PasswordGenerationServiceAbstr return await this.stateService.setEncryptedPasswordGenerationHistory(newHistory); } - async clear(userId?: string): Promise { + async clear(userId?: string): Promise { await this.stateService.setEncryptedPasswordGenerationHistory(null, { userId: userId }); await this.stateService.setDecryptedPasswordGenerationHistory(null, { userId: userId }); + return []; } private capitalize(str: string) { diff --git a/libs/common/src/tools/generator/password/password-generator-options.ts b/libs/common/src/tools/generator/password/password-generator-options.ts index aa0a6f7dabb..04a2f8c77a6 100644 --- a/libs/common/src/tools/generator/password/password-generator-options.ts +++ b/libs/common/src/tools/generator/password/password-generator-options.ts @@ -8,4 +8,4 @@ import { PasswordGenerationOptions } from "./password-generation-options"; */ export type PasswordGeneratorOptions = PasswordGenerationOptions & PassphraseGenerationOptions & - GeneratorNavigation; + GeneratorNavigation & { policyUpdated?: boolean }; diff --git a/libs/common/src/tools/generator/password/password-generator-strategy.spec.ts b/libs/common/src/tools/generator/password/password-generator-strategy.spec.ts index 5efc6a85a74..a7509e8b43e 100644 --- a/libs/common/src/tools/generator/password/password-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/password/password-generator-strategy.spec.ts @@ -93,15 +93,6 @@ describe("Password generation strategy", () => { }); }); - describe("cache_ms", () => { - it("should be a positive non-zero number", () => { - const legacy = mock(); - const strategy = new PasswordGeneratorStrategy(legacy, null); - - expect(strategy.cache_ms).toBeGreaterThan(0); - }); - }); - describe("policy", () => { it("should use password generator policy", () => { const legacy = mock(); diff --git a/libs/common/src/tools/generator/password/password-generator-strategy.ts b/libs/common/src/tools/generator/password/password-generator-strategy.ts index e98ae6fb161..23828d7b59d 100644 --- a/libs/common/src/tools/generator/password/password-generator-strategy.ts +++ b/libs/common/src/tools/generator/password/password-generator-strategy.ts @@ -6,7 +6,7 @@ import { StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; import { PasswordGenerationServiceAbstraction } from "../abstractions/password-generation.service.abstraction"; import { PASSWORD_SETTINGS } from "../key-definitions"; -import { reduceCollection } from "../reduce-collection.operator"; +import { distinctIfShallowMatch, reduceCollection } from "../rx-operators"; import { DefaultPasswordGenerationOptions, @@ -19,8 +19,6 @@ import { leastPrivilege, } from "./password-generator-policy"; -const ONE_MINUTE = 60 * 1000; - /** {@link GeneratorStrategy} */ export class PasswordGeneratorStrategy implements GeneratorStrategy @@ -48,14 +46,11 @@ export class PasswordGeneratorStrategy return PolicyType.PasswordGenerator; } - get cache_ms() { - return ONE_MINUTE; - } - /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator() { return pipe( reduceCollection(leastPrivilege, DisabledPasswordGeneratorPolicy), + distinctIfShallowMatch(), map((policy) => new PasswordGeneratorOptionsEvaluator(policy)), ); } diff --git a/libs/common/src/tools/generator/reduce-collection.operator.spec.ts b/libs/common/src/tools/generator/reduce-collection.operator.spec.ts deleted file mode 100644 index 49648dfdf00..00000000000 --- a/libs/common/src/tools/generator/reduce-collection.operator.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -/** - * include structuredClone in test environment. - * @jest-environment ../../../../shared/test.environment.ts - */ - -import { of, firstValueFrom } from "rxjs"; - -import { reduceCollection } from "./reduce-collection.operator"; - -describe("reduceCollection", () => { - it.each([[null], [undefined], [[]]])( - "should return the default value when the collection is %p", - async (value: number[]) => { - const reduce = (acc: number, value: number) => acc + value; - const source$ = of(value); - - const result$ = source$.pipe(reduceCollection(reduce, 100)); - const result = await firstValueFrom(result$); - - expect(result).toEqual(100); - }, - ); - - it("should reduce the collection to a single value", async () => { - const reduce = (acc: number, value: number) => acc + value; - const source$ = of([1, 2, 3]); - - const result$ = source$.pipe(reduceCollection(reduce, 0)); - const result = await firstValueFrom(result$); - - expect(result).toEqual(6); - }); -}); diff --git a/libs/common/src/tools/generator/rx-operators.spec.ts b/libs/common/src/tools/generator/rx-operators.spec.ts new file mode 100644 index 00000000000..3d7dd4530f7 --- /dev/null +++ b/libs/common/src/tools/generator/rx-operators.spec.ts @@ -0,0 +1,87 @@ +/** + * include structuredClone in test environment. + * @jest-environment ../../../../shared/test.environment.ts + */ + +import { of, firstValueFrom } from "rxjs"; + +import { awaitAsync, trackEmissions } from "../../../spec"; + +import { distinctIfShallowMatch, reduceCollection } from "./rx-operators"; + +describe("reduceCollection", () => { + it.each([[null], [undefined], [[]]])( + "should return the default value when the collection is %p", + async (value: number[]) => { + const reduce = (acc: number, value: number) => acc + value; + const source$ = of(value); + + const result$ = source$.pipe(reduceCollection(reduce, 100)); + const result = await firstValueFrom(result$); + + expect(result).toEqual(100); + }, + ); + + it("should reduce the collection to a single value", async () => { + const reduce = (acc: number, value: number) => acc + value; + const source$ = of([1, 2, 3]); + + const result$ = source$.pipe(reduceCollection(reduce, 0)); + const result = await firstValueFrom(result$); + + expect(result).toEqual(6); + }); +}); + +describe("distinctIfShallowMatch", () => { + it("emits a single value", async () => { + const source$ = of({ foo: true }); + const pipe$ = source$.pipe(distinctIfShallowMatch()); + + const result = trackEmissions(pipe$); + await awaitAsync(); + + expect(result).toEqual([{ foo: true }]); + }); + + it("emits different values", async () => { + const source$ = of({ foo: true }, { foo: false }); + const pipe$ = source$.pipe(distinctIfShallowMatch()); + + const result = trackEmissions(pipe$); + await awaitAsync(); + + expect(result).toEqual([{ foo: true }, { foo: false }]); + }); + + it("emits new keys", async () => { + const source$ = of({ foo: true }, { foo: true, bar: true }); + const pipe$ = source$.pipe(distinctIfShallowMatch()); + + const result = trackEmissions(pipe$); + await awaitAsync(); + + expect(result).toEqual([{ foo: true }, { foo: true, bar: true }]); + }); + + it("suppresses identical values", async () => { + const source$ = of({ foo: true }, { foo: true }); + const pipe$ = source$.pipe(distinctIfShallowMatch()); + + const result = trackEmissions(pipe$); + await awaitAsync(); + + expect(result).toEqual([{ foo: true }]); + }); + + it("suppresses removed keys", async () => { + const source$ = of({ foo: true, bar: true }, { foo: true }); + const pipe$ = source$.pipe(distinctIfShallowMatch()); + + const result = trackEmissions(pipe$); + await awaitAsync(); + + expect(result).toEqual([{ foo: true, bar: true }]); + }); +}); diff --git a/libs/common/src/tools/generator/reduce-collection.operator.ts b/libs/common/src/tools/generator/rx-operators.ts similarity index 55% rename from libs/common/src/tools/generator/reduce-collection.operator.ts rename to libs/common/src/tools/generator/rx-operators.ts index 224595eeba2..6524ef79941 100644 --- a/libs/common/src/tools/generator/reduce-collection.operator.ts +++ b/libs/common/src/tools/generator/rx-operators.ts @@ -1,4 +1,4 @@ -import { map, OperatorFunction } from "rxjs"; +import { distinctUntilChanged, map, OperatorFunction } from "rxjs"; /** * An observable operator that reduces an emitted collection to a single object, @@ -18,3 +18,21 @@ export function reduceCollection( return reduced; }); } + +/** + * An observable operator that emits distinct values by checking that all + * values in the previous entry match the next entry. This method emits + * when a key is added and does not when a key is removed. + * @remarks This method checks objects. It does not check items in arrays. + */ +export function distinctIfShallowMatch(): OperatorFunction { + return distinctUntilChanged((previous, current) => { + let isDistinct = true; + + for (const key in current) { + isDistinct &&= previous[key] === current[key]; + } + + return isDistinct; + }); +} diff --git a/libs/common/src/tools/generator/username/catchall-generator-strategy.spec.ts b/libs/common/src/tools/generator/username/catchall-generator-strategy.spec.ts index 52cfa00aaf1..30f11b1e89b 100644 --- a/libs/common/src/tools/generator/username/catchall-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/username/catchall-generator-strategy.spec.ts @@ -59,15 +59,6 @@ describe("Email subaddress list generation strategy", () => { }); }); - describe("cache_ms", () => { - it("should be a positive non-zero number", () => { - const legacy = mock(); - const strategy = new CatchallGeneratorStrategy(legacy, null); - - expect(strategy.cache_ms).toBeGreaterThan(0); - }); - }); - describe("policy", () => { it("should use password generator policy", () => { const legacy = mock(); diff --git a/libs/common/src/tools/generator/username/catchall-generator-strategy.ts b/libs/common/src/tools/generator/username/catchall-generator-strategy.ts index 5111b06e90c..ee86fd9fd66 100644 --- a/libs/common/src/tools/generator/username/catchall-generator-strategy.ts +++ b/libs/common/src/tools/generator/username/catchall-generator-strategy.ts @@ -11,8 +11,6 @@ import { NoPolicy } from "../no-policy"; import { CatchallGenerationOptions, DefaultCatchallOptions } from "./catchall-generator-options"; -const ONE_MINUTE = 60 * 1000; - /** Strategy for creating usernames using a catchall email address */ export class CatchallGeneratorStrategy implements GeneratorStrategy @@ -42,11 +40,6 @@ export class CatchallGeneratorStrategy return PolicyType.PasswordGenerator; } - /** {@link GeneratorStrategy.cache_ms} */ - get cache_ms() { - return ONE_MINUTE; - } - /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator() { return pipe(map((_) => new DefaultPolicyEvaluator())); diff --git a/libs/common/src/tools/generator/username/eff-username-generator-strategy.spec.ts b/libs/common/src/tools/generator/username/eff-username-generator-strategy.spec.ts index 9b0e4cc0694..76e51f609cc 100644 --- a/libs/common/src/tools/generator/username/eff-username-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/username/eff-username-generator-strategy.spec.ts @@ -59,15 +59,6 @@ describe("EFF long word list generation strategy", () => { }); }); - describe("cache_ms", () => { - it("should be a positive non-zero number", () => { - const legacy = mock(); - const strategy = new EffUsernameGeneratorStrategy(legacy, null); - - expect(strategy.cache_ms).toBeGreaterThan(0); - }); - }); - describe("policy", () => { it("should use password generator policy", () => { const legacy = mock(); diff --git a/libs/common/src/tools/generator/username/eff-username-generator-strategy.ts b/libs/common/src/tools/generator/username/eff-username-generator-strategy.ts index 1a4efdcb44b..70d1f854205 100644 --- a/libs/common/src/tools/generator/username/eff-username-generator-strategy.ts +++ b/libs/common/src/tools/generator/username/eff-username-generator-strategy.ts @@ -14,8 +14,6 @@ import { EffUsernameGenerationOptions, } from "./eff-username-generator-options"; -const ONE_MINUTE = 60 * 1000; - /** Strategy for creating usernames from the EFF wordlist */ export class EffUsernameGeneratorStrategy implements GeneratorStrategy @@ -45,11 +43,6 @@ export class EffUsernameGeneratorStrategy return PolicyType.PasswordGenerator; } - /** {@link GeneratorStrategy.cache_ms} */ - get cache_ms() { - return ONE_MINUTE; - } - /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator() { return pipe(map((_) => new DefaultPolicyEvaluator())); diff --git a/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts b/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts index c2a606eae0a..d3bec745f14 100644 --- a/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/username/forwarder-generator-strategy.spec.ts @@ -10,9 +10,10 @@ import { CryptoService } from "../../../platform/abstractions/crypto.service"; import { EncryptService } from "../../../platform/abstractions/encrypt.service"; import { StateProvider } from "../../../platform/state"; import { UserId } from "../../../types/guid"; +import { UserKey } from "../../../types/key"; import { DefaultPolicyEvaluator } from "../default-policy-evaluator"; -import { DUCK_DUCK_GO_FORWARDER } from "../key-definitions"; -import { SecretState } from "../state/secret-state"; +import { DUCK_DUCK_GO_FORWARDER, DUCK_DUCK_GO_BUFFER } from "../key-definitions"; +import { BufferedState } from "../state/buffered-state"; import { ForwarderGeneratorStrategy } from "./forwarder-generator-strategy"; import { DefaultDuckDuckGoOptions } from "./forwarders/duck-duck-go"; @@ -32,6 +33,10 @@ class TestForwarder extends ForwarderGeneratorStrategy { return DUCK_DUCK_GO_FORWARDER; } + get rolloverKey() { + return DUCK_DUCK_GO_BUFFER; + } + defaults$ = (userId: UserId) => { return of(DefaultDuckDuckGoOptions); }; @@ -51,13 +56,22 @@ describe("ForwarderGeneratorStrategy", () => { const keyService = mock(); const stateProvider = new FakeStateProvider(mockAccountServiceWith(SomeUser)); + beforeEach(() => { + const keyAvailable = of({} as UserKey); + keyService.getInMemoryUserKeyFor$.mockReturnValue(keyAvailable); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + describe("durableState", () => { it("constructs a secret state", () => { const strategy = new TestForwarder(encryptService, keyService, stateProvider); const result = strategy.durableState(SomeUser); - expect(result).toBeInstanceOf(SecretState); + expect(result).toBeInstanceOf(BufferedState); }); it("returns the same secret state for a single user", () => { diff --git a/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts b/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts index b4205b9fc98..1abefcc23c4 100644 --- a/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts +++ b/libs/common/src/tools/generator/username/forwarder-generator-strategy.ts @@ -8,6 +8,8 @@ import { UserId } from "../../../types/guid"; import { GeneratorStrategy } from "../abstractions"; import { DefaultPolicyEvaluator } from "../default-policy-evaluator"; import { NoPolicy } from "../no-policy"; +import { BufferedKeyDefinition } from "../state/buffered-key-definition"; +import { BufferedState } from "../state/buffered-state"; import { PaddedDataPacker } from "../state/padded-data-packer"; import { SecretClassifier } from "../state/secret-classifier"; import { SecretKeyDefinition } from "../state/secret-key-definition"; @@ -16,7 +18,6 @@ import { UserKeyEncryptor } from "../state/user-key-encryptor"; import { ApiOptions } from "./options/forwarder-options"; -const ONE_MINUTE = 60 * 1000; const OPTIONS_FRAME_SIZE = 512; /** An email forwarding service configurable through an API. */ @@ -37,8 +38,6 @@ export abstract class ForwarderGeneratorStrategy< // Uses password generator since there aren't policies // specific to usernames. this.policy = PolicyType.PasswordGenerator; - - this.cache_ms = ONE_MINUTE; } private durableStates = new Map>(); @@ -48,25 +47,7 @@ export abstract class ForwarderGeneratorStrategy< let state = this.durableStates.get(userId); if (!state) { - const encryptor = this.createEncryptor(); - // always exclude request properties - const classifier = SecretClassifier.allSecret().exclude("website"); - - // Derive the secret key definition - const key = SecretKeyDefinition.value(this.key.stateDefinition, this.key.key, classifier, { - deserializer: (d) => this.key.deserializer(d), - cleanupDelayMs: this.key.cleanupDelayMs, - clearOn: this.key.clearOn, - }); - - // the type parameter is explicit because type inference fails for `Omit` - state = SecretState.from< - Options, - void, - Options, - Record, - Omit - >(userId, key, this.stateProvider, encryptor); + state = this.createState(userId); this.durableStates.set(userId, state); } @@ -74,10 +55,42 @@ export abstract class ForwarderGeneratorStrategy< return state; }; - private createEncryptor() { + private createState(userId: UserId): SingleUserState { // construct the encryptor const packer = new PaddedDataPacker(OPTIONS_FRAME_SIZE); - return new UserKeyEncryptor(this.encryptService, this.keyService, packer); + const encryptor = new UserKeyEncryptor(this.encryptService, this.keyService, packer); + + // always exclude request properties + const classifier = SecretClassifier.allSecret().exclude("website"); + + // Derive the secret key definition + const key = SecretKeyDefinition.value(this.key.stateDefinition, this.key.key, classifier, { + deserializer: (d) => this.key.deserializer(d), + cleanupDelayMs: this.key.cleanupDelayMs, + clearOn: this.key.clearOn, + }); + + // the type parameter is explicit because type inference fails for `Omit` + const secretState = SecretState.from< + Options, + void, + Options, + Record, + Omit + >(userId, key, this.stateProvider, encryptor); + + // rollover should occur once the user key is available for decryption + const canDecrypt$ = this.keyService + .getInMemoryUserKeyFor$(userId) + .pipe(map((key) => key !== null)); + const rolloverState = new BufferedState( + this.stateProvider, + this.rolloverKey, + secretState, + canDecrypt$, + ); + + return rolloverState; } /** Gets the default options. */ @@ -86,6 +99,9 @@ export abstract class ForwarderGeneratorStrategy< /** Determine where forwarder configuration is stored */ protected abstract readonly key: UserKeyDefinition; + /** Determine where forwarder rollover configuration is stored */ + protected abstract readonly rolloverKey: BufferedKeyDefinition; + /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator = () => { return pipe(map((_) => new DefaultPolicyEvaluator())); diff --git a/libs/common/src/tools/generator/username/forwarders/addy-io.ts b/libs/common/src/tools/generator/username/forwarders/addy-io.ts index 3e4960f7e76..12121749519 100644 --- a/libs/common/src/tools/generator/username/forwarders/addy-io.ts +++ b/libs/common/src/tools/generator/username/forwarders/addy-io.ts @@ -6,7 +6,7 @@ import { EncryptService } from "../../../../platform/abstractions/encrypt.servic import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { ADDY_IO_FORWARDER } from "../../key-definitions"; +import { ADDY_IO_FORWARDER, ADDY_IO_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { EmailDomainOptions, SelfHostedApiOptions } from "../options/forwarder-options"; @@ -44,6 +44,11 @@ export class AddyIoForwarder extends ForwarderGeneratorStrategy< return ADDY_IO_FORWARDER; } + /** {@link ForwarderGeneratorStrategy.rolloverKey} */ + get rolloverKey() { + return ADDY_IO_BUFFER; + } + /** {@link ForwarderGeneratorStrategy.defaults$} */ defaults$ = (userId: UserId) => { return new BehaviorSubject({ ...DefaultAddyIoOptions }); diff --git a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts index 9b5d93d742e..4a9040d74a9 100644 --- a/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts +++ b/libs/common/src/tools/generator/username/forwarders/duck-duck-go.ts @@ -6,7 +6,7 @@ import { EncryptService } from "../../../../platform/abstractions/encrypt.servic import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { DUCK_DUCK_GO_FORWARDER } from "../../key-definitions"; +import { DUCK_DUCK_GO_FORWARDER, DUCK_DUCK_GO_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { ApiOptions } from "../options/forwarder-options"; @@ -40,6 +40,11 @@ export class DuckDuckGoForwarder extends ForwarderGeneratorStrategy return DUCK_DUCK_GO_FORWARDER; } + /** {@link ForwarderGeneratorStrategy.rolloverKey} */ + get rolloverKey() { + return DUCK_DUCK_GO_BUFFER; + } + /** {@link ForwarderGeneratorStrategy.defaults$} */ defaults$ = (userId: UserId) => { return new BehaviorSubject({ ...DefaultDuckDuckGoOptions }); diff --git a/libs/common/src/tools/generator/username/forwarders/fastmail.ts b/libs/common/src/tools/generator/username/forwarders/fastmail.ts index 9d62cd0039d..e6ab28b59e3 100644 --- a/libs/common/src/tools/generator/username/forwarders/fastmail.ts +++ b/libs/common/src/tools/generator/username/forwarders/fastmail.ts @@ -6,7 +6,7 @@ import { EncryptService } from "../../../../platform/abstractions/encrypt.servic import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { FASTMAIL_FORWARDER } from "../../key-definitions"; +import { FASTMAIL_FORWARDER, FASTMAIL_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { EmailPrefixOptions, ApiOptions } from "../options/forwarder-options"; @@ -47,6 +47,11 @@ export class FastmailForwarder extends ForwarderGeneratorStrategy { if (!options.token || options.token === "") { diff --git a/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts b/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts index a4122c53f8f..c381d3d3f2e 100644 --- a/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts +++ b/libs/common/src/tools/generator/username/forwarders/firefox-relay.ts @@ -6,7 +6,7 @@ import { EncryptService } from "../../../../platform/abstractions/encrypt.servic import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { FIREFOX_RELAY_FORWARDER } from "../../key-definitions"; +import { FIREFOX_RELAY_FORWARDER, FIREFOX_RELAY_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { ApiOptions } from "../options/forwarder-options"; @@ -40,6 +40,11 @@ export class FirefoxRelayForwarder extends ForwarderGeneratorStrategy { return new BehaviorSubject({ ...DefaultFirefoxRelayOptions }); diff --git a/libs/common/src/tools/generator/username/forwarders/forward-email.ts b/libs/common/src/tools/generator/username/forwarders/forward-email.ts index 93f4680414a..af654d3917e 100644 --- a/libs/common/src/tools/generator/username/forwarders/forward-email.ts +++ b/libs/common/src/tools/generator/username/forwarders/forward-email.ts @@ -7,7 +7,7 @@ import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { Utils } from "../../../../platform/misc/utils"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { FORWARD_EMAIL_FORWARDER } from "../../key-definitions"; +import { FORWARD_EMAIL_FORWARDER, FORWARD_EMAIL_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { EmailDomainOptions, ApiOptions } from "../options/forwarder-options"; @@ -49,6 +49,11 @@ export class ForwardEmailForwarder extends ForwarderGeneratorStrategy< return new BehaviorSubject({ ...DefaultForwardEmailOptions }); }; + /** {@link ForwarderGeneratorStrategy.rolloverKey} */ + get rolloverKey() { + return FORWARD_EMAIL_BUFFER; + } + /** {@link ForwarderGeneratorStrategy.generate} */ generate = async (options: ApiOptions & EmailDomainOptions) => { if (!options.token || options.token === "") { diff --git a/libs/common/src/tools/generator/username/forwarders/simple-login.ts b/libs/common/src/tools/generator/username/forwarders/simple-login.ts index d047fc42d14..ee91a411451 100644 --- a/libs/common/src/tools/generator/username/forwarders/simple-login.ts +++ b/libs/common/src/tools/generator/username/forwarders/simple-login.ts @@ -6,7 +6,7 @@ import { EncryptService } from "../../../../platform/abstractions/encrypt.servic import { I18nService } from "../../../../platform/abstractions/i18n.service"; import { StateProvider } from "../../../../platform/state"; import { UserId } from "../../../../types/guid"; -import { SIMPLE_LOGIN_FORWARDER } from "../../key-definitions"; +import { SIMPLE_LOGIN_FORWARDER, SIMPLE_LOGIN_BUFFER } from "../../key-definitions"; import { ForwarderGeneratorStrategy } from "../forwarder-generator-strategy"; import { Forwarders } from "../options/constants"; import { SelfHostedApiOptions } from "../options/forwarder-options"; @@ -41,6 +41,11 @@ export class SimpleLoginForwarder extends ForwarderGeneratorStrategy { return new BehaviorSubject({ ...DefaultSimpleLoginOptions }); diff --git a/libs/common/src/tools/generator/username/subaddress-generator-strategy.spec.ts b/libs/common/src/tools/generator/username/subaddress-generator-strategy.spec.ts index 827bc7aed0d..b5ac9c4cf9c 100644 --- a/libs/common/src/tools/generator/username/subaddress-generator-strategy.spec.ts +++ b/libs/common/src/tools/generator/username/subaddress-generator-strategy.spec.ts @@ -62,15 +62,6 @@ describe("Email subaddress list generation strategy", () => { }); }); - describe("cache_ms", () => { - it("should be a positive non-zero number", () => { - const legacy = mock(); - const strategy = new SubaddressGeneratorStrategy(legacy, null); - - expect(strategy.cache_ms).toBeGreaterThan(0); - }); - }); - describe("policy", () => { it("should use password generator policy", () => { const legacy = mock(); diff --git a/libs/common/src/tools/generator/username/subaddress-generator-strategy.ts b/libs/common/src/tools/generator/username/subaddress-generator-strategy.ts index 818741f8a9b..6106d6d476f 100644 --- a/libs/common/src/tools/generator/username/subaddress-generator-strategy.ts +++ b/libs/common/src/tools/generator/username/subaddress-generator-strategy.ts @@ -14,8 +14,6 @@ import { SubaddressGenerationOptions, } from "./subaddress-generator-options"; -const ONE_MINUTE = 60 * 1000; - /** Strategy for creating an email subaddress * @remarks The subaddress is the part following the `+`. * For example, if the email address is `jd+xyz@domain.io`, @@ -49,11 +47,6 @@ export class SubaddressGeneratorStrategy return PolicyType.PasswordGenerator; } - /** {@link GeneratorStrategy.cache_ms} */ - get cache_ms() { - return ONE_MINUTE; - } - /** {@link GeneratorStrategy.toEvaluator} */ toEvaluator() { return pipe(map((_) => new DefaultPolicyEvaluator())); diff --git a/libs/common/src/tools/generator/username/username-generation.service.ts b/libs/common/src/tools/generator/username/username-generation.service.ts index 1ee642da5eb..e659aacb51f 100644 --- a/libs/common/src/tools/generator/username/username-generation.service.ts +++ b/libs/common/src/tools/generator/username/username-generation.service.ts @@ -1,3 +1,5 @@ +import { from } from "rxjs"; + import { ApiService } from "../../../abstractions/api.service"; import { CryptoService } from "../../../platform/abstractions/crypto.service"; import { StateService } from "../../../platform/abstractions/state.service"; @@ -158,6 +160,10 @@ export class UsernameGenerationService implements UsernameGenerationServiceAbstr return forwarder.generate(this.apiService, forwarderOptions); } + getOptions$() { + return from(this.getOptions()); + } + async getOptions(): Promise { let options = await this.stateService.getUsernameGenerationOptions(); if (options == null) { diff --git a/libs/common/src/vault/abstractions/cipher.service.ts b/libs/common/src/vault/abstractions/cipher.service.ts index 22e2c54a59a..d559b18f06a 100644 --- a/libs/common/src/vault/abstractions/cipher.service.ts +++ b/libs/common/src/vault/abstractions/cipher.service.ts @@ -132,11 +132,7 @@ export abstract class CipherService { cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[], ) => Promise; restoreWithServer: (id: string, asAdmin?: boolean) => Promise; - restoreManyWithServer: ( - ids: string[], - organizationId?: string, - asAdmin?: boolean, - ) => Promise; + restoreManyWithServer: (ids: string[], orgId?: string) => Promise; getKeyForCipherKeyDecryption: (cipher: Cipher) => Promise; setAddEditCipherInfo: (value: AddEditCipherInfo) => Promise; } diff --git a/libs/common/src/vault/models/response/optional-cipher.response.ts b/libs/common/src/vault/models/response/optional-cipher.response.ts new file mode 100644 index 00000000000..08181407b24 --- /dev/null +++ b/libs/common/src/vault/models/response/optional-cipher.response.ts @@ -0,0 +1,14 @@ +import { BaseResponse } from "../../../models/response/base.response"; + +import { CipherResponse } from "./cipher.response"; + +export class OptionalCipherResponse extends BaseResponse { + unavailable: boolean; + cipher?: CipherResponse; + + constructor(response: any) { + super(response); + this.unavailable = this.getResponseProperty("Unavailable"); + this.cipher = new CipherResponse(this.getResponseProperty("Cipher")); + } +} diff --git a/libs/common/src/vault/models/view/cipher.view.ts b/libs/common/src/vault/models/view/cipher.view.ts index 911a78f565b..028b582db26 100644 --- a/libs/common/src/vault/models/view/cipher.view.ts +++ b/libs/common/src/vault/models/view/cipher.view.ts @@ -126,6 +126,12 @@ export class CipherView implements View, InitializerMetadata { return this.item?.linkedFieldOptions; } + get isUnassigned(): boolean { + return ( + this.organizationId != null && (this.collectionIds == null || this.collectionIds.length === 0) + ); + } + linkedFieldValue(id: LinkedIdType) { const linkedFieldOption = this.linkedFieldOptions?.get(id); if (linkedFieldOption == null) { diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 537245459eb..c03b440ff58 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -776,9 +776,14 @@ export class CipherService implements CipherServiceAbstraction { async saveCollectionsWithServer(cipher: Cipher): Promise { const request = new CipherCollectionsRequest(cipher.collectionIds); const response = await this.apiService.putCipherCollections(cipher.id, request); - const data = new CipherData(response); + // The response will now check for an unavailable value. This value determines whether + // the user still has Can Manage access to the item after updating. + if (response.unavailable) { + await this.delete(cipher.id); + return; + } + const data = new CipherData(response.cipher); const updated = await this.upsert(data); - // Collection updates don't change local data return new Cipher(updated[cipher.id as CipherId], cipher.localData); } @@ -1117,14 +1122,15 @@ export class CipherService implements CipherServiceAbstraction { await this.restore({ id: id, revisionDate: response.revisionDate }); } - async restoreManyWithServer( - ids: string[], - organizationId: string = null, - asAdmin = false, - ): Promise { + /** + * No longer using an asAdmin Param. Org Vault bulkRestore will assess if an item is unassigned or editable + * The Org Vault will pass those ids an array as well as the orgId when calling bulkRestore + */ + async restoreManyWithServer(ids: string[], orgId: string = null): Promise { let response; - if (asAdmin) { - const request = new CipherBulkRestoreRequest(ids, organizationId); + + if (orgId) { + const request = new CipherBulkRestoreRequest(ids, orgId); response = await this.apiService.putRestoreManyCiphersAdmin(request); } else { const request = new CipherBulkRestoreRequest(ids); diff --git a/libs/importer/src/components/import.component.html b/libs/importer/src/components/import.component.html index 836a1d9a1a1..eda999ab47e 100644 --- a/libs/importer/src/components/import.component.html +++ b/libs/importer/src/components/import.component.html @@ -2,7 +2,7 @@ {{ "personalOwnershipPolicyInEffectImports" | i18n }}
- + {{ "importDestination" | i18n }} (); private _importBlockedByPolicy = false; - private _isFromAC = false; + protected isFromAC = false; formGroup = this.formBuilder.group({ vaultSelector: [ @@ -232,7 +232,7 @@ export class ImportComponent implements OnInit, OnDestroy { .then((collections) => collections.sort(Utils.getSortFunction(this.i18nService, "name"))), ); - this._isFromAC = true; + this.isFromAC = true; } private handleImportInit() { @@ -359,7 +359,7 @@ export class ImportComponent implements OnInit, OnDestroy { importContents, this.organizationId, this.formGroup.controls.targetSelector.value, - (await this.canAccessImportExport(this.organizationId)) && this._isFromAC, + (await this.canAccessImportExport(this.organizationId)) && this.isFromAC, ); //No errors, display success message diff --git a/libs/importer/src/importers/lastpass/access/services/parser.ts b/libs/importer/src/importers/lastpass/access/services/parser.ts index abf55172c80..83d56832290 100644 --- a/libs/importer/src/importers/lastpass/access/services/parser.ts +++ b/libs/importer/src/importers/lastpass/access/services/parser.ts @@ -32,213 +32,220 @@ export class Parser { folder: SharedFolder, options: ParserOptions, ): Promise { - const placeholder = "decryption failed"; - const reader = new BinaryReader(chunk.payload); + let id: string; + try { + const placeholder = "decryption failed"; + const reader = new BinaryReader(chunk.payload); - // Read all items - // 0: id - const id = Utils.fromBufferToUtf8(this.readItem(reader)); + // Read all items + // 0: id + id = Utils.fromBufferToUtf8(this.readItem(reader)); - // 1: name - const name = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); + // 1: name + const name = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); - // 2: group - const group = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); + // 2: group + const group = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); - // 3: url - let url = Utils.fromBufferToUtf8( - this.decodeHexLoose(Utils.fromBufferToUtf8(this.readItem(reader))), - ); + // 3: url + let url = Utils.fromBufferToUtf8( + this.decodeHexLoose(Utils.fromBufferToUtf8(this.readItem(reader))), + ); - // Ignore "group" accounts. They have no credentials. - if (url == "http://group") { - return null; - } - - // 4: extra (notes) - const notes = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); - - // 5: fav (is favorite) - const isFavorite = Utils.fromBufferToUtf8(this.readItem(reader)) === "1"; - - // 6: sharedfromaid (?) - this.skipItem(reader); - - // 7: username - let username = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); - - // 8: password - let password = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); - - // 9: pwprotect (?) - this.skipItem(reader); - - // 10: genpw (?) - this.skipItem(reader); - - // 11: sn (is secure note) - const isSecureNote = Utils.fromBufferToUtf8(this.readItem(reader)) === "1"; - - // Parse secure note - if (options.parseSecureNotesToAccount && isSecureNote) { - let type = ""; - // ParseSecureNoteServer - for (const i of notes.split("\n")) { - const keyValue = i.split(":", 2); - if (keyValue.length < 2) { - continue; - } - switch (keyValue[0]) { - case "NoteType": - type = keyValue[1]; - break; - case "Hostname": - url = keyValue[1]; - break; - case "Username": - username = keyValue[1]; - break; - case "Password": - password = keyValue[1]; - break; - } - } - - // Only the some secure notes contain account-like information - if (!AllowedSecureNoteTypes.has(type)) { + // Ignore "group" accounts. They have no credentials. + if (url == "http://group") { return null; } + + // 4: extra (notes) + const notes = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); + + // 5: fav (is favorite) + const isFavorite = Utils.fromBufferToUtf8(this.readItem(reader)) === "1"; + + // 6: sharedfromaid (?) + this.skipItem(reader); + + // 7: username + let username = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); + + // 8: password + let password = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); + + // 9: pwprotect (?) + this.skipItem(reader); + + // 10: genpw (?) + this.skipItem(reader); + + // 11: sn (is secure note) + const isSecureNote = Utils.fromBufferToUtf8(this.readItem(reader)) === "1"; + + // Parse secure note + if (options.parseSecureNotesToAccount && isSecureNote) { + let type = ""; + // ParseSecureNoteServer + for (const i of notes.split("\n")) { + const keyValue = i.split(":", 2); + if (keyValue.length < 2) { + continue; + } + switch (keyValue[0]) { + case "NoteType": + type = keyValue[1]; + break; + case "Hostname": + url = keyValue[1]; + break; + case "Username": + username = keyValue[1]; + break; + case "Password": + password = keyValue[1]; + break; + } + } + + // Only the some secure notes contain account-like information + if (!AllowedSecureNoteTypes.has(type)) { + return null; + } + } + + // 12: last_touch_gmt (?) + this.skipItem(reader); + + // 13: autologin (?) + this.skipItem(reader); + + // 14: never_autofill (?) + this.skipItem(reader); + + // 15: realm (?) + this.skipItem(reader); + + // 16: id_again (?) + this.skipItem(reader); + + // 17: custom_js (?) + this.skipItem(reader); + + // 18: submit_id (?) + this.skipItem(reader); + + // 19: captcha_id (?) + this.skipItem(reader); + + // 20: urid (?) + this.skipItem(reader); + + // 21: basic_auth (?) + this.skipItem(reader); + + // 22: method (?) + this.skipItem(reader); + + // 23: action (?) + this.skipItem(reader); + + // 24: groupid (?) + this.skipItem(reader); + + // 25: deleted (?) + this.skipItem(reader); + + // 26: attachkey (?) + this.skipItem(reader); + + // 27: attachpresent (?) + this.skipItem(reader); + + // 28: individualshare (?) + this.skipItem(reader); + + // 29: notetype (?) + this.skipItem(reader); + + // 30: noalert (?) + this.skipItem(reader); + + // 31: last_modified_gmt (?) + this.skipItem(reader); + + // 32: hasbeenshared (?) + this.skipItem(reader); + + // 33: last_pwchange_gmt (?) + this.skipItem(reader); + + // 34: created_gmt (?) + this.skipItem(reader); + + // 35: vulnerable (?) + this.skipItem(reader); + + // 36: pwch (?) + this.skipItem(reader); + + // 37: breached (?) + this.skipItem(reader); + + // 38: template (?) + this.skipItem(reader); + + // 39: totp (?) + const totp = await this.cryptoUtils.decryptAes256PlainWithDefault( + this.readItem(reader), + encryptionKey, + placeholder, + ); + + // 3 more left. Don't even bother skipping them. + + // 40: trustedHostnames (?) + // 41: last_credential_monitoring_gmt (?) + // 42: last_credential_monitoring_stat (?) + + // Adjust the path to include the group and the shared folder, if any. + const path = this.makeAccountPath(group, folder); + + const account = new Account(); + account.id = id; + account.name = name; + account.username = username; + account.password = password; + account.url = url; + account.path = path; + account.notes = notes; + account.totp = totp; + account.isFavorite = isFavorite; + account.isShared = folder != null; + return account; + } catch (err) { + throw new Error( + "Error parsing accounts on item with ID:" + id + " errorMessage: " + err.message, + ); } - - // 12: last_touch_gmt (?) - this.skipItem(reader); - - // 13: autologin (?) - this.skipItem(reader); - - // 14: never_autofill (?) - this.skipItem(reader); - - // 15: realm (?) - this.skipItem(reader); - - // 16: id_again (?) - this.skipItem(reader); - - // 17: custom_js (?) - this.skipItem(reader); - - // 18: submit_id (?) - this.skipItem(reader); - - // 19: captcha_id (?) - this.skipItem(reader); - - // 20: urid (?) - this.skipItem(reader); - - // 21: basic_auth (?) - this.skipItem(reader); - - // 22: method (?) - this.skipItem(reader); - - // 23: action (?) - this.skipItem(reader); - - // 24: groupid (?) - this.skipItem(reader); - - // 25: deleted (?) - this.skipItem(reader); - - // 26: attachkey (?) - this.skipItem(reader); - - // 27: attachpresent (?) - this.skipItem(reader); - - // 28: individualshare (?) - this.skipItem(reader); - - // 29: notetype (?) - this.skipItem(reader); - - // 30: noalert (?) - this.skipItem(reader); - - // 31: last_modified_gmt (?) - this.skipItem(reader); - - // 32: hasbeenshared (?) - this.skipItem(reader); - - // 33: last_pwchange_gmt (?) - this.skipItem(reader); - - // 34: created_gmt (?) - this.skipItem(reader); - - // 35: vulnerable (?) - this.skipItem(reader); - - // 36: pwch (?) - this.skipItem(reader); - - // 37: breached (?) - this.skipItem(reader); - - // 38: template (?) - this.skipItem(reader); - - // 39: totp (?) - const totp = await this.cryptoUtils.decryptAes256PlainWithDefault( - this.readItem(reader), - encryptionKey, - placeholder, - ); - - // 3 more left. Don't even bother skipping them. - - // 40: trustedHostnames (?) - // 41: last_credential_monitoring_gmt (?) - // 42: last_credential_monitoring_stat (?) - - // Adjust the path to include the group and the shared folder, if any. - const path = this.makeAccountPath(group, folder); - - const account = new Account(); - account.id = id; - account.name = name; - account.username = username; - account.password = password; - account.url = url; - account.path = path; - account.notes = notes; - account.totp = totp; - account.isFavorite = isFavorite; - account.isShared = folder != null; - return account; } async parseShar( @@ -246,30 +253,37 @@ export class Parser { encryptionKey: Uint8Array, rsaKey: Uint8Array, ): Promise { - const reader = new BinaryReader(chunk.payload); + let id: string; + try { + const reader = new BinaryReader(chunk.payload); - // Id - const id = Utils.fromBufferToUtf8(this.readItem(reader)); + // Id + id = Utils.fromBufferToUtf8(this.readItem(reader)); - // Key - const folderKey = this.readItem(reader); - const rsaEncryptedFolderKey = Utils.fromHexToArray(Utils.fromBufferToUtf8(folderKey)); - const decFolderKey = await this.cryptoFunctionService.rsaDecrypt( - rsaEncryptedFolderKey, - rsaKey, - "sha1", - ); - const key = Utils.fromHexToArray(Utils.fromBufferToUtf8(decFolderKey)); + // Key + const folderKey = this.readItem(reader); + const rsaEncryptedFolderKey = Utils.fromHexToArray(Utils.fromBufferToUtf8(folderKey)); + const decFolderKey = await this.cryptoFunctionService.rsaDecrypt( + rsaEncryptedFolderKey, + rsaKey, + "sha1", + ); + const key = Utils.fromHexToArray(Utils.fromBufferToUtf8(decFolderKey)); - // Name - const encryptedName = this.readItem(reader); - const name = await this.cryptoUtils.decryptAes256Base64(encryptedName, key); + // Name + const encryptedName = this.readItem(reader); + const name = await this.cryptoUtils.decryptAes256Base64(encryptedName, key); - const folder = new SharedFolder(); - folder.id = id; - folder.name = name; - folder.encryptionKey = key; - return folder; + const folder = new SharedFolder(); + folder.id = id; + folder.name = name; + folder.encryptionKey = key; + return folder; + } catch (err) { + throw new Error( + "Error parsing shared folder with ID:" + id + " errorMessage: " + err.message, + ); + } } async parseEncryptedPrivateKey(encryptedPrivateKey: string, encryptionKey: Uint8Array) { diff --git a/libs/tools/export/vault-export/vault-export-ui/package.json b/libs/tools/export/vault-export/vault-export-ui/package.json index e27140f3657..3be54c4e191 100644 --- a/libs/tools/export/vault-export/vault-export-ui/package.json +++ b/libs/tools/export/vault-export/vault-export-ui/package.json @@ -20,6 +20,7 @@ "dependencies": { "@bitwarden/common": "file:../../../../common", "@bitwarden/angular": "file:../../../../angular", + "@bitwarden/auth": "file:../../../../auth", "@bitwarden/vault-export-core": "file:../vault-export-core" } } diff --git a/libs/tools/export/vault-export/vault-export-ui/src/components/export-scope-callout.component.ts b/libs/tools/export/vault-export/vault-export-ui/src/components/export-scope-callout.component.ts index 0f246c3a341..2cf93f72ae1 100644 --- a/libs/tools/export/vault-export/vault-export-ui/src/components/export-scope-callout.component.ts +++ b/libs/tools/export/vault-export/vault-export-ui/src/components/export-scope-callout.component.ts @@ -1,9 +1,10 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnInit } from "@angular/core"; +import { firstValueFrom, map } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; -import { StateService } from "@bitwarden/common/platform/abstractions/state.service"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { CalloutModule } from "@bitwarden/components"; @Component({ @@ -35,7 +36,7 @@ export class ExportScopeCalloutComponent implements OnInit { constructor( protected organizationService: OrganizationService, - protected stateService: StateService, + protected accountService: AccountService, ) {} async ngOnInit(): Promise { @@ -58,7 +59,9 @@ export class ExportScopeCalloutComponent implements OnInit { : { title: "exportingPersonalVaultTitle", description: "exportingIndividualVaultDescription", - scopeIdentifier: await this.stateService.getEmail(), + scopeIdentifier: await firstValueFrom( + this.accountService.activeAccount$.pipe(map((a) => a?.email)), + ), }; } } diff --git a/libs/tools/export/vault-export/vault-export-ui/src/components/export.component.ts b/libs/tools/export/vault-export/vault-export-ui/src/components/export.component.ts index ce478db19a7..3e091a2417a 100644 --- a/libs/tools/export/vault-export/vault-export-ui/src/components/export.component.ts +++ b/libs/tools/export/vault-export/vault-export-ui/src/components/export.component.ts @@ -3,12 +3,12 @@ import { UntypedFormBuilder, Validators } from "@angular/forms"; import { map, merge, Observable, startWith, Subject, takeUntil } from "rxjs"; import { PasswordStrengthComponent } from "@bitwarden/angular/tools/password-strength/password-strength.component"; +import { UserVerificationDialogComponent } from "@bitwarden/auth/angular"; import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { EventType } from "@bitwarden/common/enums"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -67,7 +67,6 @@ export class ExportComponent implements OnInit, OnDestroy { protected eventCollectionService: EventCollectionService, private policyService: PolicyService, private logService: LogService, - private userVerificationService: UserVerificationService, private formBuilder: UntypedFormBuilder, protected fileDownloadService: FileDownloadService, protected dialogService: DialogService, @@ -154,7 +153,21 @@ export class ExportComponent implements OnInit, OnDestroy { } } - async submit() { + submit = async () => { + if (this.isFileEncryptedExport && this.filePassword != this.confirmFilePassword) { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("filePasswordAndConfirmFilePasswordDoNotMatch"), + ); + return; + } + + this.exportForm.markAllAsTouched(); + if (this.exportForm.invalid) { + return; + } + if (this.disabledByPolicy) { this.platformUtilsService.showToast( "error", @@ -164,49 +177,52 @@ export class ExportComponent implements OnInit, OnDestroy { return; } - const acceptedWarning = await this.warningDialog(); - if (!acceptedWarning) { - return; - } - const secret = this.exportForm.get("secret").value; - - try { - await this.userVerificationService.verifyUser(secret); - } catch (e) { - this.platformUtilsService.showToast("error", this.i18nService.t("errorOccurred"), e.message); + const userVerified = await this.verifyUser(); + if (!userVerified) { return; } - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this.doExport(); - } - - async warningDialog() { - if (this.encryptedFormat) { - return await this.dialogService.openSimpleDialog({ - title: { key: "confirmVaultExport" }, - content: - this.i18nService.t("encExportKeyWarningDesc") + - " " + - this.i18nService.t("encExportAccountWarningDesc"), - acceptButtonText: { key: "exportVault" }, - type: "warning", - }); - } else { - return await this.dialogService.openSimpleDialog({ - title: { key: "confirmVaultExport" }, - content: { key: "exportWarningDesc" }, - acceptButtonText: { key: "exportVault" }, - type: "warning", - }); - } - } + await this.doExport(); + }; protected saved() { this.onSaved.emit(); } + private async verifyUser(): Promise { + let confirmDescription = "exportWarningDesc"; + if (this.isFileEncryptedExport) { + confirmDescription = "fileEncryptedExportWarningDesc"; + } else if (this.isAccountEncryptedExport) { + confirmDescription = "encExportKeyWarningDesc"; + } + + const result = await UserVerificationDialogComponent.open(this.dialogService, { + title: "confirmVaultExport", + bodyText: confirmDescription, + confirmButtonOptions: { + text: "exportVault", + type: "primary", + }, + }); + + // Handle the result of the dialog based on user action and verification success + if (result.userAction === "cancel") { + // User cancelled the dialog + return false; + } + + // User confirmed the dialog so check verification success + if (!result.verificationSuccess) { + if (result.noAvailableClientVerificationMethods) { + // No client-side verification methods are available + // Could send user to configure a verification method like PIN or biometrics + } + return false; + } + return true; + } + protected async getExportData(): Promise { return Utils.isNullOrWhitespace(this.organizationId) ? this.exportService.getExport(this.format, this.filePassword) diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json index 19d35b28969..7d4aee3fb36 100644 --- a/tsconfig.eslint.json +++ b/tsconfig.eslint.json @@ -27,7 +27,8 @@ "@bitwarden/importer/ui": ["./libs/importer/src/components"], "@bitwarden/platform": ["./libs/platform/src"], "@bitwarden/node/*": ["./libs/node/src/*"], - "@bitwarden/vault": ["./libs/vault/src"] + "@bitwarden/vault": ["./libs/vault/src"], + "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"] }, "plugins": [ { diff --git a/tsconfig.json b/tsconfig.json index 60dc9d223e3..0a519a5b7e4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -29,7 +29,8 @@ "@bitwarden/platform": ["./libs/platform/src"], "@bitwarden/node/*": ["./libs/node/src/*"], "@bitwarden/web-vault/*": ["./apps/web/src/*"], - "@bitwarden/vault": ["./libs/vault/src"] + "@bitwarden/vault": ["./libs/vault/src"], + "@bitwarden/bit-common/*": ["./bitwarden_license/bit-common/src/*"] }, "plugins": [ { @@ -42,7 +43,8 @@ "apps/web/src/**/*", "apps/browser/src/**/*", "libs/*/src/**/*", - "bitwarden_license/bit-web/src/**/*" + "bitwarden_license/bit-web/src/**/*", + "bitwarden_license/bit-common/src/**/*" ], "exclude": [ "apps/web/src/**/*.spec.ts",