diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 9502a9c404d..7d7fec2a5ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -134,9 +134,12 @@ libs/common/src/autofill @bitwarden/team-autofill-dev apps/desktop/macos/autofill-extension @bitwarden/team-autofill-dev apps/desktop/src/app/components/fido2placeholder.component.ts @bitwarden/team-autofill-dev apps/desktop/desktop_native/windows_plugin_authenticator @bitwarden/team-autofill-dev +apps/desktop/desktop_native/autotype @bitwarden/team-autofill-dev # DuckDuckGo integration apps/desktop/native-messaging-test-runner @bitwarden/team-autofill-dev apps/desktop/src/services/duckduckgo-message-handler.service.ts @bitwarden/team-autofill-dev +apps/desktop/src/services/encrypted-message-handler.service.ts @bitwarden/team-autofill-dev +.github/workflows/alert-ddg-files-modified.yml @bitwarden/team-autofill-dev # SSH Agent apps/desktop/desktop_native/core/src/ssh_agent @bitwarden/team-autofill-dev @bitwarden/wg-ssh-keys diff --git a/.github/workflows/alert-ddg-files-modified.yml b/.github/workflows/alert-ddg-files-modified.yml new file mode 100644 index 00000000000..61bb7f1e8af --- /dev/null +++ b/.github/workflows/alert-ddg-files-modified.yml @@ -0,0 +1,50 @@ +name: DDG File Change Monitor + +on: + pull_request: + branches: [ main ] + types: [ opened, synchronize ] + +jobs: + check-files: + name: Check files + runs-on: ubuntu-22.04 + permissions: + contents: read + pull-requests: write + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Get changed files + id: changed-files + uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + with: + list-files: shell + filters: | + monitored: + - 'apps/desktop/native-messaging-test-runner/**' + - 'apps/desktop/src/services/duckduckgo-message-handler.service.ts' + - 'apps/desktop/src/services/encrypted-message-handler.service.ts' + + - name: Comment on PR if monitored files changed + if: steps.changed-files.outputs.monitored == 'true' + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const changedFiles = `${{ steps.changed-files.outputs.monitored_files }}`.split(' ').filter(file => file.trim() !== ''); + + const message = `⚠️🦆 **DuckDuckGo Integration files have been modified in this PR:** + + ${changedFiles.map(file => `- \`${file}\``).join('\n')} + + Please run the DuckDuckGo native messaging test runner from this branch using [these instructions](https://contributing.bitwarden.com/getting-started/clients/desktop/native-messaging-test-runner) and ensure it functions properly.`; + + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: message + }); diff --git a/.github/workflows/build-browser-target.yml b/.github/workflows/build-browser-target.yml index a2ae48d419b..ef3beef4b8b 100644 --- a/.github/workflows/build-browser-target.yml +++ b/.github/workflows/build-browser-target.yml @@ -28,6 +28,8 @@ jobs: check-run: name: Check PR run uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + permissions: + contents: read run-workflow: name: Build Browser @@ -35,4 +37,7 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} uses: ./.github/workflows/build-browser.yml secrets: inherit + permissions: + contents: read + id-token: write diff --git a/.github/workflows/build-browser.yml b/.github/workflows/build-browser.yml index 40b03d9e753..bd7d70e8543 100644 --- a/.github/workflows/build-browser.yml +++ b/.github/workflows/build-browser.yml @@ -41,7 +41,8 @@ defaults: run: shell: bash -permissions: {} +permissions: + contents: read jobs: setup: @@ -77,10 +78,8 @@ jobs: - name: Check secrets id: check-secrets - env: - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} run: | - has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} + has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }} echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT @@ -302,6 +301,9 @@ jobs: build-safari: name: Build Safari runs-on: macos-13 + permissions: + contents: read + id-token: write needs: - setup - locales-test @@ -327,10 +329,19 @@ jobs: node --version npm --version - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD" - name: Download Provisioning Profiles secrets env: @@ -366,9 +377,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -440,6 +454,10 @@ jobs: name: Crowdin Push if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' runs-on: ubuntu-22.04 + permissions: + contents: write + pull-requests: write + id-token: write needs: - build - build-safari @@ -449,10 +467,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -461,6 +481,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "crowdin-api-token" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Upload Sources uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1 env: @@ -478,6 +501,9 @@ jobs: name: Check for failures if: always() runs-on: ubuntu-22.04 + permissions: + contents: read + id-token: write needs: - setup - locales-test @@ -493,11 +519,13 @@ jobs: && contains(needs.*.result, 'failure') run: exit 1 - - name: Login to Azure - Prod Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure if: failure() + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -507,6 +535,10 @@ jobs: keyvault: "bitwarden-ci" secrets: "devops-alerts-slack-webhook-url" + - name: Log out from Azure + if: failure() + uses: bitwarden/gh-actions/azure-logout@main + - name: Notify Slack on failure uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0 if: failure() diff --git a/.github/workflows/build-cli-target.yml b/.github/workflows/build-cli-target.yml index 6b493d4e6d9..54865ddaddd 100644 --- a/.github/workflows/build-cli-target.yml +++ b/.github/workflows/build-cli-target.yml @@ -28,6 +28,8 @@ jobs: check-run: name: Check PR run uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + permissions: + contents: read run-workflow: name: Build CLI @@ -35,4 +37,7 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} uses: ./.github/workflows/build-cli.yml secrets: inherit + permissions: + contents: read + id-token: write diff --git a/.github/workflows/build-cli.yml b/.github/workflows/build-cli.yml index ac314a4c33a..b31b22b926e 100644 --- a/.github/workflows/build-cli.yml +++ b/.github/workflows/build-cli.yml @@ -78,10 +78,8 @@ jobs: - name: Check secrets id: check-secrets - env: - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} run: | - has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} + has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }} echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT @@ -108,6 +106,10 @@ jobs: _NODE_VERSION: ${{ needs.setup.outputs.node_version }} _WIN_PKG_FETCH_VERSION: 20.11.1 _WIN_PKG_VERSION: 3.5 + permissions: + contents: read + id-token: write + steps: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -156,9 +158,11 @@ jobs: - name: Login to Azure if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Get certificates if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} @@ -168,10 +172,21 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert | jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12 + - name: Get Azure Key Vault secrets + id: get-kv-secrets + if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -199,13 +214,13 @@ jobs: run: | mkdir ~/private_keys cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8 - ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }} + ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }} EOF - name: Notarize app if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }} env: - APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }} + APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }} APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8 run: | @@ -261,6 +276,9 @@ jobs: { build_prefix: "bit", artifact_prefix: "", readable: "commercial license" } ] runs-on: windows-2022 + permissions: + contents: read + id-token: write needs: setup env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} @@ -344,11 +362,13 @@ jobs: ResourceHacker -open version-info.rc -save version-info.res -action compile ResourceHacker -open %WIN_PKG_BUILT% -save %WIN_PKG_BUILT% -action addoverwrite -resource version-info.res - - name: Login to Azure + - name: Log in to Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -362,6 +382,10 @@ jobs: code-signing-client-secret, code-signing-cert-name" + - name: Log out from Azure + if: ${{ needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/azure-logout@main + - name: Install run: npm ci working-directory: ./ @@ -520,6 +544,9 @@ jobs: name: Check for failures if: always() runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write needs: - setup - cli @@ -534,11 +561,13 @@ jobs: && contains(needs.*.result, 'failure') run: exit 1 - - name: Login to Azure - Prod Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure if: failure() + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -548,6 +577,10 @@ jobs: keyvault: "bitwarden-ci" secrets: "devops-alerts-slack-webhook-url" + - name: Log out from Azure + if: failure() + uses: bitwarden/gh-actions/azure-logout@main + - name: Notify Slack on failure uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0 if: failure() diff --git a/.github/workflows/build-desktop-target.yml b/.github/workflows/build-desktop-target.yml index fa21b3fe5d9..31ac819a3e6 100644 --- a/.github/workflows/build-desktop-target.yml +++ b/.github/workflows/build-desktop-target.yml @@ -28,6 +28,8 @@ jobs: check-run: name: Check PR run uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + permissions: + contents: read run-workflow: name: Build Desktop @@ -35,4 +37,7 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} uses: ./.github/workflows/build-desktop.yml secrets: inherit + permissions: + contents: read + id-token: write diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index a022fe7fd0f..366d439fb45 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -147,10 +147,8 @@ jobs: - name: Check secrets id: check-secrets - env: - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} run: | - has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} + has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }} echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT linux: @@ -404,6 +402,9 @@ jobs: runs-on: windows-2022 needs: - setup + permissions: + contents: read + id-token: write defaults: run: shell: pwsh @@ -438,11 +439,13 @@ jobs: choco --version rustup show - - name: Login to Azure + - name: Log in to Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -456,6 +459,10 @@ jobs: code-signing-client-secret, code-signing-cert-name" + - name: Log out from Azure + if: ${{ needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/azure-logout@main + - name: Install Node dependencies run: npm ci working-directory: ./ @@ -655,6 +662,9 @@ jobs: runs-on: macos-13 needs: - setup + permissions: + contents: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -700,11 +710,21 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension - - name: Login to Azure + - name: Log in to Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + if: ${{ needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD" - name: Download Provisioning Profiles secrets if: ${{ needs.setup.outputs.has_secrets == 'true' }} @@ -747,10 +767,14 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + if: ${{ needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain if: ${{ needs.setup.outputs.has_secrets == 'true' }} env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -850,6 +874,10 @@ jobs: if: ${{ needs.setup.outputs.has_secrets == 'true' }} uses: ./.github/workflows/build-browser.yml secrets: inherit + permissions: + contents: write + pull-requests: write + id-token: write macos-package-github: @@ -860,6 +888,9 @@ jobs: - browser-build - macos-build - setup + permissions: + contents: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -905,10 +936,19 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER" - name: Download Provisioning Profiles secrets env: @@ -949,9 +989,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -1055,12 +1098,12 @@ jobs: run: | mkdir ~/private_keys cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8 - ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }} + ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }} EOF - name: Build application (dist) env: - APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }} + APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }} APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8 CSC_FOR_PULL_REQUEST: true @@ -1103,6 +1146,9 @@ jobs: - browser-build - macos-build - setup + permissions: + contents: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.package_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -1148,10 +1194,19 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD,APP-STORE-CONNECT-AUTH-KEY,APP-STORE-CONNECT-TEAM-ISSUER" - name: Retrieve Slack secret id: retrieve-slack-secret @@ -1199,9 +1254,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -1305,12 +1363,12 @@ jobs: run: | mkdir ~/private_keys cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8 - ${{ secrets.APP_STORE_CONNECT_AUTH_KEY }} + ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }} EOF - name: Build application for App Store env: - APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }} + APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }} APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8 CSC_FOR_PULL_REQUEST: true @@ -1334,7 +1392,7 @@ jobs: cat << EOF > ~/secrets/appstoreconnect-fastlane.json { - "issuer_id": "${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }}", + "issuer_id": "${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}", "key_id": "6TV9MKN3GP", "key": "$KEY_WITHOUT_NEWLINES" } @@ -1346,7 +1404,7 @@ jobs: github.event_name != 'pull_request_target' && (inputs.testflight_distribute || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-desktop') env: - APP_STORE_CONNECT_TEAM_ISSUER: ${{ secrets.APP_STORE_CONNECT_TEAM_ISSUER }} + APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }} APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP BRANCH: ${{ github.ref }} run: | @@ -1396,6 +1454,10 @@ jobs: - windows - macos-package-github - macos-package-mas + permissions: + contents: write + pull-requests: write + id-token: write runs-on: ubuntu-22.04 steps: - name: Check out repo @@ -1403,10 +1465,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -1415,6 +1479,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "crowdin-api-token" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Upload Sources uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1 env: @@ -1442,6 +1509,9 @@ jobs: - macos-package-github - macos-package-mas - crowdin-push + permissions: + contents: read + id-token: write steps: - name: Check if any job failed if: | @@ -1450,11 +1520,13 @@ jobs: && contains(needs.*.result, 'failure') run: exit 1 - - name: Login to Azure - Prod Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure if: failure() + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -1464,6 +1536,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "devops-alerts-slack-webhook-url" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Notify Slack on failure uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0 if: failure() @@ -1471,3 +1546,4 @@ jobs: SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }} with: status: ${{ job.status }} + diff --git a/.github/workflows/build-web-target.yml b/.github/workflows/build-web-target.yml index ca10e6d46f2..b1055885400 100644 --- a/.github/workflows/build-web-target.yml +++ b/.github/workflows/build-web-target.yml @@ -27,6 +27,8 @@ jobs: check-run: name: Check PR run uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + permissions: + contents: read run-workflow: name: Build Web @@ -34,4 +36,8 @@ jobs: if: ${{ github.event.pull_request.head.repo.full_name != github.repository }} uses: ./.github/workflows/build-web.yml secrets: inherit + permissions: + contents: read + id-token: write + security-events: write diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 745376b46d8..b4163d161cf 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -51,7 +51,8 @@ env: _AZ_REGISTRY: bitwardenprod.azurecr.io _GITHUB_PR_REPO_NAME: ${{ github.event.pull_request.head.repo.full_name }} -permissions: {} +permissions: + contents: read jobs: setup: @@ -80,10 +81,8 @@ jobs: - name: Check secrets id: check-secrets - env: - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} run: | - has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} + has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }} echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT @@ -204,11 +203,13 @@ jobs: uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 ########## ACRs ########## - - name: Login to Prod Azure + - name: Log in to Azure if: ${{ needs.setup.outputs.has_secrets == 'true' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Log into Prod container registry if: ${{ needs.setup.outputs.has_secrets == 'true' }} @@ -328,11 +329,19 @@ jobs: - name: Log out of Docker run: docker logout $_AZ_REGISTRY + - name: Log out from Azure + if: ${{ needs.setup.outputs.has_secrets == 'true' }} + uses: bitwarden/gh-actions/azure-logout@main + crowdin-push: name: Crowdin Push if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' needs: build-containers + permissions: + contents: write + pull-requests: write + id-token: write runs-on: ubuntu-24.04 steps: - name: Check out repo @@ -340,10 +349,12 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -352,6 +363,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "crowdin-api-token" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Upload Sources uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1 env: @@ -370,11 +384,15 @@ jobs: if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' runs-on: ubuntu-24.04 needs: build-containers + permissions: + id-token: write steps: - - name: Login to Azure - CI Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve github PAT secrets id: retrieve-secret-pat @@ -383,6 +401,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "github-pat-bitwarden-devops-bot-repo-scope" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Trigger web vault deploy using GitHub Run ID uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: @@ -409,6 +430,8 @@ jobs: - build-containers - crowdin-push - trigger-web-vault-deploy + permissions: + id-token: write steps: - name: Check if any job failed if: | @@ -417,11 +440,13 @@ jobs: && contains(needs.*.result, 'failure') run: exit 1 - - name: Login to Azure - Prod Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main if: failure() with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -431,6 +456,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "devops-alerts-slack-webhook-url" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Notify Slack on failure uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0 if: failure() diff --git a/.github/workflows/chromatic.yml b/.github/workflows/chromatic.yml index 78733bc5a8b..4ee39305f84 100644 --- a/.github/workflows/chromatic.yml +++ b/.github/workflows/chromatic.yml @@ -15,6 +15,8 @@ jobs: check-run: name: Check PR run uses: bitwarden/gh-actions/.github/workflows/check-run.yml@main + permissions: + contents: read chromatic: name: Chromatic @@ -23,6 +25,7 @@ jobs: permissions: contents: read pull-requests: write + id-token: write steps: - name: Check out repo @@ -30,13 +33,13 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 - + - name: Get changed files id: get-changed-files-for-chromatic uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 with: filters: | - storyFiles: + storyFiles: - "apps/!(cli)/**" - "bitwarden_license/bit-web/src/app/**" - "libs/!(eslint)/**" @@ -74,11 +77,28 @@ jobs: if: steps.get-changed-files-for-chromatic.outputs.storyFiles == 'true' run: npm run build-storybook:ci + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "CHROMATIC-PROJECT-TOKEN" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Publish to Chromatic uses: chromaui/action@e8cc4c31775280b175a3c440076c00d19a9014d7 # v11.28.2 with: token: ${{ secrets.GITHUB_TOKEN }} - projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} + projectToken: ${{ steps.get-kv-secrets.outputs.CHROMATIC-PROJECT-TOKEN }} storybookBuildDir: ./storybook-static exitOnceUploaded: true onlyChanged: true diff --git a/.github/workflows/crowdin-pull.yml b/.github/workflows/crowdin-pull.yml index 2fc035ec038..0b891203855 100644 --- a/.github/workflows/crowdin-pull.yml +++ b/.github/workflows/crowdin-pull.yml @@ -10,6 +10,9 @@ jobs: crowdin-sync: name: Autosync runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write strategy: fail-fast: false matrix: @@ -21,22 +24,19 @@ jobs: - app_name: web crowdin_project_id: "308189" steps: - - name: Generate GH App token - uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 - id: app-token + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - app-id: ${{ secrets.BW_GHAPP_ID }} - private-key: ${{ secrets.BW_GHAPP_KEY }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - - name: Checkout repo - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main with: - token: ${{ steps.app-token.outputs.token }} - - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 - with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + keyvault: gh-org-bitwarden + secrets: "BW-GHAPP-ID,BW-GHAPP-KEY" - name: Retrieve secrets id: retrieve-secrets @@ -45,6 +45,21 @@ jobs: keyvault: "bitwarden-ci" secrets: "crowdin-api-token, github-gpg-private-key, github-gpg-private-key-passphrase" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + + - name: Generate GH App token + uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 + id: app-token + with: + app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} + private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} + + - name: Checkout repo + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + token: ${{ steps.app-token.outputs.token }} + - name: Download translations uses: bitwarden/gh-actions/crowdin@main env: diff --git a/.github/workflows/deploy-web.yml b/.github/workflows/deploy-web.yml index 1cde8dd636a..e21f7ae1e79 100644 --- a/.github/workflows/deploy-web.yml +++ b/.github/workflows/deploy-web.yml @@ -66,8 +66,9 @@ jobs: environment_url: ${{ steps.config.outputs.environment_url }} environment_name: ${{ steps.config.outputs.environment_name }} environment_artifact: ${{ steps.config.outputs.environment_artifact }} - azure_login_creds: ${{ steps.config.outputs.azure_login_creds }} - retrive_secrets_keyvault: ${{ steps.config.outputs.retrive_secrets_keyvault }} + azure_login_client_key_name: ${{ steps.config.outputs.azure_login_client_key_name }} + azure_login_subscription_id_key_name: ${{ steps.config.outputs.azure_login_subscription_id_key_name }} + retrieve_secrets_keyvault: ${{ steps.config.outputs.retrieve_secrets_keyvault }} sync_utility: ${{ steps.config.outputs.sync_utility }} sync_delete_destination_files: ${{ steps.config.outputs.sync_delete_destination_files }} slack_channel_name: ${{ steps.config.outputs.slack_channel_name }} @@ -81,40 +82,45 @@ jobs: case ${{ inputs.environment }} in "USQA") - echo "azure_login_creds=AZURE_KV_US_QA_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT - echo "retrive_secrets_keyvault=bw-webvault-rlktusqa-kv" >> $GITHUB_OUTPUT + echo "azure_login_client_key_name=AZURE_CLIENT_ID_USQA" >> $GITHUB_OUTPUT + echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USQA" >> $GITHUB_OUTPUT + echo "retrieve_secrets_keyvault=bw-webvault-rlktusqa-kv" >> $GITHUB_OUTPUT echo "environment_artifact=web-*-cloud-QA.zip" >> $GITHUB_OUTPUT echo "environment_name=Web Vault - US QA Cloud" >> $GITHUB_OUTPUT echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT echo "slack_channel_name=alerts-deploy-qa" >> $GITHUB_OUTPUT ;; "EUQA") - echo "azure_login_creds=AZURE_KV_EU_QA_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT - echo "retrive_secrets_keyvault=webvaulteu-westeurope-qa" >> $GITHUB_OUTPUT + echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUQA" >> $GITHUB_OUTPUT + echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUQA" >> $GITHUB_OUTPUT + echo "retrieve_secrets_keyvault=webvaulteu-westeurope-qa" >> $GITHUB_OUTPUT echo "environment_artifact=web-*-cloud-euqa.zip" >> $GITHUB_OUTPUT echo "environment_name=Web Vault - EU QA Cloud" >> $GITHUB_OUTPUT echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT echo "slack_channel_name=alerts-deploy-qa" >> $GITHUB_OUTPUT ;; "USPROD") - echo "azure_login_creds=AZURE_KV_US_PROD_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT - echo "retrive_secrets_keyvault=bw-webvault-klrt-kv" >> $GITHUB_OUTPUT + echo "azure_login_client_key_name=AZURE_CLIENT_ID_USPROD" >> $GITHUB_OUTPUT + echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USPROD" >> $GITHUB_OUTPUT + echo "retrieve_secrets_keyvault=bw-webvault-klrt-kv" >> $GITHUB_OUTPUT echo "environment_artifact=web-*-cloud-COMMERCIAL.zip" >> $GITHUB_OUTPUT echo "environment_name=Web Vault - US Production Cloud" >> $GITHUB_OUTPUT echo "environment_url=http://vault.bitwarden.com" >> $GITHUB_OUTPUT echo "slack_channel_name=alerts-deploy-prd" >> $GITHUB_OUTPUT ;; "EUPROD") - echo "azure_login_creds=AZURE_KV_EU_PRD_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT - echo "retrive_secrets_keyvault=webvault-westeurope-prod" >> $GITHUB_OUTPUT + echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUPROD" >> $GITHUB_OUTPUT + echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUPROD" >> $GITHUB_OUTPUT + echo "retrieve_secrets_keyvault=webvault-westeurope-prod" >> $GITHUB_OUTPUT echo "environment_artifact=web-*-cloud-euprd.zip" >> $GITHUB_OUTPUT echo "environment_name=Web Vault - EU Production Cloud" >> $GITHUB_OUTPUT echo "environment_url=http://vault.bitwarden.eu" >> $GITHUB_OUTPUT echo "slack_channel_name=alerts-deploy-prd" >> $GITHUB_OUTPUT ;; "USDEV") - echo "azure_login_creds=AZURE_KV_US_DEV_SERVICE_PRINCIPAL" >> $GITHUB_OUTPUT - echo "retrive_secrets_keyvault=webvault-eastus-dev" >> $GITHUB_OUTPUT + echo "azure_login_client_key_name=AZURE_CLIENT_ID_USDEV" >> $GITHUB_OUTPUT + echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USDEV" >> $GITHUB_OUTPUT + echo "retrieve_secrets_keyvault=webvault-eastus-dev" >> $GITHUB_OUTPUT echo "environment_artifact=web-*-cloud-usdev.zip" >> $GITHUB_OUTPUT echo "environment_name=Web Vault - US Development Cloud" >> $GITHUB_OUTPUT echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT @@ -180,6 +186,9 @@ jobs: name: Check if Web artifact is present runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read + id-token: write env: _ENVIRONMENT_ARTIFACT: ${{ needs.setup.outputs.environment_artifact }} outputs: @@ -209,11 +218,13 @@ jobs: branch: ${{ inputs.branch-or-tag }} artifacts: ${{ env._ENVIRONMENT_ARTIFACT }} - - name: Login to Azure + - name: Log in to Azure if: ${{ steps.download-latest-artifacts.outcome == 'failure' }} - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets for Build trigger if: ${{ steps.download-latest-artifacts.outcome == 'failure' }} @@ -223,6 +234,10 @@ jobs: keyvault: "bitwarden-ci" secrets: "github-pat-bitwarden-devops-bot-repo-scope" + - name: Log out from Azure + if: ${{ steps.download-latest-artifacts.outcome == 'failure' }} + uses: bitwarden/gh-actions/azure-logout@main + - name: 'Trigger build web for missing branch/tag ${{ inputs.branch-or-tag }}' if: ${{ steps.download-latest-artifacts.outcome == 'failure' }} uses: convictional/trigger-workflow-and-wait@f69fa9eedd3c62a599220f4d5745230e237904be # v1.6.5 @@ -262,6 +277,8 @@ jobs: - artifact-check runs-on: ubuntu-22.04 if: ${{ always() && ( contains( inputs.environment , 'QA' ) || contains( inputs.environment , 'DEV' ) ) }} + permissions: + id-token: write outputs: channel_id: ${{ steps.slack-message.outputs.channel_id }} ts: ${{ steps.slack-message.outputs.ts }} @@ -277,7 +294,9 @@ jobs: event: 'start' commit-sha: ${{ needs.artifact-check.outputs.artifact_build_commit }} url: https://github.com/bitwarden/clients/actions/runs/${{ github.run_id }} - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} update-summary: name: Display commit @@ -302,6 +321,9 @@ jobs: _ENVIRONMENT_URL: ${{ needs.setup.outputs.environment_url }} _ENVIRONMENT_NAME: ${{ needs.setup.outputs.environment_name }} _ENVIRONMENT_ARTIFACT: ${{ needs.setup.outputs.environment_artifact }} + permissions: + id-token: write + deployments: write steps: - name: Create GitHub deployment uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7 @@ -309,23 +331,25 @@ jobs: with: token: '${{ secrets.GITHUB_TOKEN }}' initial-status: 'in_progress' - environment_url: ${{ env._ENVIRONMENT_URL }} + environment-url: ${{ env._ENVIRONMENT_URL }} environment: ${{ env._ENVIRONMENT_NAME }} task: 'deploy' description: 'Deployment from branch/tag: ${{ inputs.branch-or-tag }}' ref: ${{ needs.artifact-check.outputs.artifact_build_commit }} - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets[needs.setup.outputs.azure_login_creds] }} + subscription_id: ${{ secrets[needs.setup.outputs.azure_login_subscription_id_key_name] }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets[needs.setup.outputs.azure_login_client_key_name] }} - name: Retrieve Storage Account connection string for az sync if: ${{ needs.setup.outputs.sync_utility == 'az-sync' }} id: retrieve-secrets-az-sync uses: bitwarden/gh-actions/get-keyvault-secrets@main with: - keyvault: ${{ needs.setup.outputs.retrive_secrets_keyvault }} + keyvault: ${{ needs.setup.outputs.retrieve_secrets_keyvault }} secrets: "sa-bitwarden-web-vault-dev-key-temp" - name: Retrieve Storage Account name and SPN credentials for azcopy @@ -333,9 +357,12 @@ jobs: id: retrieve-secrets-azcopy uses: bitwarden/gh-actions/get-keyvault-secrets@main with: - keyvault: ${{ needs.setup.outputs.retrive_secrets_keyvault }} + keyvault: ${{ needs.setup.outputs.retrieve_secrets_keyvault }} secrets: "sa-bitwarden-web-vault-name,sp-bitwarden-web-vault-password,sp-bitwarden-web-vault-appid,sp-bitwarden-web-vault-tenant" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: 'Download latest cloud asset using GitHub Run ID: ${{ inputs.build-web-run-id }}' if: ${{ inputs.build-web-run-id }} uses: bitwarden/gh-actions/download-artifacts@main @@ -397,7 +424,7 @@ jobs: uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' - environment_url: ${{ env._ENVIRONMENT_URL }} + environment-url: ${{ env._ENVIRONMENT_URL }} state: 'success' deployment-id: ${{ steps.deployment.outputs.deployment_id }} @@ -406,7 +433,7 @@ jobs: uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 with: token: '${{ secrets.GITHUB_TOKEN }}' - environment_url: ${{ env._ENVIRONMENT_URL }} + environment-url: ${{ env._ENVIRONMENT_URL }} state: 'failure' deployment-id: ${{ steps.deployment.outputs.deployment_id }} @@ -419,6 +446,8 @@ jobs: - notify-start - azure-deploy - artifact-check + permissions: + id-token: write steps: - name: Notify Slack with result uses: bitwarden/gh-actions/report-deployment-status-to-slack@main @@ -431,4 +460,6 @@ jobs: url: https://github.com/bitwarden/clients/actions/runs/${{ github.run_id }} commit-sha: ${{ needs.artifact-check.outputs.artifact_build_commit }} update-ts: ${{ needs.notify-start.outputs.ts }} - AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} diff --git a/.github/workflows/lint-crowdin-config.yml b/.github/workflows/lint-crowdin-config.yml index adb5950e3a0..38a3ef59ea7 100644 --- a/.github/workflows/lint-crowdin-config.yml +++ b/.github/workflows/lint-crowdin-config.yml @@ -5,12 +5,14 @@ on: types: [opened, synchronize] paths: - '**/crowdin.yml' -permissions: {} jobs: lint-crowdin-config: name: Lint Crowdin Config ${{ matrix.app.name }} runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write strategy: matrix: app: [ @@ -22,17 +24,25 @@ jobs: - name: Check out repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: - fetch-depth: 1 - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + fetch-depth: 1 + + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + - name: Retrieve secrets id: retrieve-secrets uses: bitwarden/gh-actions/get-keyvault-secrets@main with: keyvault: "bitwarden-ci" secrets: "crowdin-api-token" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Lint ${{ matrix.app.name }} config uses: crowdin/github-action@f214c8723025f41fc55b2ad26e67b60b80b1885d # v2.7.1 env: @@ -42,4 +52,4 @@ jobs: with: dryrun_action: true command: 'config lint' - command_args: '--verbose -c ${{ matrix.app.config_path }}' \ No newline at end of file + command_args: '--verbose -c ${{ matrix.app.config_path }}' diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml index d758e6f11c9..efb0f541d70 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish-cli.yml @@ -48,6 +48,10 @@ jobs: defaults: run: working-directory: . + permissions: + contents: read + deployments: write + steps: - name: Branch check if: ${{ inputs.publish_type != 'Dry Run' }} @@ -86,6 +90,10 @@ jobs: name: Deploy Snap runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read + packages: read + id-token: write if: inputs.snap_publish env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} @@ -93,10 +101,12 @@ jobs: - name: Checkout repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -105,6 +115,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "snapcraft-store-token" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Install Snap uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1 @@ -123,6 +136,10 @@ jobs: name: Deploy Choco runs-on: windows-2022 needs: setup + permissions: + contents: read + packages: read + id-token: write if: inputs.choco_publish env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} @@ -130,10 +147,12 @@ jobs: - name: Checkout repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -142,6 +161,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "cli-choco-api-key" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Setup Chocolatey run: choco apikey --key $env:CHOCO_API_KEY --source https://push.chocolatey.org/ env: @@ -163,6 +185,10 @@ jobs: name: Publish NPM runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read + packages: read + id-token: write if: inputs.npm_publish env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} @@ -170,10 +196,12 @@ jobs: - name: Checkout repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -182,6 +210,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "npm-api-key" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Download and set up artifact run: | mkdir -p build @@ -210,6 +241,10 @@ jobs: - npm - snap - choco + permissions: + contents: read + deployments: write + if: ${{ always() && inputs.publish_type != 'Dry Run' }} steps: - name: Check if any job failed diff --git a/.github/workflows/publish-desktop.yml b/.github/workflows/publish-desktop.yml index ae631165db9..aafc4d25ed4 100644 --- a/.github/workflows/publish-desktop.yml +++ b/.github/workflows/publish-desktop.yml @@ -42,6 +42,9 @@ jobs: release_channel: ${{ steps.release_channel.outputs.channel }} tag_name: ${{ steps.version.outputs.tag_name }} deployment_id: ${{ steps.deployment.outputs.deployment_id }} + permissions: + contents: read + deployments: write steps: - name: Branch check if: ${{ inputs.publish_type != 'Dry Run' }} @@ -106,14 +109,21 @@ jobs: name: Electron blob publish runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read + packages: read + id-token: write + deployments: write env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} _RELEASE_TAG: ${{ needs.setup.outputs.tag_name }} steps: - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -124,6 +134,9 @@ jobs: aws-electron-access-key, aws-electron-bucket-name" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Create artifacts directory run: mkdir -p apps/desktop/artifacts @@ -176,6 +189,9 @@ jobs: name: Deploy Snap runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read + id-token: write if: inputs.snap_publish env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} @@ -184,10 +200,12 @@ jobs: - name: Checkout Repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -196,6 +214,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "snapcraft-store-token" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Install Snap uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1 @@ -220,6 +241,9 @@ jobs: name: Deploy Choco runs-on: windows-2022 needs: setup + permissions: + contents: read + id-token: write if: inputs.choco_publish env: _PKG_VERSION: ${{ needs.setup.outputs.release_version }} @@ -233,10 +257,12 @@ jobs: dotnet --version dotnet nuget --version - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -245,6 +271,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "cli-choco-api-key" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Setup Chocolatey run: choco apikey --key $env:CHOCO_API_KEY --source https://push.chocolatey.org/ env: @@ -271,6 +300,9 @@ jobs: - electron-blob - snap - choco + permissions: + contents: read + deployments: write if: ${{ always() && inputs.publish_type != 'Dry Run' }} steps: - name: Check if any job failed diff --git a/.github/workflows/publish-web.yml b/.github/workflows/publish-web.yml index 69b29086d36..a6f0f1be066 100644 --- a/.github/workflows/publish-web.yml +++ b/.github/workflows/publish-web.yml @@ -24,6 +24,8 @@ jobs: outputs: release_version: ${{ steps.version.outputs.version }} tag_version: ${{ steps.version.outputs.tag }} + permissions: + contents: read steps: - name: Checkout repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -52,6 +54,10 @@ jobs: name: Release self-host docker runs-on: ubuntu-22.04 needs: setup + permissions: + id-token: write + contents: read + deployments: write env: _BRANCH_NAME: ${{ github.ref_name }} _RELEASE_VERSION: ${{ needs.setup.outputs.release_version }} @@ -69,10 +75,12 @@ jobs: uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 ########## ACR ########## - - name: Login to Azure - PROD Subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Login to Azure ACR run: az acr login -n bitwardenprod @@ -121,6 +129,9 @@ jobs: docker push $_AZ_REGISTRY/web-sh:latest fi + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Update deployment status to Success if: ${{ inputs.publish_type != 'Dry Run' && success() }} uses: chrnorm/deployment-status@9a72af4586197112e0491ea843682b5dc280d806 # v2.0.3 @@ -147,11 +158,15 @@ jobs: runs-on: ubuntu-22.04 needs: - setup + permissions: + id-token: write steps: - - name: Log in to Azure - CI subscription - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve GitHub PAT secrets id: retrieve-secret-pat @@ -160,6 +175,9 @@ jobs: keyvault: "bitwarden-ci" secrets: "github-pat-bitwarden-devops-bot-repo-scope" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Trigger self-host build uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: diff --git a/.github/workflows/release-desktop-beta.yml b/.github/workflows/release-desktop-beta.yml index a5e374395d8..e3eb9090cb7 100644 --- a/.github/workflows/release-desktop-beta.yml +++ b/.github/workflows/release-desktop-beta.yml @@ -15,6 +15,8 @@ jobs: setup: name: Setup runs-on: ubuntu-22.04 + permissions: + contents: write outputs: release_version: ${{ steps.version.outputs.version }} release_channel: ${{ steps.release_channel.outputs.channel }} @@ -115,6 +117,8 @@ jobs: name: Linux Build runs-on: ubuntu-22.04 needs: setup + permissions: + contents: read env: _PACKAGE_VERSION: ${{ needs.setup.outputs.release_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -204,6 +208,9 @@ jobs: name: Windows Build runs-on: windows-2022 needs: setup + permissions: + contents: read + id-token: write defaults: run: shell: pwsh @@ -237,10 +244,12 @@ jobs: npm --version choco --version - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -253,6 +262,9 @@ jobs: code-signing-client-secret, code-signing-cert-name" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Install Node dependencies run: npm ci working-directory: ./ @@ -394,6 +406,9 @@ jobs: name: MacOS Build runs-on: macos-13 needs: setup + permissions: + contents: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.release_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -438,6 +453,20 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD" + - name: Download Provisioning Profiles secrets env: ACCOUNT_NAME: bitwardenci @@ -472,9 +501,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -528,6 +560,10 @@ jobs: needs: - setup - macos-build + permissions: + contents: read + packages: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.release_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -572,10 +608,19 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD,APPLE-ID-USERNAME,APPLE-ID-PASSWORD" - name: Download Provisioning Profiles secrets env: @@ -611,9 +656,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -702,8 +750,8 @@ jobs: - name: Build application (dist) env: - APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + APPLE_ID_USERNAME: ${{ steps.get-kv-secrets.outputs.APPLE-ID-USERNAME }} + APPLE_ID_PASSWORD: ${{ steps.get-kv-secrets.outputs.APPLE-ID-PASSWORD }} run: npm run pack:mac - name: Upload .zip artifact @@ -741,6 +789,10 @@ jobs: needs: - setup - macos-build + permissions: + contents: read + packages: read + id-token: write env: _PACKAGE_VERSION: ${{ needs.setup.outputs.release_version }} _NODE_VERSION: ${{ needs.setup.outputs.node_version }} @@ -785,6 +837,20 @@ jobs: path: apps/browser/dist/Safari key: ${{ runner.os }}-${{ github.run_id }}-safari-extension + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-clients + secrets: "KEYCHAIN-PASSWORD,APPLE-ID-USERNAME,APPLE-ID-PASSWORD" + - name: Download Provisioning Profiles secrets env: ACCOUNT_NAME: bitwardenci @@ -819,9 +885,12 @@ jobs: az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert | jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12 + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Set up keychain env: - KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} + KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }} run: | security create-keychain -p $KEYCHAIN_PASSWORD build.keychain security default-keychain -s build.keychain @@ -911,8 +980,8 @@ jobs: - name: Build application for App Store run: npm run pack:mac:mas env: - APPLE_ID_USERNAME: ${{ secrets.APPLE_ID_USERNAME }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + APPLE_ID_USERNAME: ${{ steps.get-kv-secrets.outputs.APPLE-ID-USERNAME }} + APPLE_ID_PASSWORD: ${{ steps.get-kv-secrets.outputs.APPLE-ID-PASSWORD }} - name: Upload .pkg artifact uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 @@ -931,6 +1000,10 @@ jobs: - macos-build - macos-package-github - macos-package-mas + permissions: + contents: read + id-token: write + deployments: write steps: - name: Create GitHub deployment uses: chrnorm/deployment-action@55729fcebec3d284f60f5bcabbd8376437d696b1 # v2.0.7 @@ -942,10 +1015,12 @@ jobs: description: 'Deployment ${{ needs.setup.outputs.release_version }} to channel ${{ needs.setup.outputs.release_channel }} from branch ${{ needs.setup.outputs.branch_name }}' task: release - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -956,6 +1031,9 @@ jobs: aws-electron-access-key, aws-electron-bucket-name" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Download all artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: @@ -1008,6 +1086,8 @@ jobs: - macos-package-github - macos-package-mas - release + permissions: + contents: write steps: - name: Checkout repo uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/.github/workflows/repository-management.yml b/.github/workflows/repository-management.yml index d91e0a12afd..ecb8e448a8a 100644 --- a/.github/workflows/repository-management.yml +++ b/.github/workflows/repository-management.yml @@ -36,7 +36,9 @@ on: description: "New version override (leave blank for automatic calculation, example: '2024.1.0')" required: false type: string + permissions: {} + jobs: setup: name: Setup @@ -56,6 +58,7 @@ jobs: fi echo "branch=$BRANCH" >> $GITHUB_OUTPUT + bump_version: name: Bump Version if: ${{ always() }} @@ -66,6 +69,9 @@ jobs: version_cli: ${{ steps.set-final-version-output.outputs.version_cli }} version_desktop: ${{ steps.set-final-version-output.outputs.version_desktop }} version_web: ${{ steps.set-final-version-output.outputs.version_web }} + permissions: + id-token: write + steps: - name: Validate version input format if: ${{ inputs.version_number_override != '' }} @@ -73,12 +79,29 @@ jobs: with: version: ${{ inputs.version_number_override }} + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-org-bitwarden + secrets: "BW-GHAPP-ID,BW-GHAPP-KEY" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Generate GH App token uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 id: app-token with: - app-id: ${{ secrets.BW_GHAPP_ID }} - private-key: ${{ secrets.BW_GHAPP_KEY }} + app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} + private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} - name: Check out branch uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -400,6 +423,7 @@ jobs: - name: Push changes if: ${{ steps.version-changed.outputs.changes_to_commit == 'TRUE' }} run: git push + cut_branch: name: Cut branch if: ${{ needs.setup.outputs.branch == 'rc' }} @@ -407,13 +431,33 @@ jobs: - setup - bump_version runs-on: ubuntu-24.04 + permissions: + id-token: write + steps: + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-org-bitwarden + secrets: "BW-GHAPP-ID,BW-GHAPP-KEY" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Generate GH App token uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 id: app-token with: - app-id: ${{ secrets.BW_GHAPP_ID }} - private-key: ${{ secrets.BW_GHAPP_KEY }} + app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} + private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} - name: Check out target ref uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -435,4 +479,4 @@ jobs: BRANCH_NAME: ${{ needs.setup.outputs.branch }} run: | git switch --quiet --create $BRANCH_NAME - git push --quiet --set-upstream origin $BRANCH_NAME \ No newline at end of file + git push --quiet --set-upstream origin $BRANCH_NAME diff --git a/.github/workflows/retrieve-current-desktop-rollout.yml b/.github/workflows/retrieve-current-desktop-rollout.yml index 2ab3072f566..c45453ed9d0 100644 --- a/.github/workflows/retrieve-current-desktop-rollout.yml +++ b/.github/workflows/retrieve-current-desktop-rollout.yml @@ -11,11 +11,15 @@ jobs: rollout: name: Retrieve Rollout Percentage runs-on: ubuntu-22.04 + permissions: + id-token: write steps: - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -26,6 +30,9 @@ jobs: aws-electron-access-key, aws-electron-bucket-name" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Download channel update info files from S3 env: AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} diff --git a/.github/workflows/staged-rollout-desktop.yml b/.github/workflows/staged-rollout-desktop.yml index 4ec3af3be97..4adf81100bd 100644 --- a/.github/workflows/staged-rollout-desktop.yml +++ b/.github/workflows/staged-rollout-desktop.yml @@ -18,11 +18,15 @@ jobs: rollout: name: Update Rollout Percentage runs-on: ubuntu-22.04 + permissions: + id-token: write steps: - - name: Login to Azure - uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main with: - creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Retrieve secrets id: retrieve-secrets @@ -33,6 +37,9 @@ jobs: aws-electron-access-key, aws-electron-bucket-name" + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Download channel update info files from S3 env: AWS_ACCESS_KEY_ID: ${{ steps.retrieve-secrets.outputs.aws-electron-access-id }} diff --git a/.github/workflows/version-auto-bump.yml b/.github/workflows/version-auto-bump.yml index e8bd1dde246..3cb5646886a 100644 --- a/.github/workflows/version-auto-bump.yml +++ b/.github/workflows/version-auto-bump.yml @@ -9,13 +9,33 @@ jobs: bump-version: name: Bump Desktop Version runs-on: ubuntu-24.04 + permissions: + id-token: write + contents: write steps: + - name: Log in to Azure + uses: bitwarden/gh-actions/azure-login@main + with: + subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + tenant_id: ${{ secrets.AZURE_TENANT_ID }} + client_id: ${{ secrets.AZURE_CLIENT_ID }} + + - name: Get Azure Key Vault secrets + id: get-kv-secrets + uses: bitwarden/gh-actions/get-keyvault-secrets@main + with: + keyvault: gh-org-bitwarden + secrets: "BW-GHAPP-ID,BW-GHAPP-KEY" + + - name: Log out from Azure + uses: bitwarden/gh-actions/azure-logout@main + - name: Generate GH App token uses: actions/create-github-app-token@30bf6253fa41bdc8d1501d202ad15287582246b4 # v2.0.3 id: app-token with: - app-id: ${{ secrets.BW_GHAPP_ID }} - private-key: ${{ secrets.BW_GHAPP_KEY }} + app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }} + private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }} - name: Check out target ref uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 02734de942b..d7aef05ab92 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "رمز الأمان" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "مثال." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "موافقة الجهاز مطلوبة. حدّد خيار الموافقة أدناه:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index 64fa77c8683..5e7bf056980 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Güvənlik kodu" }, + "cardNumber": { + "message": "kart nömrəsi" + }, "ex": { "message": "məs." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Tələb göndərildi" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "$DEVICE$ cihazında $EMAIL$ üçün giriş tələbi təsdiqləndi", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Başqa bir cihazdan giriş cəhdinə rədd cavabı verdiniz. Bu siz idinizsə, cihazla yenidən giriş etməyə çalışın." + }, + "device": { + "message": "Cihaz" + }, + "loginStatus": { + "message": "Giriş statusu" + }, "masterPasswordChanged": { "message": "Ana parol saxlanıldı" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Gələcək girişləri problemsiz etmək üçün bu cihazı xatırla" }, + "manageDevices": { + "message": "Cihazları idarə et" + }, + "currentSession": { + "message": "Hazırkı seans" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Uzantı", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Masaüstü", + "description": "Desktop app" + }, + "webVault": { + "message": "Veb seyf" + }, + "webApp": { + "message": "Veb tətbiq" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Tələb gözlənir" + }, + "firstLogin": { + "message": "İlk giriş" + }, + "trusted": { + "message": "Güvənli" + }, + "needsApproval": { + "message": "Təsdiq lazımdır" + }, + "devices": { + "message": "Cihazlar" + }, + "accessAttemptBy": { + "message": "$EMAIL$ ilə müraciət cəhdi", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Müraciəti təsdiqlə" + }, + "denyAccess": { + "message": "Müraciətə rədd cavabı ver" + }, + "time": { + "message": "Vaxt" + }, + "deviceType": { + "message": "Cihaz növü" + }, + "loginRequest": { + "message": "Giriş tələbi" + }, + "thisRequestIsNoLongerValid": { + "message": "Bu tələb artıq yararsızdır." + }, + "areYouTryingToAccessYourAccount": { + "message": "Hesabınıza müraciət etməyə çalışırsınız?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "$DEVICE$ cihazında $EMAIL$ üçün giriş təsdiqləndi", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Başqa bir cihazdan giriş cəhdinə rədd cavabı verdiniz. Bu həqiqətən siz idinizsə, cihazla yenidən giriş etməyə çalışın." + }, + "loginRequestHasAlreadyExpired": { + "message": "Giriş tələbinin müddəti artıq bitib." + }, + "justNow": { + "message": "İndicə" + }, + "requestedXMinutesAgo": { + "message": "$MINUTES$ dəqiqə əvvəl tələb göndərildi", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Cihaz təsdiqi tələb olunur. Aşağıdan bir təsdiq variantı seçin:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopyala: $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopyala: $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index eb721e76850..a49899eaee0 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Код бяспекі" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "напр." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Патрабуецца ўхваленне прылады. Выберыце параметры ўхвалення ніжэй:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index dad53b42e36..672e029a662 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Код за сигурност" }, + "cardNumber": { + "message": "номер на карта" + }, "ex": { "message": "напр." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Заявката е изпратена" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Заявката за вписване за $EMAIL$ на $DEVICE$ е одобрена", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Вие отказахте опит за вписване от друго устройство. Ако това сте били Вие, опитайте да се впишете от устройството отново." + }, + "device": { + "message": "Устройство" + }, + "loginStatus": { + "message": "Състояние на вписването" + }, "masterPasswordChanged": { "message": "Главната парола е запазена" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Запомняне на това устройство, така че в бъдеще вписването да бъде по-лесно" }, + "manageDevices": { + "message": "Управление на устройствата" + }, + "currentSession": { + "message": "Текуща сесия" + }, + "mobile": { + "message": "Мобилно приложение", + "description": "Mobile app" + }, + "extension": { + "message": "Добавка за браузър", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Работен плот", + "description": "Desktop app" + }, + "webVault": { + "message": "Трезор по уеб" + }, + "webApp": { + "message": "Приложение по уеб" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Чакаща заявка" + }, + "firstLogin": { + "message": "Първо вписване" + }, + "trusted": { + "message": "Доверено" + }, + "needsApproval": { + "message": "Изисква одобрение" + }, + "devices": { + "message": "Устройства" + }, + "accessAttemptBy": { + "message": "Опит за достъп от $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Разрешаване на достъпа" + }, + "denyAccess": { + "message": "Отказване на достъпа" + }, + "time": { + "message": "Време" + }, + "deviceType": { + "message": "Вид устройство" + }, + "loginRequest": { + "message": "Заявка за вписване" + }, + "thisRequestIsNoLongerValid": { + "message": "Тази заявка вече не е активна." + }, + "areYouTryingToAccessYourAccount": { + "message": "Опитвате ли се да получите достъп до акаунта си?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Вписването за $EMAIL$ на $DEVICE$ е одобрено", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Вие отказахте опит за вписване от друго устройство. Ако това наистина сте били Вие, опитайте да се впишете от устройството отново." + }, + "loginRequestHasAlreadyExpired": { + "message": "Заявката за вписване вече е изтекла." + }, + "justNow": { + "message": "Току-що" + }, + "requestedXMinutesAgo": { + "message": "Заявено преди $MINUTES$ минути", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Изисква се одобрение на устройството. Изберете начин за одобрение по-долу:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Копиране на $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Копиране на $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index d70378f146c..4e30612b9a6 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "নিরাপত্তা কোড" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "উদাহরণ" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index afe20ff55ca..be64d0bade5 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 29859f03dd0..f6c40da1096 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Codi de seguretat" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Sol·licitud enviada" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Cal l'aprovació del dispositiu. Seleccioneu una opció d'aprovació a continuació:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 05135190fb4..4e0096a1520 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Bezpečnostní kód" }, + "cardNumber": { + "message": "číslo karty" + }, "ex": { "message": "např." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Požadavek odeslán" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Požadavek na přihlášení byl schválen pro $EMAIL$ na $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Pokus o přihlášení byl zamítnut z jiného zařízení. Pokud jste to Vy, zkuste se znovu přihlásit do zařízení." + }, + "device": { + "message": "Zařízení" + }, + "loginStatus": { + "message": "Stav přihlášení" + }, "masterPasswordChanged": { "message": "Hlavní heslo bylo uloženo" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Zapamatovat si toto zařízení pro bezproblémové budoucí přihlášení" }, + "manageDevices": { + "message": "Spravovat zařízení" + }, + "currentSession": { + "message": "Aktuální relace" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Rozšíření", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Počítač", + "description": "Desktop app" + }, + "webVault": { + "message": "Webový trezor" + }, + "webApp": { + "message": "Webová aplikace" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Čekající požadavek" + }, + "firstLogin": { + "message": "První přihlášení" + }, + "trusted": { + "message": "Důvěryhodný" + }, + "needsApproval": { + "message": "Vyžaduje schválení" + }, + "devices": { + "message": "Zařízení" + }, + "accessAttemptBy": { + "message": "Pokus o přístup z $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Potvrdit přístup" + }, + "denyAccess": { + "message": "Zamítnout přístup" + }, + "time": { + "message": "Čas" + }, + "deviceType": { + "message": "Typ zařízení" + }, + "loginRequest": { + "message": "Požadavek na přihlášení" + }, + "thisRequestIsNoLongerValid": { + "message": "Tento požadavek již není platný." + }, + "areYouTryingToAccessYourAccount": { + "message": "Pokoušíte se získat přístup k Vašemu účtu?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Přihlášení bylo potvrzeno z $EMAIL$ pro $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Pokus o přihlášení byl zamítnut z jiného zařízení. Pokud jste to opravdu Vy, zkuste se znovu přihlásit do zařízení." + }, + "loginRequestHasAlreadyExpired": { + "message": "Požadavek na přihlášení již vypršel." + }, + "justNow": { + "message": "Právě teď" + }, + "requestedXMinutesAgo": { + "message": "Požadováno před $MINUTES$ minutami", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Vyžaduje se schválení zařízení. Vyberte možnost schválení níže:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopírovat $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopírovat $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index c5cbbdd189c..1235b49dd2c 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Cod diogelwch" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "engh." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 5737ba66b8d..bc34810f97f 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Sikkerhedskode" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "eks." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Husk denne enhed for at gøre fremtidige indlogninger gnidningsløse" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Enhedsgodkendelse kræves. Vælg en godkendelsesmulighed nedenfor:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 352705ec281..2e3d9369c41 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -1174,10 +1174,10 @@ "description": "Detailed error message shown when saving login details fails." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Nachdem du dein Passwort geändert hast, musst du dich mit deinem neuen Passwort anmelden. Aktive Sitzungen auf anderen Geräten werden innerhalb einer Stunde abgemeldet." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Ändere dein Master-Passwort, um die Kontowiederherstellung abzuschließen." }, "enableChangedPasswordNotification": { "message": "Nach dem Aktualisieren bestehender Zugangsdaten fragen" @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Sicherheitscode" }, + "cardNumber": { + "message": "Kartennummer" + }, "ex": { "message": "Bsp." }, @@ -2926,7 +2929,7 @@ "message": "Du musst deine E-Mail Adresse verifizieren, um diese Funktion nutzen zu können. Du kannst deine E-Mail im Web-Tresor verifizieren." }, "masterPasswordSuccessfullySet": { - "message": "Master-Passwort erfolgreich eingerichtet" + "message": "Master-Passwort erfolgreich festgelegt" }, "updatedMasterPassword": { "message": "Master-Passwort aktualisiert" @@ -3460,8 +3463,30 @@ "logInRequestSent": { "message": "Anfrage gesendet" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Anmeldeanfrage für $EMAIL$ auf $DEVICE$ genehmigt", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Du hast einen Anmeldeversuch von einem anderen Gerät abgelehnt. Wenn du das wirklich warst, versuche dich erneut mit dem Gerät anzumelden." + }, + "device": { + "message": "Gerät" + }, + "loginStatus": { + "message": "Anmeldestatus" + }, "masterPasswordChanged": { - "message": "Master password saved" + "message": "Master-Passwort gespeichert" }, "exposedMasterPassword": { "message": "Kompromittiertes Master-Passwort" @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Dieses Gerät merken, um zukünftige Anmeldungen reibungslos zu gestalten" }, + "manageDevices": { + "message": "Geräte verwalten" + }, + "currentSession": { + "message": "Aktuelle Sitzung" + }, + "mobile": { + "message": "Mobile App", + "description": "Mobile app" + }, + "extension": { + "message": "Erweiterung", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web-Tresor" + }, + "webApp": { + "message": "Web-App" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Anfrage ausstehend" + }, + "firstLogin": { + "message": "Erste Anmeldung" + }, + "trusted": { + "message": "Vertrauenswürdig" + }, + "needsApproval": { + "message": "Benötigt Genehmigung" + }, + "devices": { + "message": "Geräte" + }, + "accessAttemptBy": { + "message": "Zugriffsversuch von $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Zugriff bestätigen" + }, + "denyAccess": { + "message": "Zugriff ablehnen" + }, + "time": { + "message": "Zeit" + }, + "deviceType": { + "message": "Gerätetyp" + }, + "loginRequest": { + "message": "Anmeldungsanfrage" + }, + "thisRequestIsNoLongerValid": { + "message": "Diese Anfrage ist nicht mehr gültig." + }, + "areYouTryingToAccessYourAccount": { + "message": "Versuchst du auf dein Konto zuzugreifen?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Anmeldung von $EMAIL$ auf $DEVICE$ bestätigt", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Du hast einen Anmeldeversuch von einem anderen Gerät abgelehnt. Wenn du das wirklich warst, versuche dich erneut mit dem Gerät anzumelden." + }, + "loginRequestHasAlreadyExpired": { + "message": "Anmeldeanfrage ist bereits abgelaufen." + }, + "justNow": { + "message": "Gerade eben" + }, + "requestedXMinutesAgo": { + "message": "Vor $MINUTES$ Minuten angefordert", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Geräte-Genehmigung erforderlich. Wähle unten eine Genehmigungsoption aus:" }, @@ -3578,10 +3710,10 @@ "message": "Admin-Genehmigung anfragen" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "Anmeldung kann nicht abgeschlossen werden" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Du musst dich auf einem vertrauenswürdigen Gerät anmelden oder deinem Administrator bitten, dir ein Passwort zuzuweisen." }, "ssoIdentifierRequired": { "message": "SSO-Kennung der Organisation erforderlich." @@ -4263,23 +4395,23 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "Die URI-Übereinstimmungserkennung ist die Methode, mit der Bitwarden Auto-Ausfüllen-Vorschläge erkennt.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Regulärer Ausdruck\" ist eine erweiterte Option mit erhöhtem Risiko der Kompromittierung von Zugangsdaten.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Beginnt mit\" ist eine erweiterte Option mit erhöhtem Risiko der Kompromittierung von Zugangsdaten.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "Mehr über die Übereinstimmungs-Erkennung", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Erweiterte Optionen", "description": "Advanced option placeholder for uri option component" }, "confirmContinueToBrowserSettingsTitle": { @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "$FIELD$, $VALUE$ kopieren", + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ kopieren", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 960de6670d5..014d17b74c8 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Κωδικός ασφαλείας" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "πχ." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Απομνημόνευση αυτής της συσκευής για την αυτόματες συνδέσεις στο μέλλον" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Απαιτείται έγκριση συσκευής. Επιλέξτε μια επιλογή έγκρισης παρακάτω:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index aab61eca30e..a17a48e95b8 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "e.g." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index eaf11a04e57..9f383c2f0e3 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "e.g." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 724d07f4404..35a28528f49 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Código de seguridad" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ej." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Solicitud enviada" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Se requiere aprobación del dispositivo. Seleccione una opción de aprobación a continuación:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copiar $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index 99e7b72a524..daadcbf00e9 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Turvakood" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "nt." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Nõutav on seadme kinnitamine. Vali kinnitamise meetod alt:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 393f922463e..e5f836fcaae 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Segurtasun-kodea" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "adib." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index fb9380d5317..e551e96f74a 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "کد امنیتی" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "مثال." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "درخواست ارسال شد" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "این دستگاه را به خاطر بسپار تا ورودهای بعدی بدون مشکل انجام شود" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "کپی $FIELD$، $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index 85c47f2733b..22f2046bae3 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Turvakoodi (CVC/CVV)" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "esim." }, @@ -2214,7 +2217,7 @@ "message": "Käytä tätä salasanaa" }, "useThisPassphrase": { - "message": "Use this passphrase" + "message": "Käytä tätä salalausetta" }, "useThisUsername": { "message": "Käytä tätä käyttäjätunnusta" @@ -2531,7 +2534,7 @@ "message": "Vaihda" }, "changePassword": { - "message": "Change password", + "message": "Vaihda salasana", "description": "Change password button for browser at risk notification on login." }, "changeButtonTitle": { @@ -3460,8 +3463,30 @@ "logInRequestSent": { "message": "Pyyntö lähetetty" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { - "message": "Master password saved" + "message": "Pääsalasana tallennettiin" }, "exposedMasterPassword": { "message": "Paljastunut pääsalasana" @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Muista tämä laite tehdäksesi tulevista kirjautumisista saumattomia" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Laitehyväksyntä vaaditaan. Valitse hyväksyntätapa alta:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopioi $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 4e3f94cb474..88610d6874c 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Kodigo ng Seguridad" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index efcc28ddcea..680a19f33cc 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Code de sécurité" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Demande envoyée" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Mémorisez cet appareil pour faciliter les futures connexions" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "L'approbation de l'appareil est requise. Sélectionnez une option d'approbation ci-dessous :" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copier $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 71841239698..559d0ca82b3 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Código de seguridade" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Lembrar este dispositivo para futuros inicios de sesión imperceptibles" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Aprobación de dispositivo requirida. Selecciona unha das seguintes opcións:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index b9a0a3dada4..e4d959785bf 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "קוד אבטחה" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "לדוגמא" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "בקשה נשלחה" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "זכור מכשיר זה כדי להפוך כניסות עתידיות לחלקות" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "נדרש אישור מכשיר. בחר אפשרות אישור למטה:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "העתק $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 74fc419d7f1..4fd2652d786 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security Code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 6434a09bcfb..07c3e20cd18 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Sigurnosni kôd" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "npr." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Zahtjev poslan" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Glavna lozinka promijenjena" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Zapamti ovaj uređaj kako bi buduće prijave bile brže" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Potrebno je odobriti uređaj. Odaberi metodu odobravanja:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopiraj $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index 5391b266a93..b77d613da51 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Biztonsági Kód" }, + "cardNumber": { + "message": "kártya szám" + }, "ex": { "message": "példa:" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "A kérés elküldésre került." }, + "loginRequestApprovedForEmailOnDevice": { + "message": "A bejelentkezési kérelem jóváhagyásra került: $EMAIL$ - $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Megtagadásra került egy bejelentkezési kísérletet egy másik eszközről. Ha valóban mi voltunk, próbáljunk meg újra bejelentkezni az eszközzel." + }, + "device": { + "message": "Eszköz" + }, + "loginStatus": { + "message": "Bejelentkezési állapot" + }, "masterPasswordChanged": { "message": "A mesterjelszó mentésre került." }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Emlékezés az eszközre, hogy zökkenőmentes legyen a jövőbeni bejelentkezés" }, + "manageDevices": { + "message": "Eszközök kezelése" + }, + "currentSession": { + "message": "Jelenlegi munkamenet" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Kiterjesztés", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Asztali", + "description": "Desktop app" + }, + "webVault": { + "message": "Webes széf" + }, + "webApp": { + "message": "Webalkalmazás" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Függőben lévő kérelem" + }, + "firstLogin": { + "message": "Első bejelentkezés" + }, + "trusted": { + "message": "Megbízható" + }, + "needsApproval": { + "message": "Jóváhagyást igényel" + }, + "devices": { + "message": "Eszközök" + }, + "accessAttemptBy": { + "message": "Bejelentkezési kísérlet $EMAIL$ segítségével", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Hozzáférés megerősítése" + }, + "denyAccess": { + "message": "Hozzáférés megtagadása" + }, + "time": { + "message": "Időpont" + }, + "deviceType": { + "message": "Eszköz típus" + }, + "loginRequest": { + "message": "Bejelentkezés kérés" + }, + "thisRequestIsNoLongerValid": { + "message": "A kérés a továbbiakban már nem érvényes." + }, + "areYouTryingToAccessYourAccount": { + "message": "A fiókhoz próbálunk hozzáférni?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "A bejelelentketés $EMAIL$ email címmel megerősítésre került $DEVICE$ eszközön.", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Megtagadásra került egy bejelentkezési kísérletet egy másik eszközről. Ha valóban mi voltunk, próbáljunk meg újra bejelentkezni az eszközzel." + }, + "loginRequestHasAlreadyExpired": { + "message": "A bejelentkezési kérés már lejárt." + }, + "justNow": { + "message": "Éppen most" + }, + "requestedXMinutesAgo": { + "message": "Kérve $MINUTES$ perccel ezelőtt", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Az eszköz jóváhagyása szükséges. Válasszunk egy jóváhagyási lehetőséget lentebb:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "$FIELD$, $VALUE$ másolása", + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ másolása", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index dc1ec15cede..07e094e10bd 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Kode Keamanan" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "mis." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Permintaan terkirim" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Ingat perangkat ini untuk membuat login berikutnya lebih lancar" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Persetujuan perangkat diperlukan. Pilih sebuah pilihan persetujuan berikut:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Salin $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index f4829ecabec..167cc51c0b1 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Codice di sicurezza" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "es." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Richiesta inviata" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Ricorda questo dispositivo per rendere immediati i futuri accessi" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Approvazione del dispositivo obbligatoria. Seleziona un'opzione di approvazione:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copia $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 783a9ff0eb1..49d22bd065f 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "セキュリティコード" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "例:" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "リクエストが送信されました" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "このデバイスを記憶して今後のログインをシームレスにする" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "デバイスの承認が必要です。以下から承認オプションを選択してください:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "$FIELD$ 「$VALUE$」 をコピー", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index efbf97e9a92..1e75805638c 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index d4e4498a322..c7a821de19b 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "ಭದ್ರತಾ ಕೋಡ್ " }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ಉದಾಹರಣೆ" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index d5eba5ccbd8..730d3eeda61 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "보안 코드" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "예)" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "향후 로그인을 원활하게 하기 위해 이 기기 기억하기" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "기기 승인이 필요합니다. 아래에서 승인 옵션을 선택하세요:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index 33f3b0f0ed6..29815c9de82 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Apsaugos kodas" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "pvz." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Įrenginio patvirtinimas reikalingas. Pasirink patvirtinimo būdą toliau:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 2235baef2ab..ba43b1e5f44 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Drošības kods" }, + "cardNumber": { + "message": "kartes numurs" + }, "ex": { "message": "piem." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Pieprasījums nosūtīts" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "$EMAIL$ pieteikšanās pieprasījums apstiprināts $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Tu noraidīji pieteikšanās mēģinājumu no citas ierīces. Ja tas biji Tu, mēģini pieteikties no ierīces vēlreiz!" + }, + "device": { + "message": "Ierīce" + }, + "loginStatus": { + "message": "Pieteikšanās stāvoklis" + }, "masterPasswordChanged": { "message": "Galvenā parole saglabāta" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Atcerēties šo ierīci, lai nākotnes pieteikšanos padarītu plūdenāku" }, + "manageDevices": { + "message": "Pārvaldīt ierīces" + }, + "currentSession": { + "message": "Pašreizējā sesija" + }, + "mobile": { + "message": "Tālrunis", + "description": "Mobile app" + }, + "extension": { + "message": "Paplašinājums", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Darbvirsma", + "description": "Desktop app" + }, + "webVault": { + "message": "Tīmekļa glabātava" + }, + "webApp": { + "message": "Tīmekļa lietotne" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Pieprasījums gaida uz apstrādi" + }, + "firstLogin": { + "message": "Pirmā pieteikšanās" + }, + "trusted": { + "message": "Uzticama" + }, + "needsApproval": { + "message": "Nepieciešams apstiprinājums" + }, + "devices": { + "message": "Ierīces" + }, + "accessAttemptBy": { + "message": "$EMAIL$ piekļuves mēģinājums", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Apstiprināt piekļuvi" + }, + "denyAccess": { + "message": "Noraidīt piekļuvi" + }, + "time": { + "message": "Laiks" + }, + "deviceType": { + "message": "Ierīces veids" + }, + "loginRequest": { + "message": "Pieteikšanās pieprasījums" + }, + "thisRequestIsNoLongerValid": { + "message": "Šis pieprasījums vairs nav derīgs." + }, + "areYouTryingToAccessYourAccount": { + "message": "Vai mēģini piekļūt savam kontam?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "$EMAIL$ pieteikšanās apstiprināta ierīcē $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Tu noraidīji pieteikšanās mēģinājumu no citas ierīces. Ja tas tiešām biji Tu, mēģini pieteikties no ierīces vēlreiz!" + }, + "loginRequestHasAlreadyExpired": { + "message": "Pieteikšanās pieprasījuma derīgums jau ir beidzies." + }, + "justNow": { + "message": "Tikko" + }, + "requestedXMinutesAgo": { + "message": "Pieprasīts pirms $MINUTES$ minūtēm", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Nepieciešams ierīces apstiprinājums. Zemāk jāatlasa apstiprinājuma iespēja:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Ievietot starpliktuvē $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Ievietot starpliktuvē $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 7c0050906b0..a39fe07b2c6 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "സുരക്ഷാ കോഡ്" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ഉദാഹരണം." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index feb3377a2f1..c79b8b322a7 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 59a8ca94c9d..01353cac5e0 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Sikkerhetskode" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "f.eks." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Forespørsel sendt" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopier $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 71134c7a33b..b5220861652 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Beveiligingscode" }, + "cardNumber": { + "message": "kaartnummer" + }, "ex": { "message": "bijv." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Verzoek verzonden" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Inloggen voor $EMAIL$ goedgekeurd op $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Je hebt een inlogpoging vanaf een ander apparaat geweigerd. Als je dit toch echt zelf was, probeer dan opnieuw in te loggen met het apparaat." + }, + "device": { + "message": "Apparaat" + }, + "loginStatus": { + "message": "Loginstatus" + }, "masterPasswordChanged": { "message": "Hoofdwachtwoord gewijzigd" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Onthoud dit apparaat om in het vervolg naadloos in te loggen" }, + "manageDevices": { + "message": "Apparaten beheren" + }, + "currentSession": { + "message": "Huidige sessie" + }, + "mobile": { + "message": "Mobiel", + "description": "Mobile app" + }, + "extension": { + "message": "Extensie", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Webkluis" + }, + "webApp": { + "message": "Web-app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Verzoek in behandeling" + }, + "firstLogin": { + "message": "Eerst inloggen" + }, + "trusted": { + "message": "Vertrouwd" + }, + "needsApproval": { + "message": "Heeft goedkeuring nodig" + }, + "devices": { + "message": "Apparaten" + }, + "accessAttemptBy": { + "message": "Inlogpoging door $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Toegang bevestigen" + }, + "denyAccess": { + "message": "Toegang weigeren" + }, + "time": { + "message": "Tijd" + }, + "deviceType": { + "message": "Apparaattype" + }, + "loginRequest": { + "message": "Log-inverzoek" + }, + "thisRequestIsNoLongerValid": { + "message": "Dit verzoek is niet langer geldig." + }, + "areYouTryingToAccessYourAccount": { + "message": "Probeer je toegang te krijgen tot je account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Inloggen voor $EMAIL$ bevestigd op $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Je hebt een inlogpoging vanaf een ander apparaat geweigerd. Als je dit toch echt zelf was, probeer dan opnieuw in te loggen met het apparaat." + }, + "loginRequestHasAlreadyExpired": { + "message": "Inlogverzoek is al verlopen." + }, + "justNow": { + "message": "Zojuist" + }, + "requestedXMinutesAgo": { + "message": "$MINUTES$ minuten geleden aangevraagd", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Apparaattoestemming vereist. Kies een goedkeuringsoptie hieronder:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "$FIELD$, $VALUE$ kopiëren", + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ kopiëren", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index b4b62d7968c..aa8ab76d543 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -659,7 +659,7 @@ "message": "Zweryfikuj tożsamość" }, "weDontRecognizeThisDevice": { - "message": "Nie rozpoznajemy tego urządzenia. Wpisz kod wysłany na Twój e-mail, aby zweryfikować tożsamość." + "message": "Nie rozpoznajemy tego urządzenia. Wpisz kod wysłany na adres e-mail, aby zweryfikować swoją tożsamość." }, "continueLoggingIn": { "message": "Kontynuuj logowanie" @@ -1213,17 +1213,17 @@ "message": "Pokaż opcje w menu kontekstowym" }, "contextMenuItemDesc": { - "message": "Użyj drugiego kliknięcia, aby uzyskać dostęp do generowania haseł i pasujących danych logowania do witryny." + "message": "Użyj drugiego kliknięcia, aby uzyskać dostęp do generatora hasła i pasujących danych logowania." }, "contextMenuItemDescAlt": { - "message": "Użyj drugiego kliknięcia, aby uzyskać dostęp do generowania haseł i pasujących danych logowania do witryny. Dotyczy wszystkich zalogowanych kont." + "message": "Użyj drugiego kliknięcia, aby uzyskać dostęp do generatora hasła i pasujących danych logowania. Dotyczy wszystkich zalogowanych kont." }, "defaultUriMatchDetection": { "message": "Domyślne wykrywanie dopasowania", "description": "Default URI match detection for autofill." }, "defaultUriMatchDetectionDesc": { - "message": "Wybierz domyślny sposób wykrywania dopasowania adresów dla czynności takich jak autouzupełnianie." + "message": "Wybierz domyślne wykrywanie dopasowania dla autouzupełniania." }, "theme": { "message": "Motyw" @@ -1252,7 +1252,7 @@ "message": "Format pliku" }, "fileEncryptedExportWarningDesc": { - "message": "Plik będzie chroniony hasłem, które będzie wymagane do odszyfrowania pliku." + "message": "Plik zostanie zaszyfrowany hasłem." }, "filePassword": { "message": "Hasło pliku" @@ -1296,7 +1296,7 @@ "message": "Klucze szyfrowania konta są unikalne dla każdego użytkownika Bitwarden, więc nie możesz zaimportować zaszyfrowanego pliku eksportu na inne konto." }, "exportMasterPassword": { - "message": "Wpisz hasło główne, aby wyeksportować dane z sejfu." + "message": "Wpisz hasło główne, aby wyeksportować dane sejfu." }, "shared": { "message": "Udostępnione" @@ -1372,7 +1372,7 @@ "message": "Funkcja jest niedostępna" }, "legacyEncryptionUnsupported": { - "message": "Starsze szyfrowanie nie jest już obsługiwane. Skontaktuj się z pomocą techniczną, aby odzyskać swoje konto." + "message": "Starsze szyfrowanie nie jest już obsługiwane. Skontaktuj się z pomocą techniczną, aby odzyskać konto." }, "premiumMembership": { "message": "Konto premium" @@ -1490,7 +1490,7 @@ "message": "Użyj kodu odzyskiwania" }, "insertU2f": { - "message": "Włóż klucz bezpieczeństwa do portu USB komputera. Jeśli klucz posiada przycisk, dotknij go." + "message": "Włóż klucz bezpieczeństwa do portu USB urządzenia. Jeśli klucz ma przycisk, dotknij go." }, "openInNewTab": { "message": "Otwórz w nowej karcie" @@ -1502,7 +1502,7 @@ "message": "Odczytaj klucz bezpieczeństwa" }, "awaitingSecurityKeyInteraction": { - "message": "Oczekiwanie na interakcję z kluczem bezpieczeństwa..." + "message": "Oczekiwanie na klucz bezpieczeństwa..." }, "loginUnavailable": { "message": "Logowanie jest niedostępne" @@ -1550,7 +1550,7 @@ "message": "FIDO2 WebAuthn" }, "webAuthnDesc": { - "message": "Użyj dowolnego klucza bezpieczeństwa WebAuthn, aby uzyskać dostęp do swojego konta." + "message": "Użyj dowolnego klucza bezpieczeństwa WebAuthn, aby uzyskać dostęp do konta." }, "emailTitle": { "message": "Adres e-mail" @@ -1606,7 +1606,7 @@ "message": "Sugestie autouzupełniania" }, "autofillSpotlightTitle": { - "message": "Łatwe znajdowanie sugestii autouzupełniania" + "message": "Łatwe wyszukiwanie sugestii autouzupełniania" }, "autofillSpotlightDesc": { "message": "Wyłącz ustawienia autouzupełniania swojej przeglądarki, aby nie kolidowały z Bitwarden." @@ -1639,7 +1639,7 @@ "message": "Dotyczy wszystkich zalogowanych kont." }, "turnOffBrowserBuiltInPasswordManagerSettings": { - "message": "Wyłącz wbudowany w przeglądarkę menedżer haseł, aby uniknąć konfliktów." + "message": "Wyłącz menedżer haseł przeglądarki, aby uniknąć konfliktów." }, "turnOffBrowserBuiltInPasswordManagerSettingsLink": { "message": "Edytuj ustawienia przeglądarki." @@ -1761,10 +1761,10 @@ "message": "Pokaż ikony stron internetowych" }, "faviconDesc": { - "message": "Pokaż rozpoznawalny obraz obok danych logowania." + "message": "Pokaż rozpoznawalną ikonę obok danych logowania." }, "faviconDescAlt": { - "message": "Pokaż rozpoznawalny obraz obok danych logowania. Dotyczy wszystkich zalogowanych kont." + "message": "Pokaż rozpoznawalną ikonę obok danych logowania. Dotyczy wszystkich zalogowanych kont." }, "enableBadgeCounter": { "message": "Pokaż licznik na ikonie" @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Kod zabezpieczający" }, + "cardNumber": { + "message": "numer karty" + }, "ex": { "message": "np." }, @@ -1977,7 +1980,7 @@ "message": "Kolekcje" }, "nCollections": { - "message": "Kolekcje: $COUNT$", + "message": "Kolekcje ($COUNT$)", "placeholders": { "count": { "content": "$1", @@ -2646,13 +2649,13 @@ "description": "Description of the update in Bitwarden slide on the at-risk password page carousel" }, "updateInBitwardenSlideImgAltPeriod": { - "message": "Ilustracja powiadomienia Bitwardena, skłaniająca użytkownika do zaktualizowania danych logowania." + "message": "Ilustracja powiadomienia Bitwarden, zachęcająca użytkownika do zaktualizowania danych logowania." }, "turnOnAutofill": { "message": "Włącz autouzupełnianie" }, "turnedOnAutofill": { - "message": "Włączono autouzupełnianie" + "message": "Autouzupełnianie zostało włączone" }, "dismiss": { "message": "Odrzuć" @@ -2902,7 +2905,7 @@ "message": "Data i czas usunięcia są wymagane." }, "dateParsingError": { - "message": "Wystąpił błąd podczas zapisywania daty usunięcia i wygaśnięcia." + "message": "Wystąpił błąd podczas zapisywania dat usunięcia i wygaśnięcia." }, "hideYourEmail": { "message": "Ukryj mój adres e-mail przed odbiorcami." @@ -3136,7 +3139,7 @@ "message": "Błąd odszyfrowywania" }, "couldNotDecryptVaultItemsBelow": { - "message": "Bitwarden nie mógł odszyfrować elementów sejfu wymienionych poniżej." + "message": "Bitwarden nie mógł odszyfrować poniższych elementów sejfu." }, "contactCSToAvoidDataLossPart1": { "message": "Skontaktuj się z działem obsługi klienta,", @@ -3449,7 +3452,7 @@ "message": "Powiadomienie zostało wysłane na urządzenie" }, "youWillBeNotifiedOnceTheRequestIsApproved": { - "message": "Zostaniesz powiadomiony po zatwierdzeniu prośby" + "message": "Zostaniesz powiadomiony po potwierdzeniu" }, "needAnotherOptionV1": { "message": "Potrzebujesz innej opcji?" @@ -3458,7 +3461,29 @@ "message": "Logowanie rozpoczęte" }, "logInRequestSent": { - "message": "Żądanie wysłane" + "message": "Prośba została wysłana" + }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Logowanie potwierdzone dla $EMAIL$ na $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Odrzucono próby logowania z innego urządzenia. Jeśli to naprawdę Ty, spróbuj ponownie zalogować się za pomocą urządzenia." + }, + "device": { + "message": "Urządzenie" + }, + "loginStatus": { + "message": "Status zalogowania" }, "masterPasswordChanged": { "message": "Hasło główne zostało zapisane" @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Zapamiętaj to urządzenie, aby przyszłe logowania były bezproblemowe" }, + "manageDevices": { + "message": "Zarządzaj urządzeniami" + }, + "currentSession": { + "message": "Obecna sesja" + }, + "mobile": { + "message": "Telefon", + "description": "Mobile app" + }, + "extension": { + "message": "Rozszerzenie", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Komputer", + "description": "Desktop app" + }, + "webVault": { + "message": "Sejf internetowy" + }, + "webApp": { + "message": "Aplikacja internetowa" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Zapytanie oczekuje" + }, + "firstLogin": { + "message": "Pierwsze logowanie" + }, + "trusted": { + "message": "Zaufane" + }, + "needsApproval": { + "message": "Wymagane potwierdzenie" + }, + "devices": { + "message": "Urządzenia" + }, + "accessAttemptBy": { + "message": "Próba dostępu przez $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Potwierdź dostęp" + }, + "denyAccess": { + "message": "Odmów dostępu" + }, + "time": { + "message": "Czas" + }, + "deviceType": { + "message": "Rodzaj urządzenia" + }, + "loginRequest": { + "message": "Żądanie logowania" + }, + "thisRequestIsNoLongerValid": { + "message": "Prośba nie jest już ważna." + }, + "areYouTryingToAccessYourAccount": { + "message": "Czy próbujesz uzyskać dostęp do swojego konta?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Logowanie potwierdzone dla $EMAIL$ na $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Odrzucono próby logowania z innego urządzenia. Jeśli to naprawdę Ty, spróbuj ponownie zalogować się za pomocą urządzenia." + }, + "loginRequestHasAlreadyExpired": { + "message": "Prośba logowania wygasła." + }, + "justNow": { + "message": "Teraz" + }, + "requestedXMinutesAgo": { + "message": "Poproszono $MINUTES$ min temu", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Wymagane zatwierdzenie urządzenia. Wybierz opcję zatwierdzenia poniżej:" }, @@ -3563,19 +3695,19 @@ "message": "Wymagane zatwierdzenie urządzenia" }, "selectAnApprovalOptionBelow": { - "message": "Wybierz opcję zatwierdzenia poniżej" + "message": "Wybierz opcję potwierdzenia" }, "rememberThisDevice": { "message": "Zapamiętaj urządzenie" }, "uncheckIfPublicDevice": { - "message": "Odznacz, jeśli używasz publicznego urządzenia" + "message": "Wyłącz na obcych urządzeniach" }, "approveFromYourOtherDevice": { - "message": "Zatwierdź z innego twojego urządzenia" + "message": "Potwierdź za pomocą innego urządzenia" }, "requestAdminApproval": { - "message": "Poproś administratora o zatwierdzenie" + "message": "Poproś administratora o potwierdzenie" }, "unableToCompleteLogin": { "message": "Nie można ukończyć logowania" @@ -3624,10 +3756,10 @@ "message": "Konto zostało utworzone!" }, "adminApprovalRequested": { - "message": "Poproszono administratora o zatwierdzenie" + "message": "Poproszono administratora o potwierdzenie" }, "adminApprovalRequestSentToAdmins": { - "message": "Twoja prośba została wysłana do Twojego administratora." + "message": "Prośba została wysłana do administratora." }, "troubleLoggingIn": { "message": "Problem z logowaniem?" @@ -4307,7 +4439,7 @@ "description": "Body content for dialog which asks if the user wants to proceed to the browser's keyboard shortcut settings page" }, "overrideDefaultBrowserAutofillTitle": { - "message": "Czy ustawić Bitwarden jako domyślny menadżer haseł?", + "message": "Ustawić Bitwarden jako domyślny menadżer haseł?", "description": "Dialog title facilitating the ability to override a chrome browser's default autofill behavior" }, "overrideDefaultBrowserAutofillDescription": { @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopiuj $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopiuj $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, @@ -5455,7 +5587,7 @@ "message": "Nie masz uprawnień do przeglądania tej strony. Spróbuj zalogować się na inne konto." }, "wasmNotSupported": { - "message": "Zestaw WebAssembly nie jest obsługiwany w przeglądarce lub nie jest włączony. Do korzystania z aplikacji Bitwarden wymagany jest zestaw WebAssembre.", + "message": "WebAssembly nie jest obsługiwany w przeglądarce lub jest wyłączony. WebAssembly jest wymagany do korzystania z aplikacji Bitwarden.", "description": "'WebAssembly' is a technical term and should not be translated." } } diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 4d0e4148782..7d5509a628b 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Código de Segurança" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Pedido enviado" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Lembrar deste dispositivo para permanecer conectado" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Aprovação do dispositivo necessária. Selecione uma opção de aprovação abaixo:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copiar $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 8f06014b6b2..1e77e1c3035 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -450,7 +450,7 @@ "message": "Gera automaticamente palavras-passe fortes e únicas para as suas credenciais." }, "bitWebVaultApp": { - "message": "Aplicação Web Bitwarden" + "message": "Aplicação web Bitwarden" }, "importItems": { "message": "Importar itens" @@ -653,7 +653,7 @@ "message": "Classificar a extensão" }, "browserNotSupportClipboard": { - "message": "O seu navegador Web não suporta a cópia fácil da área de transferência. Em vez disso, copie manualmente." + "message": "O seu navegador web não suporta a cópia fácil da área de transferência. Em vez disso, copie manualmente." }, "verifyYourIdentity": { "message": "Verifique a sua identidade" @@ -929,7 +929,7 @@ "message": "Torne a sua conta mais segura configurando a verificação de dois passos na aplicação Web Bitwarden." }, "twoStepLoginConfirmationTitle": { - "message": "Continuar para a aplicação Web?" + "message": "Continuar para a aplicação web?" }, "editedFolder": { "message": "Pasta guardada" @@ -1584,7 +1584,7 @@ "message": "URL do servidor da API" }, "webVaultUrl": { - "message": "URL do servidor do cofre Web" + "message": "URL do servidor do cofre web" }, "identityUrl": { "message": "URL do servidor de identidade" @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Código de segurança" }, + "cardNumber": { + "message": "número do cartão" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Pedido enviado" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Pedido de início de sessão aprovado para $EMAIL$ no $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Recusou uma tentativa de início de sessão de outro dispositivo. Se foi realmente o caso, tente iniciar sessão com o dispositivo novamente." + }, + "device": { + "message": "Dispositivo" + }, + "loginStatus": { + "message": "Estado do início de sessão" + }, "masterPasswordChanged": { "message": "Palavra-passe mestra guardada" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Memorizar este dispositivo para facilitar futuros inícios de sessão" }, + "manageDevices": { + "message": "Gerir dispositivos" + }, + "currentSession": { + "message": "Sessão atual" + }, + "mobile": { + "message": "Móvel", + "description": "Mobile app" + }, + "extension": { + "message": "Extensão", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Computador", + "description": "Desktop app" + }, + "webVault": { + "message": "Cofre web" + }, + "webApp": { + "message": "Aplicação web" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Pedido pendente" + }, + "firstLogin": { + "message": "Primeiro início de sessão" + }, + "trusted": { + "message": "Confiável" + }, + "needsApproval": { + "message": "Precisa de aprovação" + }, + "devices": { + "message": "Dispositivos" + }, + "accessAttemptBy": { + "message": "Tentativa de acesso por $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirmar acesso" + }, + "denyAccess": { + "message": "Recusar acesso" + }, + "time": { + "message": "Hora" + }, + "deviceType": { + "message": "Tipo de dispositivo" + }, + "loginRequest": { + "message": "Pedido de início de sessão" + }, + "thisRequestIsNoLongerValid": { + "message": "Este pedido já não é válido." + }, + "areYouTryingToAccessYourAccount": { + "message": "Está a tentar aceder à sua conta?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Início de sessão confirmado para $EMAIL$ no $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Recusou uma tentativa de início de sessão de outro dispositivo. Se foi realmente o caso, tente iniciar sessão com o dispositivo novamente." + }, + "loginRequestHasAlreadyExpired": { + "message": "O pedido de início de sessão já expirou." + }, + "justNow": { + "message": "Agora mesmo" + }, + "requestedXMinutesAgo": { + "message": "Pedido há $MINUTES$ minutos", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "É necessária a aprovação do dispositivo. Selecione uma opção de aprovação abaixo:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copiar $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copiar $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index 02fc0054e73..7f54640af25 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Cod de securitate" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Este necesară aprobarea dispozitivului. Selectați o opțiune de autorizare de mai jos:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 2c9aa0f4d45..db236cbfcc8 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Код безопасности" }, + "cardNumber": { + "message": "номер карты" + }, "ex": { "message": "напр." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Запрос отправлен" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Запрос входа для $EMAIL$ на $DEVICE$ одобрен", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Вы отклонили попытку авторизации с другого устройства. Если это были вы, попробуйте авторизоваться с этого устройства еще раз." + }, + "device": { + "message": "Устройство" + }, + "loginStatus": { + "message": "Статус авторизации" + }, "masterPasswordChanged": { "message": "Мастер-пароль сохранен" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Запомнить это устройство, чтобы в будущем авторизовываться быстрее" }, + "manageDevices": { + "message": "Управление устройствами" + }, + "currentSession": { + "message": "Текущая сессия" + }, + "mobile": { + "message": "Мобильный", + "description": "Mobile app" + }, + "extension": { + "message": "Расширение", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Компьютер", + "description": "Desktop app" + }, + "webVault": { + "message": "Веб-хранилище" + }, + "webApp": { + "message": "Веб-приложение" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Запрос в ожидании" + }, + "firstLogin": { + "message": "Первый вход" + }, + "trusted": { + "message": "Доверенный" + }, + "needsApproval": { + "message": "Требуется одобрение" + }, + "devices": { + "message": "Устройства" + }, + "accessAttemptBy": { + "message": "Попытка доступа $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Подтвердить доступ" + }, + "denyAccess": { + "message": "Отказать в доступе" + }, + "time": { + "message": "Время" + }, + "deviceType": { + "message": "Тип устройства" + }, + "loginRequest": { + "message": "Запрос на вход" + }, + "thisRequestIsNoLongerValid": { + "message": "Этот запрос больше не действителен." + }, + "areYouTryingToAccessYourAccount": { + "message": "Вы пытаетесь получить доступ к своему аккаунту?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Вход подтвержден для $EMAIL$ на $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Вы отклонили попытку авторизации с другого устройства. Если это действительно были вы, попробуйте авторизоваться с этого устройства еще раз." + }, + "loginRequestHasAlreadyExpired": { + "message": "Запрос на вход истек." + }, + "justNow": { + "message": "Только что" + }, + "requestedXMinutesAgo": { + "message": "Запрошено $MINUTES$ минут назад", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Требуется одобрение устройства. Выберите вариант ниже:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Скопировать $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Копировать $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index aa88e12ba39..13e6c2522bf 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "ආරක්ෂක කේතය" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "හිටපු." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 356617ea25c..e98c643edb9 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Bezpečnostný kód" }, + "cardNumber": { + "message": "číslo karty" + }, "ex": { "message": "napr." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Požiadavka bola odoslaná" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Potvrdené prihlásenie pre $EMAIL$ na $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Odmietli ste pokus o prihlásenie z iného zariadenia. Ak ste to boli vy, skúste sa prihlásiť pomocou zariadenia znova." + }, + "device": { + "message": "Zariadenie" + }, + "loginStatus": { + "message": "Stav prihlásenia" + }, "masterPasswordChanged": { "message": "Hlavné heslo uložené" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Zapamätať si toto zariadenie, pre budúce bezproblémové prihlásenie" }, + "manageDevices": { + "message": "Spravovať zariadenia" + }, + "currentSession": { + "message": "Aktuálna relácia" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Rozšírenie", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Počítač", + "description": "Desktop app" + }, + "webVault": { + "message": "Webový trezor" + }, + "webApp": { + "message": "Webová aplikácia" + }, + "cli": { + "message": "Príkazový riadok (CLI)" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Žiadosť čaká na spracovanie" + }, + "firstLogin": { + "message": "Prvé prihlásenie" + }, + "trusted": { + "message": "Dôveryhodné" + }, + "needsApproval": { + "message": "Potrebuje súhlas" + }, + "devices": { + "message": "Zariadenia" + }, + "accessAttemptBy": { + "message": "Pokus o prístup z $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Potvrdiť prístup" + }, + "denyAccess": { + "message": "Zamietnuť prístup" + }, + "time": { + "message": "Čas" + }, + "deviceType": { + "message": "Typ zariadenia" + }, + "loginRequest": { + "message": "Žiadosť o prihlásenie" + }, + "thisRequestIsNoLongerValid": { + "message": "Táto žiadosť už nie je platná." + }, + "areYouTryingToAccessYourAccount": { + "message": "Snažíte sa získať prístup k svojmu účtu?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Potvrdené prihlásenie pre $EMAIL$ na $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Odmietli ste pokus o prihlásenie z iného zariadenia. Ak ste to boli naozaj vy, skúste sa prihlásiť pomocou zariadenia znova." + }, + "loginRequestHasAlreadyExpired": { + "message": "Platnosť žiadosti o prihlásenie už vypršala." + }, + "justNow": { + "message": "Práve teraz" + }, + "requestedXMinutesAgo": { + "message": "Vyžiadané pred $MINUTES$ min.", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Vyžaduje sa schválenie zariadenia. Vyberte možnosť schválenia nižšie:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopírovať $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopírovať $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 72f058254e4..397b7be54e8 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Varnostna koda" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "npr." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 4ac75bde569..f68d0b97447 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Сигурносни код" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "нпр." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Захтев је послат" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Главна лозинка сачувана" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Запамтити овај уређај да би будуће пријаве биле беспрекорне" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Потребно је одобрење уређаја. Изаберите опцију одобрења испод:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Копирај $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index ff20cdd2ed9..cbfc3e478f5 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Säkerhetskod" }, + "cardNumber": { + "message": "kortnummer" + }, "ex": { "message": "t. ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Begäran skickad" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Inloggningsbegäran godkänd för $EMAIL$ på $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Du nekade ett inloggningsförsök från en annan enhet. Om det var du, försök att logga in med enheten igen." + }, + "device": { + "message": "Enhet" + }, + "loginStatus": { + "message": "Inloggningsstatus" + }, "masterPasswordChanged": { "message": "Huvudlösenordet sparades" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Kom ihåg den här enheten för att göra framtida inloggningar smidiga" }, + "manageDevices": { + "message": "Hantera enheter" + }, + "currentSession": { + "message": "Aktuell session" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Tillägg", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Skrivbord", + "description": "Desktop app" + }, + "webVault": { + "message": "Webbvalv" + }, + "webApp": { + "message": "Webbapp" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Förfrågning väntar" + }, + "firstLogin": { + "message": "Första inloggningen" + }, + "trusted": { + "message": "Betrodd" + }, + "needsApproval": { + "message": "Kräver godkännande" + }, + "devices": { + "message": "Enheter" + }, + "accessAttemptBy": { + "message": "Åtkomstförsök av $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Bekräfta åtkomst" + }, + "denyAccess": { + "message": "Neka åtkomst" + }, + "time": { + "message": "Tid" + }, + "deviceType": { + "message": "Enhetstyp" + }, + "loginRequest": { + "message": "Begäran om inloggning" + }, + "thisRequestIsNoLongerValid": { + "message": "Denna begäran är inte längre giltig." + }, + "areYouTryingToAccessYourAccount": { + "message": "Försöker du komma åt ditt konto?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Inloggning bekräftad för $EMAIL$ på $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Du har avvisat ett inloggningsförsök från en annan enhet. Om det verkligen var du, försök logga in med enheten igen." + }, + "loginRequestHasAlreadyExpired": { + "message": "Inloggningsbegäran har redan gått ut." + }, + "justNow": { + "message": "Just nu" + }, + "requestedXMinutesAgo": { + "message": "Begärdes för $MINUTES$ minuter sedan", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Godkännande av enhet krävs. Välj ett alternativ för godkännande nedan:" }, @@ -4075,10 +4207,10 @@ "message": "Inloggad!" }, "passkeyNotCopied": { - "message": "Lösennyckeln kommer inte kopieras" + "message": "Inloggningsnyckeln kommer inte kopieras" }, "passkeyNotCopiedAlert": { - "message": "Lösennyckeln kommer inte att kopieras till det klonade objektet. Vill du fortsätta klona det här objektet?" + "message": "Inloggningsnyckeln kommer inte att kopieras till det klonade objektet. Vill du fortsätta klona det här objektet?" }, "passkeyFeatureIsNotImplementedForAccountsWithoutMasterPassword": { "message": "Verifiering krävs av den initierande webbplatsen. Denna funktion är ännu inte implementerad för konton utan huvudlösenord." @@ -4087,7 +4219,7 @@ "message": "Logga in med nyckel?" }, "passkeyAlreadyExists": { - "message": "En lösennyckel finns redan för detta program." + "message": "En inloggningsnyckel finns redan för detta program." }, "noPasskeysFoundForThisApplication": { "message": "Inga lösennycklar hittades för detta program." @@ -4111,25 +4243,25 @@ "message": "Spara nyckel som ny inloggning" }, "chooseCipherForPasskeySave": { - "message": "Välj en inloggning som du vill spara nyckeln till" + "message": "Välj en inloggning som du vill spara inloggningsnyckeln till" }, "chooseCipherForPasskeyAuth": { - "message": "Välj en lösenordskod att logga in med" + "message": "Välj en inloggningsnyckel att logga in med" }, "passkeyItem": { - "message": "Lösennyckelobjekt" + "message": "Inloggningsnyckelsobjekt" }, "overwritePasskey": { - "message": "Skriv över lösennyckel?" + "message": "Skriv över inloggningsnyckel?" }, "overwritePasskeyAlert": { - "message": "Detta objekt innehåller redan en lösennyckel. Är du säker på att du vill skriva över nuvarande lösennyckeln?" + "message": "Detta objekt innehåller redan en inloggningsnyckel. Är du säker på att du vill skriva över nuvarande inloggningsnyckel?" }, "featureNotSupported": { "message": "Funktionen stöds ännu inte" }, "yourPasskeyIsLocked": { - "message": "Autentisering krävs för att använda lösennyckel. Verifiera din identitet för att fortsätta." + "message": "Autentisering krävs för att använda inloggningsnyckel. Verifiera din identitet för att fortsätta." }, "multifactorAuthenticationCancelled": { "message": "Flerfaktorsautentisering avbruten" @@ -4354,10 +4486,10 @@ "message": "Lyckades" }, "removePasskey": { - "message": "Ta bort passkey" + "message": "Ta bort inloggningsnyckel" }, "passkeyRemoved": { - "message": "Passkey borttagen" + "message": "Inloggningsnyckel borttagen" }, "autofillSuggestions": { "message": "Förslag för autofyll" @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopiera $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopiera $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index ecc7da63e79..9a6d9a4d316 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index c085b7557e0..49515eb1c64 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Security Code" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "ex." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Request sent" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Remember this device to make future logins seamless" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Device approval required. Select an approval option below:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 5dae8dfcdc4..cd7c8d3f0b6 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Güvenlik kodu" }, + "cardNumber": { + "message": "kart numarası" + }, "ex": { "message": "örn." }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "İstek gönderildi" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "$DEVICE$ cihazında $EMAIL$ girişi onaylandı", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Başka bir cihazdan giriş isteğini reddettiniz. Yanlışlıkla yaptıysanız aynı cihazdan yeniden giriş yapmayı deneyin." + }, + "device": { + "message": "Cihaz" + }, + "loginStatus": { + "message": "Oturum açma durumu" + }, "masterPasswordChanged": { "message": "Ana parola kaydedildi" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Sonraki girişleri kolaylaştırmak için bu cihazı hatırla" }, + "manageDevices": { + "message": "Cihazları yönet" + }, + "currentSession": { + "message": "Geçerli oturum" + }, + "mobile": { + "message": "Mobil", + "description": "Mobile app" + }, + "extension": { + "message": "Uzantı", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Masaüstü", + "description": "Desktop app" + }, + "webVault": { + "message": "Web kasası" + }, + "webApp": { + "message": "Web uygulaması" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "İstek bekliyor" + }, + "firstLogin": { + "message": "İlk giriş" + }, + "trusted": { + "message": "Güvenilen" + }, + "needsApproval": { + "message": "Onay gerekiyor" + }, + "devices": { + "message": "Cihazlar" + }, + "accessAttemptBy": { + "message": "$EMAIL$ erişim denemesi", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Erişimi onayla" + }, + "denyAccess": { + "message": "Erişimi reddet" + }, + "time": { + "message": "Tarih" + }, + "deviceType": { + "message": "Cihaz türü" + }, + "loginRequest": { + "message": "Giriş isteği" + }, + "thisRequestIsNoLongerValid": { + "message": "Bu istek artık geçerli değil." + }, + "areYouTryingToAccessYourAccount": { + "message": "Hesabınıza erişmeye mi çalışıyorsunuz?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "$DEVICE$ cihazında $EMAIL$ girişi onaylandı", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Başka bir cihazdan giriş isteğini reddettiniz. Yanlışlıkla yaptıysanız aynı cihazdan yeniden giriş yapmayı deneyin." + }, + "loginRequestHasAlreadyExpired": { + "message": "Giriş isteğinin süresi doldu." + }, + "justNow": { + "message": "Az önce" + }, + "requestedXMinutesAgo": { + "message": "$MINUTES$ dakika önce istendi", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Cihaz onayı gerekiyor. Lütfen onay yönteminizi seçin:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Kopyala: $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Kopyala: $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index 3d25e982642..083d89fbd12 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Код безпеки" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "зразок" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Запит надіслано" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Головний пароль збережено" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Запам'ятайте цей пристрій, щоб спростити майбутні входи в систему" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Необхідне підтвердження пристрою. Виберіть варіант підтвердження нижче:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Копіювати $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index e2752827221..b5de1c2981c 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "Mã bảo mật" }, + "cardNumber": { + "message": "số thẻ" + }, "ex": { "message": "Ví dụ:" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "Đã gửi yêu cầu" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Đã phê duyệt yêu cầu đăng nhập cho $EMAIL$ trên $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "Bạn đã từ chối một lần đăng nhập từ thiết bị khác. Nếu đó là bạn, hãy thử đăng nhập lại bằng thiết bị đó." + }, + "device": { + "message": "Thiết bị" + }, + "loginStatus": { + "message": "Trạng thái đăng nhập" + }, "masterPasswordChanged": { "message": "Đã lưu mật khẩu chính" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "Nhớ thiết bị này để đăng nhập dễ dàng trong tương lai" }, + "manageDevices": { + "message": "Quản lý thiết bị" + }, + "currentSession": { + "message": "Phiên hiện tại" + }, + "mobile": { + "message": "Di động", + "description": "Mobile app" + }, + "extension": { + "message": "Tiện ích mở rộng", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Máy tính", + "description": "Desktop app" + }, + "webVault": { + "message": "Kho web" + }, + "webApp": { + "message": "Ứng dụng web" + }, + "cli": { + "message": "Giao diện dòng lệnh (CLI)" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Yêu cầu đang chờ xử lý" + }, + "firstLogin": { + "message": "Đăng nhập lần đầu" + }, + "trusted": { + "message": "Tin tưởng" + }, + "needsApproval": { + "message": "Cần phê duyệt" + }, + "devices": { + "message": "Thiết bị" + }, + "accessAttemptBy": { + "message": "Cố gắng truy cập bởi $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Xác nhận truy cập" + }, + "denyAccess": { + "message": "Từ chối truy cập" + }, + "time": { + "message": "Thời gian" + }, + "deviceType": { + "message": "Loại thiết bị" + }, + "loginRequest": { + "message": "Yêu cầu đăng nhập" + }, + "thisRequestIsNoLongerValid": { + "message": "Yêu cầu này không còn hiệu lực." + }, + "areYouTryingToAccessYourAccount": { + "message": "Bạn đang cố gắng truy cập tài khoản của mình?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Đã xác nhận đăng nhập cho $EMAIL$ trên $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "Bạn đã từ chối một lần đăng nhập từ thiết bị khác. Nếu thực sự là bạn, hãy thử đăng nhập lại bằng thiết bị đó." + }, + "loginRequestHasAlreadyExpired": { + "message": "Yêu cầu đăng nhập đã hết hạn." + }, + "justNow": { + "message": "Vừa xong" + }, + "requestedXMinutesAgo": { + "message": "Đã yêu cầu $MINUTES$ phút trước", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "Yêu cầu phê duyệt thiết bị. Chọn một tuỳ chọn phê duyệt bên dưới:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Sao chép $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Sao chép $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 9ee8fd5a48f..f44265425e9 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "安全码" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "例如" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "请求已发送" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "设备" + }, + "loginStatus": { + "message": "登录状态" + }, "masterPasswordChanged": { "message": "主密码已保存" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "记住此设备以便将来无缝登录" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "此请求已失效。" + }, + "areYouTryingToAccessYourAccount": { + "message": "您正在尝试访问您的账户吗?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "已确认 $EMAIL$ 在 $DEVICE$ 上的登录", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "您拒绝了另一台设备的登录尝试。如果真的是您,请尝试再次使用该设备登录。" + }, + "loginRequestHasAlreadyExpired": { + "message": "登录请求已过期。" + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "需要设备批准。请在下面选择一个批准选项:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "复制 $FIELD$,$VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index 7403ad53705..b41b9271c75 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -1829,6 +1829,9 @@ "securityCode": { "message": "安全代碼" }, + "cardNumber": { + "message": "card number" + }, "ex": { "message": "例如" }, @@ -3460,6 +3463,28 @@ "logInRequestSent": { "message": "已傳送請求" }, + "loginRequestApprovedForEmailOnDevice": { + "message": "Login request approved for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "Web app - Chrome" + } + } + }, + "youDeniedLoginAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this was you, try to log in with the device again." + }, + "device": { + "message": "Device" + }, + "loginStatus": { + "message": "Login status" + }, "masterPasswordChanged": { "message": "Master password saved" }, @@ -3556,6 +3581,113 @@ "rememberThisDeviceToMakeFutureLoginsSeamless": { "message": "記住此裝置來讓未來的登入體驗更簡易" }, + "manageDevices": { + "message": "Manage devices" + }, + "currentSession": { + "message": "Current session" + }, + "mobile": { + "message": "Mobile", + "description": "Mobile app" + }, + "extension": { + "message": "Extension", + "description": "Browser extension/addon" + }, + "desktop": { + "message": "Desktop", + "description": "Desktop app" + }, + "webVault": { + "message": "Web vault" + }, + "webApp": { + "message": "Web app" + }, + "cli": { + "message": "CLI" + }, + "sdk": { + "message": "SDK", + "description": "Software Development Kit" + }, + "requestPending": { + "message": "Request pending" + }, + "firstLogin": { + "message": "First login" + }, + "trusted": { + "message": "Trusted" + }, + "needsApproval": { + "message": "Needs approval" + }, + "devices": { + "message": "Devices" + }, + "accessAttemptBy": { + "message": "Access attempt by $EMAIL$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + } + } + }, + "confirmAccess": { + "message": "Confirm access" + }, + "denyAccess": { + "message": "Deny access" + }, + "time": { + "message": "Time" + }, + "deviceType": { + "message": "Device Type" + }, + "loginRequest": { + "message": "Login request" + }, + "thisRequestIsNoLongerValid": { + "message": "This request is no longer valid." + }, + "areYouTryingToAccessYourAccount": { + "message": "Are you trying to access your account?" + }, + "logInConfirmedForEmailOnDevice": { + "message": "Login confirmed for $EMAIL$ on $DEVICE$", + "placeholders": { + "email": { + "content": "$1", + "example": "name@example.com" + }, + "device": { + "content": "$2", + "example": "iOS" + } + } + }, + "youDeniedALogInAttemptFromAnotherDevice": { + "message": "You denied a login attempt from another device. If this really was you, try to log in with the device again." + }, + "loginRequestHasAlreadyExpired": { + "message": "Login request has already expired." + }, + "justNow": { + "message": "Just now" + }, + "requestedXMinutesAgo": { + "message": "Requested $MINUTES$ minutes ago", + "placeholders": { + "minutes": { + "content": "$1", + "example": "5" + } + } + }, "deviceApprovalRequired": { "message": "裝置需要取得核准。請在下面選擇一個核准選項:" }, @@ -4465,17 +4597,17 @@ } } }, - "copyFieldValue": { - "message": "Copy $FIELD$, $VALUE$", + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", "description": "Title for a button that copies a field value to the clipboard.", "placeholders": { "field": { "content": "$1", "example": "Username" }, - "value": { + "ciphername": { "content": "$2", - "example": "Foo" + "example": "Login Item" } } }, diff --git a/apps/browser/src/platform/services/local-backed-session-storage.service.ts b/apps/browser/src/platform/services/local-backed-session-storage.service.ts index ee5a53b0ad2..978b993fa4d 100644 --- a/apps/browser/src/platform/services/local-backed-session-storage.service.ts +++ b/apps/browser/src/platform/services/local-backed-session-storage.service.ts @@ -118,14 +118,14 @@ export class LocalBackedSessionStorageService return null; } - const valueJson = await this.encryptService.decryptString(new EncString(local), encKey); - if (valueJson == null) { + try { + const valueJson = await this.encryptService.decryptString(new EncString(local), encKey); + return JSON.parse(valueJson); + } catch { // error with decryption, value is lost, delete state and start over await this.localStorage.remove(this.sessionStorageKey(key)); return null; } - - return JSON.parse(valueJson); } private async updateLocalSessionValue(key: string, value: unknown): Promise { diff --git a/apps/browser/src/popup/app-routing.module.ts b/apps/browser/src/popup/app-routing.module.ts index 9e55cfce2ce..52a60d9c23d 100644 --- a/apps/browser/src/popup/app-routing.module.ts +++ b/apps/browser/src/popup/app-routing.module.ts @@ -268,7 +268,7 @@ const routes: Routes = [ { path: "device-management", component: ExtensionDeviceManagementComponent, - canActivate: [authGuard], + canActivate: [canAccessFeature(FeatureFlag.PM14938_BrowserExtensionLoginApproval), authGuard], data: { elevation: 1 } satisfies RouteDataProperties, }, { diff --git a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts index 9db5811d75c..7af6fb5f212 100644 --- a/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts +++ b/apps/browser/src/vault/popup/services/vault-popup-list-filters.service.ts @@ -237,7 +237,7 @@ export class VaultPopupListFiltersService { return false; } - if (filters.collection && !cipher.collectionIds?.includes(filters.collection.id)) { + if (filters.collection && !cipher.collectionIds?.includes(filters.collection.id!)) { return false; } diff --git a/apps/browser/store/locales/sv/copy.resx b/apps/browser/store/locales/sv/copy.resx index d03c7fc808d..c37095ec167 100644 --- a/apps/browser/store/locales/sv/copy.resx +++ b/apps/browser/store/locales/sv/copy.resx @@ -165,7 +165,7 @@ Applikationer för flera plattformar Säkra och dela känslig data i ditt Bitwarden Vault från vilken webbläsare, mobil enhet eller stationärt operativsystem som helst, och mycket mer. Bitwarden säkrar mer än bara lösenord -End-to-end krypterade lösningar för hantering av referenser från Bitwarden gör det möjligt för organisationer att säkra allt, inklusive utvecklarhemligheter och passkey-upplevelser. Besök Bitwarden.com för att lära dig mer om Bitwarden Secrets Manager och Bitwarden Passwordless.dev! +End-to-end krypterade lösningar för hantering av referenser från Bitwarden gör det möjligt för organisationer att säkra allt, inklusive utvecklarhemligheter och upplevelser med inloggningsnycklar. Besök Bitwarden.com för att lära dig mer om Bitwarden Secrets Manager och Bitwarden Passwordless.dev! diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index 4c514016675..70814c74106 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -349,6 +349,14 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +[[package]] +name = "autotype" +version = "0.0.0" +dependencies = [ + "windows 0.61.1", + "windows-core 0.61.0", +] + [[package]] name = "backtrace" version = "0.3.75" @@ -912,6 +920,7 @@ name = "desktop_napi" version = "0.0.0" dependencies = [ "anyhow", + "autotype", "base64", "desktop_core", "hex", @@ -3677,7 +3686,7 @@ dependencies = [ "windows-implement 0.60.0", "windows-interface 0.59.1", "windows-link", - "windows-result 0.3.2", + "windows-result 0.3.4", "windows-strings", ] @@ -3737,9 +3746,9 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" [[package]] name = "windows-numerics" @@ -3753,12 +3762,12 @@ dependencies = [ [[package]] name = "windows-registry" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1da3e436dc7653dfdf3da67332e22bff09bb0e28b0239e1624499c7830842e" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ "windows-link", - "windows-result 0.3.2", + "windows-result 0.3.4", "windows-strings", ] @@ -3773,18 +3782,18 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index 8e12dded52c..21835c61585 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator"] +members = ["napi", "core", "proxy", "macos_provider", "windows_plugin_authenticator", "autotype"] [workspace.package] version = "0.0.0" @@ -60,7 +60,7 @@ widestring = "=1.2.0" windows = "=0.61.1" windows-core = "=0.61.0" windows-future = "=0.2.0" -windows-registry = "=0.5.1" +windows-registry = "=0.5.3" zbus = "=5.5.0" zbus_polkit = "=5.0.0" zeroizing-alloc = "=0.1.0" diff --git a/apps/desktop/desktop_native/autotype/Cargo.toml b/apps/desktop/desktop_native/autotype/Cargo.toml new file mode 100644 index 00000000000..c8267c3e2ea --- /dev/null +++ b/apps/desktop/desktop_native/autotype/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "autotype" +version.workspace = true +license.workspace = true +edition.workspace = true +publish.workspace = true + +[target.'cfg(windows)'.dependencies] +windows = { workspace = true, features = ["Win32_UI_Input_KeyboardAndMouse", "Win32_UI_WindowsAndMessaging"] } +windows-core = { workspace = true } diff --git a/apps/desktop/desktop_native/autotype/src/lib.rs b/apps/desktop/desktop_native/autotype/src/lib.rs new file mode 100644 index 00000000000..e3083422eb2 --- /dev/null +++ b/apps/desktop/desktop_native/autotype/src/lib.rs @@ -0,0 +1,12 @@ +#[cfg_attr(target_os = "linux", path = "linux.rs")] +#[cfg_attr(target_os = "macos", path = "macos.rs")] +#[cfg_attr(target_os = "windows", path = "windows.rs")] +mod windowing; + +/// Gets the title bar string for the foreground window. +/// +/// TODO: The error handling will be improved in a future PR: PM-23615 +#[allow(clippy::result_unit_err)] +pub fn get_foreground_window_title() -> std::result::Result { + windowing::get_foreground_window_title() +} diff --git a/apps/desktop/desktop_native/autotype/src/linux.rs b/apps/desktop/desktop_native/autotype/src/linux.rs new file mode 100644 index 00000000000..aa06da21a49 --- /dev/null +++ b/apps/desktop/desktop_native/autotype/src/linux.rs @@ -0,0 +1,3 @@ +pub fn get_foreground_window_title() -> std::result::Result { + todo!("Bitwarden does not yet support Linux autotype"); +} diff --git a/apps/desktop/desktop_native/autotype/src/macos.rs b/apps/desktop/desktop_native/autotype/src/macos.rs new file mode 100644 index 00000000000..12a4ca08d3e --- /dev/null +++ b/apps/desktop/desktop_native/autotype/src/macos.rs @@ -0,0 +1,3 @@ +pub fn get_foreground_window_title() -> std::result::Result { + todo!("Bitwarden does not yet support Mac OS autotype"); +} diff --git a/apps/desktop/desktop_native/autotype/src/windows.rs b/apps/desktop/desktop_native/autotype/src/windows.rs new file mode 100644 index 00000000000..d86d5dd35ae --- /dev/null +++ b/apps/desktop/desktop_native/autotype/src/windows.rs @@ -0,0 +1,75 @@ +use std::ffi::OsString; +use std::os::windows::ffi::OsStringExt; + +use windows::Win32::Foundation::HWND; +use windows::Win32::UI::WindowsAndMessaging::{ + GetForegroundWindow, GetWindowTextLengthW, GetWindowTextW, +}; + +/// Gets the title bar string for the foreground window. +pub fn get_foreground_window_title() -> std::result::Result { + let Ok(window_handle) = get_foreground_window() else { + return Err(()); + }; + let Ok(Some(window_title)) = get_window_title(window_handle) else { + return Err(()); + }; + + Ok(window_title) +} + +/// Gets the foreground window handle. +/// +/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getforegroundwindow +fn get_foreground_window() -> Result { + let foreground_window_handle = unsafe { GetForegroundWindow() }; + + if foreground_window_handle.is_invalid() { + return Err(()); + } + + Ok(foreground_window_handle) +} + +/// Gets the length of the window title bar text. +/// +/// TODO: Future improvement is to use GetLastError for better error handling +/// +/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextlengthw +fn get_window_title_length(window_handle: HWND) -> Result { + if window_handle.is_invalid() { + return Err(()); + } + + match usize::try_from(unsafe { GetWindowTextLengthW(window_handle) }) { + Ok(length) => Ok(length), + Err(_) => Err(()), + } +} + +/// Gets the window title bar title. +/// +/// TODO: Future improvement is to use GetLastError for better error handling +/// +/// https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowtextw +fn get_window_title(window_handle: HWND) -> Result, ()> { + if window_handle.is_invalid() { + return Err(()); + } + + let window_title_length = get_window_title_length(window_handle)?; + if window_title_length == 0 { + return Ok(None); + } + + let mut buffer: Vec = vec![0; window_title_length + 1]; // add extra space for the null character + + let window_title_length = unsafe { GetWindowTextW(window_handle, &mut buffer) }; + if window_title_length == 0 { + return Ok(None); + } + + let window_title = OsString::from_wide(&buffer); + + Ok(Some(window_title.to_string_lossy().into_owned())) +} diff --git a/apps/desktop/desktop_native/core/src/biometric/mod.rs b/apps/desktop/desktop_native/core/src/biometric/mod.rs index 79be43b1bfc..e4d51f5da9a 100644 --- a/apps/desktop/desktop_native/core/src/biometric/mod.rs +++ b/apps/desktop/desktop_native/core/src/biometric/mod.rs @@ -83,3 +83,93 @@ impl KeyMaterial { Ok(Sha256::digest(self.digest_material())) } } + +#[cfg(test)] +mod tests { + use crate::biometric::{decrypt, encrypt, KeyMaterial}; + use crate::crypto::CipherString; + use base64::{engine::general_purpose::STANDARD as base64_engine, Engine}; + use std::str::FromStr; + + fn key_material() -> KeyMaterial { + KeyMaterial { + os_key_part_b64: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(), + client_key_part_b64: Some("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()), + } + } + + #[test] + fn test_encrypt() { + let key_material = key_material(); + let iv_b64 = "l9fhDUP/wDJcKwmEzcb/3w==".to_owned(); + let secret = encrypt("secret", &key_material, &iv_b64) + .unwrap() + .parse::() + .unwrap(); + + match secret { + CipherString::AesCbc256_B64 { iv, data: _ } => { + assert_eq!(iv_b64, base64_engine.encode(iv)); + } + _ => panic!("Invalid cipher string"), + } + } + + #[test] + fn test_decrypt() { + let secret = + CipherString::from_str("0.l9fhDUP/wDJcKwmEzcb/3w==|uP4LcqoCCj5FxBDP77NV6Q==").unwrap(); // output from test_encrypt + let key_material = key_material(); + assert_eq!(decrypt(&secret, &key_material).unwrap(), "secret") + } + + #[test] + fn key_material_produces_valid_key() { + let result = key_material().derive_key().unwrap(); + assert_eq!(result.len(), 32); + } + + #[test] + fn key_material_uses_os_part() { + let mut key_material = key_material(); + let result = key_material.derive_key().unwrap(); + key_material.os_key_part_b64 = "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(); + let result2 = key_material.derive_key().unwrap(); + assert_ne!(result, result2); + } + + #[test] + fn key_material_uses_client_part() { + let mut key_material = key_material(); + let result = key_material.derive_key().unwrap(); + key_material.client_key_part_b64 = + Some("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()); + let result2 = key_material.derive_key().unwrap(); + assert_ne!(result, result2); + } + + #[test] + fn key_material_produces_consistent_os_only_key() { + let mut key_material = key_material(); + key_material.client_key_part_b64 = None; + let result = key_material.derive_key().unwrap(); + assert_eq!( + result, + [ + 81, 100, 62, 172, 151, 119, 182, 58, 123, 38, 129, 116, 209, 253, 66, 118, 218, + 237, 236, 155, 201, 234, 11, 198, 229, 171, 246, 144, 71, 188, 84, 246 + ] + .into() + ); + } + + #[test] + fn key_material_produces_unique_os_only_key() { + let mut key_material = key_material(); + key_material.client_key_part_b64 = None; + let result = key_material.derive_key().unwrap(); + key_material.os_key_part_b64 = "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(); + let result2 = key_material.derive_key().unwrap(); + assert_ne!(result, result2); + } +} diff --git a/apps/desktop/desktop_native/core/src/biometric/windows.rs b/apps/desktop/desktop_native/core/src/biometric/windows.rs index 4c2e2c8ae25..99bec132edb 100644 --- a/apps/desktop/desktop_native/core/src/biometric/windows.rs +++ b/apps/desktop/desktop_native/core/src/biometric/windows.rs @@ -1,22 +1,18 @@ -use std::{ - ffi::c_void, - str::FromStr, - sync::{atomic::AtomicBool, Arc}, -}; +use std::{ffi::c_void, str::FromStr}; use anyhow::{anyhow, Result}; use base64::{engine::general_purpose::STANDARD as base64_engine, Engine}; use rand::RngCore; use sha2::{Digest, Sha256}; use windows::{ - core::{factory, h, HSTRING}, - Security::{ - Credentials::{ - KeyCredentialCreationOption, KeyCredentialManager, KeyCredentialStatus, UI::*, - }, - Cryptography::CryptographicBuffer, + core::{factory, HSTRING}, + Security::Credentials::UI::{ + UserConsentVerificationResult, UserConsentVerifier, UserConsentVerifierAvailability, + }, + Win32::{ + Foundation::HWND, System::WinRT::IUserConsentVerifierInterop, + UI::WindowsAndMessaging::GetForegroundWindow, }, - Win32::{Foundation::HWND, System::WinRT::IUserConsentVerifierInterop}, }; use windows_future::IAsyncOperation; @@ -25,10 +21,7 @@ use crate::{ crypto::CipherString, }; -use super::{ - decrypt, encrypt, - windows_focus::{focus_security_prompt, set_focus}, -}; +use super::{decrypt, encrypt, windows_focus::set_focus}; /// The Windows OS implementation of the biometric trait. pub struct Biometric {} @@ -44,9 +37,15 @@ impl super::BiometricTrait for Biometric { // should set the window to the foreground and focus it. set_focus(window); + // Windows Hello prompt must be in foreground, focused, otherwise the face or fingerprint + // unlock will not work. We get the current foreground window, which will either be the + // Bitwarden desktop app or the browser extension. + let foreground_window = unsafe { GetForegroundWindow() }; + let interop = factory::()?; - let operation: IAsyncOperation = - unsafe { interop.RequestVerificationForWindowAsync(window, &HSTRING::from(message))? }; + let operation: IAsyncOperation = unsafe { + interop.RequestVerificationForWindowAsync(foreground_window, &HSTRING::from(message))? + }; let result = operation.get()?; match result { @@ -65,14 +64,6 @@ impl super::BiometricTrait for Biometric { } } - /// Derive the symmetric encryption key from the Windows Hello signature. - /// - /// This works by signing a static challenge string with Windows Hello protected key store. The - /// signed challenge is then hashed using SHA-256 and used as the symmetric encryption key for the - /// Windows Hello protected keys. - /// - /// Windows will only sign the challenge if the user has successfully authenticated with Windows, - /// ensuring user presence. fn derive_key_material(challenge_str: Option<&str>) -> Result { let challenge: [u8; 16] = match challenge_str { Some(challenge_str) => base64_engine @@ -81,51 +72,10 @@ impl super::BiometricTrait for Biometric { .map_err(|e: Vec<_>| anyhow!("Expect length {}, got {}", 16, e.len()))?, None => random_challenge(), }; - let bitwarden = h!("Bitwarden"); - let result = KeyCredentialManager::RequestCreateAsync( - bitwarden, - KeyCredentialCreationOption::FailIfExists, - )? - .get()?; - - let result = match result.Status()? { - KeyCredentialStatus::CredentialAlreadyExists => { - KeyCredentialManager::OpenAsync(bitwarden)?.get()? - } - KeyCredentialStatus::Success => result, - _ => return Err(anyhow!("Failed to create key credential")), - }; - - let challenge_buffer = CryptographicBuffer::CreateFromByteArray(&challenge)?; - let async_operation = result.Credential()?.RequestSignAsync(&challenge_buffer)?; - focus_security_prompt(); - - let done = Arc::new(AtomicBool::new(false)); - let done_clone = done.clone(); - let _ = std::thread::spawn(move || loop { - if !done_clone.load(std::sync::atomic::Ordering::Relaxed) { - focus_security_prompt(); - std::thread::sleep(std::time::Duration::from_millis(500)); - } else { - break; - } - }); - - let signature = async_operation.get(); - done.store(true, std::sync::atomic::Ordering::Relaxed); - let signature = signature?; - - if signature.Status()? != KeyCredentialStatus::Success { - return Err(anyhow!("Failed to sign data")); - } - - let signature_buffer = signature.Result()?; - let mut signature_value = - windows::core::Array::::with_len(signature_buffer.Length().unwrap() as usize); - CryptographicBuffer::CopyToByteArray(&signature_buffer, &mut signature_value)?; - - let key = Sha256::digest(&*signature_value); + // Uses a key derived from the iv. This key is not intended to add any security + // but only a place-holder + let key = Sha256::digest(challenge); let key_b64 = base64_engine.encode(key); let iv_b64 = base64_engine.encode(challenge); Ok(OsDerivedKey { key_b64, iv_b64 }) @@ -182,10 +132,9 @@ fn random_challenge() -> [u8; 16] { mod tests { use super::*; - use crate::biometric::{encrypt, BiometricTrait}; + use crate::biometric::BiometricTrait; #[test] - #[cfg(feature = "manual_test")] fn test_derive_key_material() { let iv_input = "l9fhDUP/wDJcKwmEzcb/3w=="; let result = ::derive_key_material(Some(iv_input)).unwrap(); @@ -195,7 +144,6 @@ mod tests { } #[test] - #[cfg(feature = "manual_test")] fn test_derive_key_material_no_iv() { let result = ::derive_key_material(None).unwrap(); let key = base64_engine.decode(result.key_b64).unwrap(); @@ -221,38 +169,8 @@ mod tests { assert!(::available().await.unwrap()) } - #[test] - fn test_encrypt() { - let key_material = KeyMaterial { - os_key_part_b64: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(), - client_key_part_b64: Some("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()), - }; - let iv_b64 = "l9fhDUP/wDJcKwmEzcb/3w==".to_owned(); - let secret = encrypt("secret", &key_material, &iv_b64) - .unwrap() - .parse::() - .unwrap(); - - match secret { - CipherString::AesCbc256_B64 { iv, data: _ } => { - assert_eq!(iv_b64, base64_engine.encode(iv)); - } - _ => panic!("Invalid cipher string"), - } - } - - #[test] - fn test_decrypt() { - let secret = - CipherString::from_str("0.l9fhDUP/wDJcKwmEzcb/3w==|uP4LcqoCCj5FxBDP77NV6Q==").unwrap(); // output from test_encrypt - let key_material = KeyMaterial { - os_key_part_b64: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(), - client_key_part_b64: Some("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()), - }; - assert_eq!(decrypt(&secret, &key_material).unwrap(), "secret") - } - #[tokio::test] + #[cfg(feature = "manual_test")] async fn get_biometric_secret_requires_key() { let result = ::get_biometric_secret("", "", None).await; assert!(result.is_err()); @@ -263,6 +181,7 @@ mod tests { } #[tokio::test] + #[cfg(feature = "manual_test")] async fn get_biometric_secret_handles_unencrypted_secret() { let test = "test"; let secret = "password"; @@ -284,6 +203,7 @@ mod tests { } #[tokio::test] + #[cfg(feature = "manual_test")] async fn get_biometric_secret_handles_encrypted_secret() { let test = "test"; let secret = @@ -316,61 +236,4 @@ mod tests { "Key material is required for Windows Hello protected keys" ); } - - fn key_material() -> KeyMaterial { - KeyMaterial { - os_key_part_b64: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(), - client_key_part_b64: Some("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()), - } - } - - #[test] - fn key_material_produces_valid_key() { - let result = key_material().derive_key().unwrap(); - assert_eq!(result.len(), 32); - } - - #[test] - fn key_material_uses_os_part() { - let mut key_material = key_material(); - let result = key_material.derive_key().unwrap(); - key_material.os_key_part_b64 = "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(); - let result2 = key_material.derive_key().unwrap(); - assert_ne!(result, result2); - } - - #[test] - fn key_material_uses_client_part() { - let mut key_material = key_material(); - let result = key_material.derive_key().unwrap(); - key_material.client_key_part_b64 = - Some("BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned()); - let result2 = key_material.derive_key().unwrap(); - assert_ne!(result, result2); - } - - #[test] - fn key_material_produces_consistent_os_only_key() { - let mut key_material = key_material(); - key_material.client_key_part_b64 = None; - let result = key_material.derive_key().unwrap(); - assert_eq!( - result, - [ - 81, 100, 62, 172, 151, 119, 182, 58, 123, 38, 129, 116, 209, 253, 66, 118, 218, - 237, 236, 155, 201, 234, 11, 198, 229, 171, 246, 144, 71, 188, 84, 246 - ] - .into() - ); - } - - #[test] - fn key_material_produces_unique_os_only_key() { - let mut key_material = key_material(); - key_material.client_key_part_b64 = None; - let result = key_material.derive_key().unwrap(); - key_material.os_key_part_b64 = "BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=".to_owned(); - let result2 = key_material.derive_key().unwrap(); - assert_ne!(result, result2); - } } diff --git a/apps/desktop/desktop_native/napi/Cargo.toml b/apps/desktop/desktop_native/napi/Cargo.toml index 669f166e748..20b56395801 100644 --- a/apps/desktop/desktop_native/napi/Cargo.toml +++ b/apps/desktop/desktop_native/napi/Cargo.toml @@ -14,6 +14,7 @@ default = [] manual_test = [] [dependencies] +autotype = { path = "../autotype" } base64 = { workspace = true } hex = { workspace = true } anyhow = { workspace = true } diff --git a/apps/desktop/desktop_native/napi/index.d.ts b/apps/desktop/desktop_native/napi/index.d.ts index 6ee460a8065..f554fdb12e8 100644 --- a/apps/desktop/desktop_native/napi/index.d.ts +++ b/apps/desktop/desktop_native/napi/index.d.ts @@ -208,3 +208,6 @@ export declare namespace logging { } export function initNapiLog(jsLogFn: (err: Error | null, arg0: LogLevel, arg1: string) => any): void } +export declare namespace autotype { + export function getForegroundWindowTitle(): string +} diff --git a/apps/desktop/desktop_native/napi/src/lib.rs b/apps/desktop/desktop_native/napi/src/lib.rs index 784bfb72086..aa271b335ad 100644 --- a/apps/desktop/desktop_native/napi/src/lib.rs +++ b/apps/desktop/desktop_native/napi/src/lib.rs @@ -865,3 +865,15 @@ pub mod logging { fn flush(&self) {} } } + +#[napi] +pub mod autotype { + #[napi] + pub fn get_foreground_window_title() -> napi::Result { + autotype::get_foreground_window_title().map_err(|_| { + napi::Error::from_reason( + "Autotype Error: faild to get foreground window title".to_string(), + ) + }) + } +} diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 005b823253f..2ab88fed621 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -1,7 +1,7 @@ { "name": "@bitwarden/desktop", "description": "A secure and free password manager for all of your devices.", - "version": "2025.7.1", + "version": "2025.7.0", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/app/accounts/settings.component.html b/apps/desktop/src/app/accounts/settings.component.html index 46cd323b071..473cfa73f1d 100644 --- a/apps/desktop/src/app/accounts/settings.component.html +++ b/apps/desktop/src/app/accounts/settings.component.html @@ -126,13 +126,13 @@ {{ biometricText | i18n }} - {{ - additionalBiometricSettingsText | i18n + {{ + "additionalTouchIdSettings" | i18n }}
@@ -152,7 +152,7 @@ supportsBiometric && this.form.value.biometric && (userHasMasterPassword || (this.form.value.pin && userHasPinSet)) && - this.isWindows + false " >
@@ -170,9 +170,6 @@ }
- {{ - "recommendedForSecurity" | i18n - }} diff --git a/apps/desktop/src/app/accounts/settings.component.spec.ts b/apps/desktop/src/app/accounts/settings.component.spec.ts index 16ada3fbc07..819438eaa3b 100644 --- a/apps/desktop/src/app/accounts/settings.component.spec.ts +++ b/apps/desktop/src/app/accounts/settings.component.spec.ts @@ -271,74 +271,46 @@ describe("SettingsComponent", () => { vaultTimeoutSettingsService.isBiometricLockSet.mockResolvedValue(true); }); - it("require password or pin on app start message when RemoveUnlockWithPin policy is disabled and pin set and windows desktop", async () => { - const policy = new Policy(); - policy.type = PolicyType.RemoveUnlockWithPin; - policy.enabled = false; - policyService.policiesByType$.mockReturnValue(of([policy])); - platformUtilsService.getDevice.mockReturnValue(DeviceType.WindowsDesktop); - i18nService.t.mockImplementation((id: string) => { - if (id === "requirePasswordOnStart") { - return "Require password or pin on app start"; - } else if (id === "requirePasswordWithoutPinOnStart") { - return "Require password on app start"; - } - return ""; + describe("windows desktop", () => { + beforeEach(() => { + platformUtilsService.getDevice.mockReturnValue(DeviceType.WindowsDesktop); + + // Recreate component to apply the correct device + fixture = TestBed.createComponent(SettingsComponent); + component = fixture.componentInstance; }); - pinServiceAbstraction.isPinSet.mockResolvedValue(true); - await component.ngOnInit(); - fixture.detectChanges(); + it("require password or pin on app start not visible when RemoveUnlockWithPin policy is disabled and pin set and windows desktop", async () => { + const policy = new Policy(); + policy.type = PolicyType.RemoveUnlockWithPin; + policy.enabled = false; + policyService.policiesByType$.mockReturnValue(of([policy])); + pinServiceAbstraction.isPinSet.mockResolvedValue(true); - const requirePasswordOnStartLabelElement = fixture.debugElement.query( - By.css("label[for='requirePasswordOnStart']"), - ); - expect(requirePasswordOnStartLabelElement).not.toBeNull(); - expect(requirePasswordOnStartLabelElement.children).toHaveLength(1); - expect(requirePasswordOnStartLabelElement.children[0].name).toBe("input"); - expect(requirePasswordOnStartLabelElement.children[0].attributes).toMatchObject({ - id: "requirePasswordOnStart", - type: "checkbox", + await component.ngOnInit(); + fixture.detectChanges(); + + const requirePasswordOnStartLabelElement = fixture.debugElement.query( + By.css("label[for='requirePasswordOnStart']"), + ); + expect(requirePasswordOnStartLabelElement).toBeNull(); }); - const textNodes = requirePasswordOnStartLabelElement.childNodes - .filter((node) => node.nativeNode.nodeType === Node.TEXT_NODE) - .map((node) => node.nativeNode.wholeText?.trim()); - expect(textNodes).toContain("Require password or pin on app start"); - }); - it("require password on app start message when RemoveUnlockWithPin policy is enabled and pin set and windows desktop", async () => { - const policy = new Policy(); - policy.type = PolicyType.RemoveUnlockWithPin; - policy.enabled = true; - policyService.policiesByType$.mockReturnValue(of([policy])); - platformUtilsService.getDevice.mockReturnValue(DeviceType.WindowsDesktop); - i18nService.t.mockImplementation((id: string) => { - if (id === "requirePasswordOnStart") { - return "Require password or pin on app start"; - } else if (id === "requirePasswordWithoutPinOnStart") { - return "Require password on app start"; - } - return ""; + it("require password on app start not visible when RemoveUnlockWithPin policy is enabled and pin set and windows desktop", async () => { + const policy = new Policy(); + policy.type = PolicyType.RemoveUnlockWithPin; + policy.enabled = true; + policyService.policiesByType$.mockReturnValue(of([policy])); + pinServiceAbstraction.isPinSet.mockResolvedValue(true); + + await component.ngOnInit(); + fixture.detectChanges(); + + const requirePasswordOnStartLabelElement = fixture.debugElement.query( + By.css("label[for='requirePasswordOnStart']"), + ); + expect(requirePasswordOnStartLabelElement).toBeNull(); }); - pinServiceAbstraction.isPinSet.mockResolvedValue(true); - - await component.ngOnInit(); - fixture.detectChanges(); - - const requirePasswordOnStartLabelElement = fixture.debugElement.query( - By.css("label[for='requirePasswordOnStart']"), - ); - expect(requirePasswordOnStartLabelElement).not.toBeNull(); - expect(requirePasswordOnStartLabelElement.children).toHaveLength(1); - expect(requirePasswordOnStartLabelElement.children[0].name).toBe("input"); - expect(requirePasswordOnStartLabelElement.children[0].attributes).toMatchObject({ - id: "requirePasswordOnStart", - type: "checkbox", - }); - const textNodes = requirePasswordOnStartLabelElement.childNodes - .filter((node) => node.nativeNode.nodeType === Node.TEXT_NODE) - .map((node) => node.nativeNode.wholeText?.trim()); - expect(textNodes).toContain("Require password on app start"); }); }); diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts index 74f02f8b619..bbe5fb60719 100644 --- a/apps/desktop/src/app/accounts/settings.component.ts +++ b/apps/desktop/src/app/accounts/settings.component.ts @@ -78,6 +78,7 @@ export class SettingsComponent implements OnInit, OnDestroy { showOpenAtLoginOption = false; isWindows: boolean; isLinux: boolean; + isMac: boolean; enableTrayText: string; enableTrayDescText: string; @@ -170,31 +171,33 @@ export class SettingsComponent implements OnInit, OnDestroy { private configService: ConfigService, private validationService: ValidationService, ) { - const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop; + this.isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop; + this.isLinux = this.platformUtilsService.getDevice() === DeviceType.LinuxDesktop; + this.isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop; // Workaround to avoid ghosting trays https://github.com/electron/electron/issues/17622 this.requireEnableTray = this.platformUtilsService.getDevice() === DeviceType.LinuxDesktop; - const trayKey = isMac ? "enableMenuBar" : "enableTray"; + const trayKey = this.isMac ? "enableMenuBar" : "enableTray"; this.enableTrayText = this.i18nService.t(trayKey); this.enableTrayDescText = this.i18nService.t(trayKey + "Desc"); - const minToTrayKey = isMac ? "enableMinToMenuBar" : "enableMinToTray"; + const minToTrayKey = this.isMac ? "enableMinToMenuBar" : "enableMinToTray"; this.enableMinToTrayText = this.i18nService.t(minToTrayKey); this.enableMinToTrayDescText = this.i18nService.t(minToTrayKey + "Desc"); - const closeToTrayKey = isMac ? "enableCloseToMenuBar" : "enableCloseToTray"; + const closeToTrayKey = this.isMac ? "enableCloseToMenuBar" : "enableCloseToTray"; this.enableCloseToTrayText = this.i18nService.t(closeToTrayKey); this.enableCloseToTrayDescText = this.i18nService.t(closeToTrayKey + "Desc"); - const startToTrayKey = isMac ? "startToMenuBar" : "startToTray"; + const startToTrayKey = this.isMac ? "startToMenuBar" : "startToTray"; this.startToTrayText = this.i18nService.t(startToTrayKey); this.startToTrayDescText = this.i18nService.t(startToTrayKey + "Desc"); this.showOpenAtLoginOption = !ipc.platform.isWindowsStore; // DuckDuckGo browser is only for macos initially - this.showDuckDuckGoIntegrationOption = isMac; + this.showDuckDuckGoIntegrationOption = this.isMac; const localeOptions: any[] = []; this.i18nService.supportedTranslationLocales.forEach((locale) => { @@ -239,7 +242,6 @@ export class SettingsComponent implements OnInit, OnDestroy { async ngOnInit() { this.vaultTimeoutOptions = await this.generateVaultTimeoutOptions(); const activeAccount = await firstValueFrom(this.accountService.activeAccount$); - this.isLinux = (await this.platformUtilsService.getDevice()) === DeviceType.LinuxDesktop; // Autotype is for Windows initially const isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop; @@ -250,8 +252,6 @@ export class SettingsComponent implements OnInit, OnDestroy { this.userHasMasterPassword = await this.userVerificationService.hasMasterPassword(); - this.isWindows = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop; - this.currentUserEmail = activeAccount.email; this.currentUserId = activeAccount.id; @@ -911,28 +911,4 @@ export class SettingsComponent implements OnInit, OnDestroy { throw new Error("Unsupported platform"); } } - - get autoPromptBiometricsText() { - switch (this.platformUtilsService.getDevice()) { - case DeviceType.MacOsDesktop: - return "autoPromptTouchId"; - case DeviceType.WindowsDesktop: - return "autoPromptWindowsHello"; - case DeviceType.LinuxDesktop: - return "autoPromptPolkit"; - default: - throw new Error("Unsupported platform"); - } - } - - get additionalBiometricSettingsText() { - switch (this.platformUtilsService.getDevice()) { - case DeviceType.MacOsDesktop: - return "additionalTouchIdSettings"; - case DeviceType.WindowsDesktop: - return "additionalWindowsHelloSettings"; - default: - throw new Error("Unsupported platform"); - } - } } diff --git a/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts b/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts index 7de34da5aaf..e0871f86f8c 100644 --- a/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts +++ b/apps/desktop/src/autofill/main/main-desktop-autotype.service.ts @@ -1,3 +1,5 @@ +import { autotype } from "@bitwarden/desktop-napi"; + import { DesktopAutotypeService } from "../services/desktop-autotype.service"; export class MainDesktopAutotypeService { @@ -17,6 +19,10 @@ export class MainDesktopAutotypeService { private enableAutotype() { // eslint-disable-next-line no-console console.log("Enabling Autotype..."); + + const result = autotype.getForegroundWindowTitle(); + // eslint-disable-next-line no-console + console.log("Window Title: " + result); } // TODO: this will call into desktop native code diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts index c310f337182..26a8e949f38 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-linux.service.ts @@ -34,6 +34,7 @@ const policyFileName = "com.bitwarden.Bitwarden.policy"; const policyPath = "/usr/share/polkit-1/actions/"; const SERVICE = "Bitwarden_biometric"; + function getLookupKeyForUser(userId: UserId): string { return `${userId}_user_biometric`; } @@ -45,16 +46,18 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { private cryptoFunctionService: CryptoFunctionService, private logService: LogService, ) {} + private _iv: string | null = null; // Use getKeyMaterial helper instead of direct access private _osKeyHalf: string | null = null; private clientKeyHalves = new Map(); async setBiometricKey(userId: UserId, key: SymmetricCryptoKey): Promise { - const clientKeyPartB64 = Utils.fromBufferToB64( - await this.getOrCreateBiometricEncryptionClientKeyHalf(userId, key), - ); - const storageDetails = await this.getStorageDetails({ clientKeyHalfB64: clientKeyPartB64 }); + const clientKeyHalf = await this.getOrCreateBiometricEncryptionClientKeyHalf(userId, key); + + const storageDetails = await this.getStorageDetails({ + clientKeyHalfB64: clientKeyHalf ? Utils.fromBufferToB64(clientKeyHalf) : undefined, + }); await biometrics.setBiometricSecret( SERVICE, getLookupKeyForUser(userId), @@ -63,6 +66,7 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { storageDetails.ivB64, ); } + async deleteBiometricKey(userId: UserId): Promise { try { await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId)); @@ -91,11 +95,15 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { if (value == null || value == "") { return null; } else { - const clientKeyHalf = this.clientKeyHalves.get(userId); - const clientKeyPartB64 = Utils.fromBufferToB64(clientKeyHalf); + let clientKeyPartB64: string | null = null; + if (this.clientKeyHalves.has(userId)) { + clientKeyPartB64 = Utils.fromBufferToB64(this.clientKeyHalves.get(userId)!); + } const encValue = new EncString(value); this.setIv(encValue.iv); - const storageDetails = await this.getStorageDetails({ clientKeyHalfB64: clientKeyPartB64 }); + const storageDetails = await this.getStorageDetails({ + clientKeyHalfB64: clientKeyPartB64 ?? undefined, + }); const storedValue = await biometrics.getBiometricSecret( SERVICE, getLookupKeyForUser(userId), @@ -169,7 +177,6 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { }): Promise<{ key_material: biometrics.KeyMaterial; ivB64: string }> { if (this._osKeyHalf == null) { const keyMaterial = await biometrics.deriveKeyMaterial(this._iv); - // osKeyHalf is based on the iv and in contrast to windows is not locked behind user verification! this._osKeyHalf = keyMaterial.keyB64; this._iv = keyMaterial.ivB64; } @@ -209,8 +216,8 @@ export default class OsBiometricsServiceLinux implements OsBiometricService { } if (clientKeyHalf == null) { // Set a key half if it doesn't exist - const keyBytes = await this.cryptoFunctionService.randomBytes(32); - const encKey = await this.encryptService.encryptBytes(keyBytes, key); + clientKeyHalf = await this.cryptoFunctionService.randomBytes(32); + const encKey = await this.encryptService.encryptBytes(clientKeyHalf, key); await this.biometricStateService.setEncryptedClientKeyHalf(encKey, userId); } diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts index 674d97bf696..f301efc70e7 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.spec.ts @@ -1,51 +1,65 @@ +import { randomBytes } from "node:crypto"; + +import { BrowserWindow } from "electron"; import { mock } from "jest-mock-extended"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; -import { passwords } from "@bitwarden/desktop-napi"; +import { biometrics, passwords } from "@bitwarden/desktop-napi"; import { BiometricsStatus, BiometricStateService } from "@bitwarden/key-management"; import { WindowMain } from "../../main/window.main"; import OsBiometricsServiceWindows from "./os-biometrics-windows.service"; -jest.mock("@bitwarden/desktop-napi", () => ({ - biometrics: { - available: jest.fn(), - setBiometricSecret: jest.fn(), - getBiometricSecret: jest.fn(), - deleteBiometricSecret: jest.fn(), - prompt: jest.fn(), - deriveKeyMaterial: jest.fn(), - }, - passwords: { - getPassword: jest.fn(), - deletePassword: jest.fn(), - isAvailable: jest.fn(), - PASSWORD_NOT_FOUND: "Password not found", - }, -})); +import OsDerivedKey = biometrics.OsDerivedKey; + +jest.mock("@bitwarden/desktop-napi", () => { + return { + biometrics: { + available: jest.fn().mockResolvedValue(true), + getBiometricSecret: jest.fn().mockResolvedValue(""), + setBiometricSecret: jest.fn().mockResolvedValue(""), + deleteBiometricSecret: jest.fn(), + deriveKeyMaterial: jest.fn().mockResolvedValue({ + keyB64: "", + ivB64: "", + }), + prompt: jest.fn().mockResolvedValue(true), + }, + passwords: { + getPassword: jest.fn().mockResolvedValue(null), + deletePassword: jest.fn().mockImplementation(() => {}), + isAvailable: jest.fn(), + PASSWORD_NOT_FOUND: "Password not found", + }, + }; +}); + +describe("OsBiometricsServiceWindows", function () { + const i18nService = mock(); + const windowMain = mock(); + const browserWindow = mock(); + const encryptionService: EncryptService = mock(); + const cryptoFunctionService: CryptoFunctionService = mock(); + const biometricStateService: BiometricStateService = mock(); + const logService = mock(); -describe("OsBiometricsServiceWindows", () => { let service: OsBiometricsServiceWindows; - let i18nService: I18nService; - let windowMain: WindowMain; - let logService: LogService; - let biometricStateService: BiometricStateService; - const mockUserId = "test-user-id" as UserId; + const key = new SymmetricCryptoKey(new Uint8Array(64)); + const userId = "test-user-id" as UserId; + const serviceKey = "Bitwarden_biometric"; + const storageKey = `${userId}_user_biometric`; beforeEach(() => { - i18nService = mock(); - windowMain = mock(); - logService = mock(); - biometricStateService = mock(); - const encryptionService = mock(); - const cryptoFunctionService = mock(); + windowMain.win = browserWindow; + service = new OsBiometricsServiceWindows( i18nService, windowMain, @@ -62,20 +76,13 @@ describe("OsBiometricsServiceWindows", () => { describe("getBiometricsFirstUnlockStatusForUser", () => { const userId = "test-user-id" as UserId; - it("should return Available when requirePasswordOnRestart is false", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(false); - const result = await service.getBiometricsFirstUnlockStatusForUser(userId); - expect(result).toBe(BiometricsStatus.Available); - }); - it("should return Available when requirePasswordOnRestart is true and client key half is set", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(true); + it("should return Available when client key half is set", async () => { (service as any).clientKeyHalves = new Map(); (service as any).clientKeyHalves.set(userId, new Uint8Array([1, 2, 3, 4])); const result = await service.getBiometricsFirstUnlockStatusForUser(userId); expect(result).toBe(BiometricsStatus.Available); }); - it("should return UnlockNeeded when requirePasswordOnRestart is true and client key half is not set", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(true); + it("should return UnlockNeeded when client key half is not set", async () => { (service as any).clientKeyHalves = new Map(); const result = await service.getBiometricsFirstUnlockStatusForUser(userId); expect(result).toBe(BiometricsStatus.UnlockNeeded); @@ -83,32 +90,7 @@ describe("OsBiometricsServiceWindows", () => { }); describe("getOrCreateBiometricEncryptionClientKeyHalf", () => { - const userId = "test-user-id" as UserId; - const key = new SymmetricCryptoKey(new Uint8Array(64)); - let encryptionService: EncryptService; - let cryptoFunctionService: CryptoFunctionService; - - beforeEach(() => { - encryptionService = mock(); - cryptoFunctionService = mock(); - service = new OsBiometricsServiceWindows( - mock(), - windowMain, - mock(), - biometricStateService, - encryptionService, - cryptoFunctionService, - ); - }); - - it("should return null if getRequirePasswordOnRestart is false", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(false); - const result = await service.getOrCreateBiometricEncryptionClientKeyHalf(userId, key); - expect(result).toBeNull(); - }); - it("should return cached key half if already present", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(true); const cachedKeyHalf = new Uint8Array([10, 20, 30]); (service as any).clientKeyHalves.set(userId.toString(), cachedKeyHalf); const result = await service.getOrCreateBiometricEncryptionClientKeyHalf(userId, key); @@ -116,7 +98,6 @@ describe("OsBiometricsServiceWindows", () => { }); it("should decrypt and return existing encrypted client key half", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(true); biometricStateService.getEncryptedClientKeyHalf = jest .fn() .mockResolvedValue(new Uint8Array([1, 2, 3])); @@ -132,7 +113,6 @@ describe("OsBiometricsServiceWindows", () => { }); it("should generate, encrypt, store, and cache a new key half if none exists", async () => { - biometricStateService.getRequirePasswordOnStart = jest.fn().mockResolvedValue(true); biometricStateService.getEncryptedClientKeyHalf = jest.fn().mockResolvedValue(null); const randomBytes = new Uint8Array([7, 8, 9]); cryptoFunctionService.randomBytes = jest.fn().mockResolvedValue(randomBytes); @@ -148,101 +128,251 @@ describe("OsBiometricsServiceWindows", () => { encrypted, userId, ); - expect(result).toBeNull(); - expect((service as any).clientKeyHalves.get(userId.toString())).toBeNull(); + expect(result).toEqual(randomBytes); + expect((service as any).clientKeyHalves.get(userId.toString())).toEqual(randomBytes); }); }); + describe("supportsBiometrics", () => { + it("should return true if biometrics are available", async () => { + biometrics.available = jest.fn().mockResolvedValue(true); + + const result = await service.supportsBiometrics(); + + expect(result).toBe(true); + }); + + it("should return false if biometrics are not available", async () => { + biometrics.available = jest.fn().mockResolvedValue(false); + + const result = await service.supportsBiometrics(); + + expect(result).toBe(false); + }); + }); + + describe("getBiometricKey", () => { + beforeEach(() => { + biometrics.prompt = jest.fn().mockResolvedValue(true); + }); + + it("should return null when unsuccessfully authenticated biometrics", async () => { + biometrics.prompt = jest.fn().mockResolvedValue(false); + + const result = await service.getBiometricKey(userId); + + expect(result).toBeNull(); + }); + + it.each([null, undefined, ""])( + "should throw error when no biometric key is found '%s'", + async (password) => { + passwords.getPassword = jest.fn().mockResolvedValue(password); + + await expect(service.getBiometricKey(userId)).rejects.toThrow( + "Biometric key not found for user", + ); + + expect(passwords.getPassword).toHaveBeenCalledWith(serviceKey, storageKey); + }, + ); + + it.each([[false], [true]])( + "should return the biometricKey and setBiometricSecret called if password is not encrypted and cached clientKeyHalves is %s", + async (haveClientKeyHalves) => { + const clientKeyHalveBytes = new Uint8Array([1, 2, 3]); + if (haveClientKeyHalves) { + service["clientKeyHalves"].set(userId, clientKeyHalveBytes); + } + const biometricKey = key.toBase64(); + passwords.getPassword = jest.fn().mockResolvedValue(biometricKey); + biometrics.deriveKeyMaterial = jest.fn().mockResolvedValue({ + keyB64: "testKeyB64", + ivB64: "testIvB64", + } satisfies OsDerivedKey); + + const result = await service.getBiometricKey(userId); + + expect(result.toBase64()).toBe(biometricKey); + expect(passwords.getPassword).toHaveBeenCalledWith(serviceKey, storageKey); + expect(biometrics.setBiometricSecret).toHaveBeenCalledWith( + serviceKey, + storageKey, + biometricKey, + { + osKeyPartB64: "testKeyB64", + clientKeyPartB64: haveClientKeyHalves + ? Utils.fromBufferToB64(clientKeyHalveBytes) + : undefined, + }, + "testIvB64", + ); + }, + ); + + it.each([[false], [true]])( + "should return the biometricKey if password is encrypted and cached clientKeyHalves is %s", + async (haveClientKeyHalves) => { + const clientKeyHalveBytes = new Uint8Array([1, 2, 3]); + if (haveClientKeyHalves) { + service["clientKeyHalves"].set(userId, clientKeyHalveBytes); + } + const biometricKey = key.toBase64(); + const biometricKeyEncrypted = "2.testId|data|mac"; + passwords.getPassword = jest.fn().mockResolvedValue(biometricKeyEncrypted); + biometrics.getBiometricSecret = jest.fn().mockResolvedValue(biometricKey); + biometrics.deriveKeyMaterial = jest.fn().mockResolvedValue({ + keyB64: "testKeyB64", + ivB64: "testIvB64", + } satisfies OsDerivedKey); + + const result = await service.getBiometricKey(userId); + + expect(result.toBase64()).toBe(biometricKey); + expect(passwords.getPassword).toHaveBeenCalledWith(serviceKey, storageKey); + expect(biometrics.setBiometricSecret).not.toHaveBeenCalled(); + expect(biometrics.getBiometricSecret).toHaveBeenCalledWith(serviceKey, storageKey, { + osKeyPartB64: "testKeyB64", + clientKeyPartB64: haveClientKeyHalves + ? Utils.fromBufferToB64(clientKeyHalveBytes) + : undefined, + }); + }, + ); + }); + describe("deleteBiometricKey", () => { const serviceName = "Bitwarden_biometric"; const keyName = "test-user-id_user_biometric"; - const witnessKeyName = "test-user-id_user_biometric_witness"; it("should delete biometric key successfully", async () => { - await service.deleteBiometricKey(mockUserId); + await service.deleteBiometricKey(userId); expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); - expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); }); - it.each([ - [false, false], - [false, true], - [true, false], - ])( - "should not throw error if key found: %s and witness key found: %s", - async (keyFound, witnessKeyFound) => { - passwords.deletePassword = jest.fn().mockImplementation((_, account) => { - if (account === keyName) { - if (!keyFound) { - throw new Error(passwords.PASSWORD_NOT_FOUND); - } - return Promise.resolve(); - } - if (account === witnessKeyName) { - if (!witnessKeyFound) { - throw new Error(passwords.PASSWORD_NOT_FOUND); - } - return Promise.resolve(); - } - throw new Error("Unexpected key"); - }); + it.each([[false], [true]])("should not throw error if key found: %s", async (keyFound) => { + if (!keyFound) { + passwords.deletePassword = jest + .fn() + .mockRejectedValue(new Error(passwords.PASSWORD_NOT_FOUND)); + } - await service.deleteBiometricKey(mockUserId); + await service.deleteBiometricKey(userId); - expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); - expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); - if (!keyFound) { - expect(logService.debug).toHaveBeenCalledWith( - "[OsBiometricService] Biometric key %s not found for service %s.", - keyName, - serviceName, - ); - } - if (!witnessKeyFound) { - expect(logService.debug).toHaveBeenCalledWith( - "[OsBiometricService] Biometric witness key %s not found for service %s.", - witnessKeyName, - serviceName, - ); - } - }, - ); + expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); + if (!keyFound) { + expect(logService.debug).toHaveBeenCalledWith( + "[OsBiometricService] Biometric key %s not found for service %s.", + keyName, + serviceName, + ); + } + }); it("should throw error when deletePassword for key throws unexpected errors", async () => { const error = new Error("Unexpected error"); - passwords.deletePassword = jest.fn().mockImplementation((_, account) => { - if (account === keyName) { - throw error; - } - if (account === witnessKeyName) { - return Promise.resolve(); - } - throw new Error("Unexpected key"); - }); + passwords.deletePassword = jest.fn().mockRejectedValue(error); - await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + await expect(service.deleteBiometricKey(userId)).rejects.toThrow(error); expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); - expect(passwords.deletePassword).not.toHaveBeenCalledWith(serviceName, witnessKeyName); + }); + }); + + describe("authenticateBiometric", () => { + const hwnd = randomBytes(32).buffer; + const consentMessage = "Test Windows Hello Consent Message"; + + beforeEach(() => { + windowMain.win.getNativeWindowHandle = jest.fn().mockReturnValue(hwnd); + i18nService.t.mockReturnValue(consentMessage); }); - it("should throw error when deletePassword for witness key throws unexpected errors", async () => { - const error = new Error("Unexpected error"); - passwords.deletePassword = jest.fn().mockImplementation((_, account) => { - if (account === keyName) { - return Promise.resolve(); - } - if (account === witnessKeyName) { - throw error; - } - throw new Error("Unexpected key"); - }); + it("should return true when biometric authentication is successful", async () => { + const result = await service.authenticateBiometric(); - await expect(service.deleteBiometricKey(mockUserId)).rejects.toThrow(error); + expect(result).toBe(true); + expect(biometrics.prompt).toHaveBeenCalledWith(hwnd, consentMessage); + }); - expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, keyName); - expect(passwords.deletePassword).toHaveBeenCalledWith(serviceName, witnessKeyName); + it("should return false when biometric authentication fails", async () => { + biometrics.prompt = jest.fn().mockResolvedValue(false); + + const result = await service.authenticateBiometric(); + + expect(result).toBe(false); + expect(biometrics.prompt).toHaveBeenCalledWith(hwnd, consentMessage); + }); + }); + + describe("getStorageDetails", () => { + it.each([ + ["testClientKeyHalfB64", "testIvB64"], + [undefined, "testIvB64"], + ["testClientKeyHalfB64", null], + [undefined, null], + ])( + "should derive key material and ivB64 and return it when os key half not saved yet", + async (clientKeyHalfB64, ivB64) => { + service["setIv"](ivB64); + + const derivedKeyMaterial = { + keyB64: "derivedKeyB64", + ivB64: "derivedIvB64", + }; + biometrics.deriveKeyMaterial = jest.fn().mockResolvedValue(derivedKeyMaterial); + + const result = await service["getStorageDetails"]({ clientKeyHalfB64 }); + + expect(result).toEqual({ + key_material: { + osKeyPartB64: derivedKeyMaterial.keyB64, + clientKeyPartB64: clientKeyHalfB64, + }, + ivB64: derivedKeyMaterial.ivB64, + }); + expect(biometrics.deriveKeyMaterial).toHaveBeenCalledWith(ivB64); + expect(service["_osKeyHalf"]).toEqual(derivedKeyMaterial.keyB64); + expect(service["_iv"]).toEqual(derivedKeyMaterial.ivB64); + }, + ); + + it("should throw an error when deriving key material and returned iv is null", async () => { + service["setIv"]("testIvB64"); + + const derivedKeyMaterial = { + keyB64: "derivedKeyB64", + ivB64: null as string | undefined | null, + }; + biometrics.deriveKeyMaterial = jest.fn().mockResolvedValue(derivedKeyMaterial); + + await expect( + service["getStorageDetails"]({ clientKeyHalfB64: "testClientKeyHalfB64" }), + ).rejects.toThrow("Initialization Vector is null"); + + expect(biometrics.deriveKeyMaterial).toHaveBeenCalledWith("testIvB64"); + }); + }); + + describe("setIv", () => { + it("should set the iv and reset the osKeyHalf", () => { + const iv = "testIv"; + service["_osKeyHalf"] = "testOsKeyHalf"; + + service["setIv"](iv); + + expect(service["_iv"]).toBe(iv); + expect(service["_osKeyHalf"]).toBeNull(); + }); + + it("should set the iv to null when iv is undefined and reset the osKeyHalf", () => { + service["_osKeyHalf"] = "testOsKeyHalf"; + + service["setIv"](undefined); + + expect(service["_iv"]).toBeNull(); + expect(service["_osKeyHalf"]).toBeNull(); }); }); }); diff --git a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts index 65abced1526..897304c9f61 100644 --- a/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts +++ b/apps/desktop/src/key-management/biometrics/os-biometrics-windows.service.ts @@ -3,7 +3,6 @@ import { EncryptService } from "@bitwarden/common/key-management/crypto/abstract import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { EncryptionType } from "@bitwarden/common/platform/enums"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { UserId } from "@bitwarden/common/types/guid"; @@ -14,10 +13,8 @@ import { WindowMain } from "../../main/window.main"; import { OsBiometricService } from "./os-biometrics.service"; -const KEY_WITNESS_SUFFIX = "_witness"; -const WITNESS_VALUE = "known key"; - const SERVICE = "Bitwarden_biometric"; + function getLookupKeyForUser(userId: UserId): string { return `${userId}_user_biometric`; } @@ -43,18 +40,25 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { } async getBiometricKey(userId: UserId): Promise { - const value = await passwords.getPassword(SERVICE, getLookupKeyForUser(userId)); - let clientKeyHalfB64: string | null = null; - if (this.clientKeyHalves.has(userId)) { - clientKeyHalfB64 = Utils.fromBufferToB64(this.clientKeyHalves.get(userId)); + const success = await this.authenticateBiometric(); + if (!success) { + return null; } + const value = await passwords.getPassword(SERVICE, getLookupKeyForUser(userId)); if (value == null || value == "") { - return null; - } else if (!EncString.isSerializedEncString(value)) { + throw new Error("Biometric key not found for user"); + } + + let clientKeyHalfB64: string | null = null; + if (this.clientKeyHalves.has(userId)) { + clientKeyHalfB64 = Utils.fromBufferToB64(this.clientKeyHalves.get(userId)!); + } + + if (!EncString.isSerializedEncString(value)) { // Update to format encrypted with client key half const storageDetails = await this.getStorageDetails({ - clientKeyHalfB64: clientKeyHalfB64, + clientKeyHalfB64: clientKeyHalfB64 ?? undefined, }); await biometrics.setBiometricSecret( @@ -69,7 +73,7 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { const encValue = new EncString(value); this.setIv(encValue.iv); const storageDetails = await this.getStorageDetails({ - clientKeyHalfB64: clientKeyHalfB64, + clientKeyHalfB64: clientKeyHalfB64 ?? undefined, }); return SymmetricCryptoKey.fromString( await biometrics.getBiometricSecret( @@ -84,35 +88,16 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { async setBiometricKey(userId: UserId, key: SymmetricCryptoKey): Promise { const clientKeyHalf = await this.getOrCreateBiometricEncryptionClientKeyHalf(userId, key); - if ( - await this.valueUpToDate({ - value: key, - clientKeyPartB64: Utils.fromBufferToB64(clientKeyHalf), - service: SERVICE, - storageKey: getLookupKeyForUser(userId), - }) - ) { - return; - } - const storageDetails = await this.getStorageDetails({ clientKeyHalfB64: Utils.fromBufferToB64(clientKeyHalf), }); - const storedValue = await biometrics.setBiometricSecret( + await biometrics.setBiometricSecret( SERVICE, getLookupKeyForUser(userId), key.toBase64(), storageDetails.key_material, storageDetails.ivB64, ); - const parsedStoredValue = new EncString(storedValue); - await this.storeValueWitness( - key, - parsedStoredValue, - SERVICE, - getLookupKeyForUser(userId), - Utils.fromBufferToB64(clientKeyHalf), - ); } async deleteBiometricKey(userId: UserId): Promise { @@ -129,21 +114,11 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { throw e; } } - try { - await passwords.deletePassword(SERVICE, getLookupKeyForUser(userId) + KEY_WITNESS_SUFFIX); - } catch (e) { - if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { - this.logService.debug( - "[OsBiometricService] Biometric witness key %s not found for service %s.", - getLookupKeyForUser(userId) + KEY_WITNESS_SUFFIX, - SERVICE, - ); - } else { - throw e; - } - } } + /** + * Prompts Windows Hello + */ async authenticateBiometric(): Promise { const hwnd = this.windowMain.win.getNativeWindowHandle(); return await biometrics.prompt(hwnd, this.i18nService.t("windowsHelloConsentMessage")); @@ -155,7 +130,6 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { clientKeyHalfB64: string | undefined; }): Promise<{ key_material: biometrics.KeyMaterial; ivB64: string }> { if (this._osKeyHalf == null) { - // Prompts Windows Hello const keyMaterial = await biometrics.deriveKeyMaterial(this._iv); this._osKeyHalf = keyMaterial.keyB64; this._iv = keyMaterial.ivB64; @@ -187,118 +161,6 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { this._osKeyHalf = null; } - /** - * Stores a witness key alongside the encrypted value. This is used to determine if the value is up to date. - * - * @param unencryptedValue The key to store - * @param encryptedValue The encrypted value of the key to store. Used to sync IV of the witness key with the stored key. - * @param service The service to store the witness key under - * @param storageKey The key to store the witness key under. The witness key will be stored under storageKey + {@link KEY_WITNESS_SUFFIX} - * @returns - */ - private async storeValueWitness( - unencryptedValue: SymmetricCryptoKey, - encryptedValue: EncString, - service: string, - storageKey: string, - clientKeyPartB64: string | undefined, - ) { - if (encryptedValue.iv == null) { - return; - } - - const storageDetails = { - keyMaterial: this.witnessKeyMaterial(unencryptedValue, clientKeyPartB64), - ivB64: encryptedValue.iv, - }; - await biometrics.setBiometricSecret( - service, - storageKey + KEY_WITNESS_SUFFIX, - WITNESS_VALUE, - storageDetails.keyMaterial, - storageDetails.ivB64, - ); - } - - /** - * Uses a witness key stored alongside the encrypted value to determine if the value is up to date. - * @param value The value being validated - * @param service The service the value is stored under - * @param storageKey The key the value is stored under. The witness key will be stored under storageKey + {@link KEY_WITNESS_SUFFIX} - * @returns Boolean indicating if the value is up to date. - */ - // Uses a witness key stored alongside the encrypted value to determine if the value is up to date. - private async valueUpToDate({ - value, - clientKeyPartB64, - service, - storageKey, - }: { - value: SymmetricCryptoKey; - clientKeyPartB64: string | undefined; - service: string; - storageKey: string; - }): Promise { - const witnessKeyMaterial = this.witnessKeyMaterial(value, clientKeyPartB64); - if (witnessKeyMaterial == null) { - return false; - } - - let witness = null; - try { - witness = await biometrics.getBiometricSecret( - service, - storageKey + KEY_WITNESS_SUFFIX, - witnessKeyMaterial, - ); - } catch (e) { - if (e instanceof Error && e.message === passwords.PASSWORD_NOT_FOUND) { - this.logService.debug( - "[OsBiometricService] Biometric witness key %s not found for service %s, value is not up to date.", - storageKey + KEY_WITNESS_SUFFIX, - service, - ); - } else { - this.logService.error( - "[OsBiometricService] Error retrieving witness key, assuming value is not up to date.", - e, - ); - } - return false; - } - - if (witness === WITNESS_VALUE) { - return true; - } - - return false; - } - - /** Derives a witness key from a symmetric key being stored for biometric protection */ - private witnessKeyMaterial( - symmetricKey: SymmetricCryptoKey, - clientKeyPartB64: string | undefined, - ): biometrics.KeyMaterial { - let key = null; - const innerKey = symmetricKey.inner(); - if (innerKey.type === EncryptionType.AesCbc256_HmacSha256_B64) { - key = Utils.fromBufferToB64(innerKey.authenticationKey); - } else { - key = Utils.fromBufferToB64(innerKey.encryptionKey); - } - - const result = { - osKeyPartB64: key, - clientKeyPartB64, - }; - - // napi-rs fails to convert null values - if (result.clientKeyPartB64 == null) { - delete result.clientKeyPartB64; - } - return result; - } - async needsSetup() { return false; } @@ -312,14 +174,9 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { async getOrCreateBiometricEncryptionClientKeyHalf( userId: UserId, key: SymmetricCryptoKey, - ): Promise { - const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId); - if (!requireClientKeyHalf) { - return null; - } - + ): Promise { if (this.clientKeyHalves.has(userId)) { - return this.clientKeyHalves.get(userId); + return this.clientKeyHalves.get(userId)!; } // Retrieve existing key half if it exists @@ -331,8 +188,8 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { } if (clientKeyHalf == null) { // Set a key half if it doesn't exist - const keyBytes = await this.cryptoFunctionService.randomBytes(32); - const encKey = await this.encryptService.encryptBytes(keyBytes, key); + clientKeyHalf = await this.cryptoFunctionService.randomBytes(32); + const encKey = await this.encryptService.encryptBytes(clientKeyHalf, key); await this.biometricStateService.setEncryptedClientKeyHalf(encKey, userId); } @@ -342,11 +199,6 @@ export default class OsBiometricsServiceWindows implements OsBiometricService { } async getBiometricsFirstUnlockStatusForUser(userId: UserId): Promise { - const requireClientKeyHalf = await this.biometricStateService.getRequirePasswordOnStart(userId); - if (!requireClientKeyHalf) { - return BiometricsStatus.Available; - } - if (this.clientKeyHalves.has(userId)) { return BiometricsStatus.Available; } else { diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 68f389a40a0..3e539e48eb9 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopieer bevestigingskode (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lengte" }, @@ -1425,6 +1439,9 @@ "message": "Kopieer Sekureiteitskode", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premie-lidmaatskap" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 7b2e220fa48..26aaf141dd2 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "نسخ رمز التحقق (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "الطول" }, @@ -1425,6 +1439,9 @@ "message": "نسخ رمز الأمان", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "العضوية المميزة" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 6d6ce16b126..b04f3204a15 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Doğrulama kodunu kopyala (TOTP)" }, + "copyFieldCipherName": { + "message": "Kopyala: $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Uzunluq" }, @@ -1425,6 +1439,9 @@ "message": "Güvənlik kodunu kopyala", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kart nömrəsi" + }, "premiumMembership": { "message": "Premium üzvlük" }, @@ -3567,11 +3584,11 @@ "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Qabaqcıl seçimlər", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "Xəbərdarlıq", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Avto-yazma qısayolunu fəallaşdır" + }, + "enableAutotypeDescription": { + "message": "Bitwarden, giriş yerlərini doğrulamır, qısayolu istifadə etməzdən əvvəl doğru pəncərədə və xanada olduğunuza əmin olun." } } diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index ae3c8a0cc60..f4b58c89cac 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Скапіяваць праверачны код (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Даўжыня" }, @@ -1425,6 +1439,9 @@ "message": "Скапіяваць код бяспекі", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Прэміяльны статус" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index c67e1dfe829..92ee97ba16a 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Код за потвърждаване (TOTP)" }, + "copyFieldCipherName": { + "message": "Копиране на $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Дължина" }, @@ -1425,6 +1439,9 @@ "message": "Копиране на кода за сигурност", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "номер на карта" + }, "premiumMembership": { "message": "Платен абонамент" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Включване на клавишната комбинация за автоматично попълване" + }, + "enableAutotypeDescription": { + "message": "Битуорден не проверява местата за въвеждане, така че се уверете, че сте в правилния прозорец, преди да ползвате клавишната комбинация." } } diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index 6f5ac9de909..4a39428590e 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "দৈর্ঘ্য" }, @@ -1425,6 +1439,9 @@ "message": "সুরক্ষা কোড অনুলিপিত করুন", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "প্রিমিয়াম সদস্যতা" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 4600780eda5..5be68fe816f 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopira Verifikacioni kod (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Dužina" }, @@ -1425,6 +1439,9 @@ "message": "Kopirajte sigurnosni kod", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium članstvo" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index a28b3b3c6d4..6534c0eef02 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copia codi de verificació (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Longitud" }, @@ -1425,6 +1439,9 @@ "message": "Copia el codi de seguretat", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Subscripció Premium" }, @@ -2197,7 +2214,7 @@ "message": "Identification" }, "contactInfo": { - "message": "Contact information" + "message": "Informació de contacte" }, "allSends": { "message": "Tots els Send", @@ -2363,10 +2380,10 @@ "message": "Autenticar WebAuthn" }, "readSecurityKey": { - "message": "Read security key" + "message": "Llegeix clau de seguretat" }, "awaitingSecurityKeyInteraction": { - "message": "Awaiting security key interaction..." + "message": "S'està esperant la interacció amb la clau de seguretat..." }, "hideEmail": { "message": "Amagueu la meua adreça de correu electrònic als destinataris." @@ -2408,16 +2425,16 @@ "message": "La vostra contrasenya mestra no compleix una o més de les polítiques de l'organització. Per accedir a la caixa forta, heu d'actualitzar-la ara. Si continueu, es tancarà la sessió actual i us demanarà que torneu a iniciar-la. Les sessions en altres dispositius poden continuar romanent actives fins a una hora." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "En canviar la teva contrasenya, cal iniciar la sessió amb la nova contrasenya. Les sessions actives en altres dispositius es tancaran en una hora." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Canvia la contrasenya mestra per completar el recobrament del compte." }, "updateMasterPasswordSubtitle": { - "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + "message": "La contrasenya mestra no s'ajusta als requisits de l'organització. Canvia't la contrasenya mestra per continuar." }, "tdeDisabledMasterPasswordRequired": { - "message": "Your organization has disabled trusted device encryption. Please set a master password to access your vault." + "message": "La teva organització ha desactivat l'encriptació de dispositius fiables. Fixa una contrasenya mestra per accedir a la teva caixa forta." }, "tryAgain": { "message": "Torneu-ho a provar" @@ -2462,7 +2479,7 @@ "message": "Minuts" }, "vaultTimeoutPolicyInEffect1": { - "message": "$HOURS$ hour(s) and $MINUTES$ minute(s) maximum.", + "message": "$HOURS$ hora(es) i $MINUTES$ minut(s) màxim.", "placeholders": { "hours": { "content": "$1", @@ -2528,13 +2545,13 @@ "message": "S'ha suprimit la contrasenya mestra." }, "removeMasterPasswordForOrganizationUserKeyConnector": { - "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." + "message": "Ja no cal contrasenya mestra per als membres de la següent organització. Confirma'n el domini a sota amb l'administrador de la teva organització." }, "organizationName": { "message": "Nom de l'organització" }, "keyConnectorDomain": { - "message": "Key Connector domain" + "message": "Domini del Connector de claus" }, "leaveOrganization": { "message": "Abandona l'organització" @@ -2597,7 +2614,7 @@ } }, "exportingIndividualVaultWithAttachmentsDescription": { - "message": "Only the individual vault items including attachments associated with $EMAIL$ will be exported. Organization vault items will not be included", + "message": "Només els objectes individuals de la caixa forta, inclosos adjunts associats amb $EMAIL$, seran exportats. Els objectes de la caixa forta de l'organització no hi seran inclosos", "placeholders": { "email": { "content": "$1", @@ -2723,7 +2740,7 @@ "message": "Utilitzeu aquesta contrasenya" }, "useThisPassphrase": { - "message": "Use this passphrase" + "message": "Empra aquesta frase de pas" }, "useThisUsername": { "message": "Utilitzeu aquest nom d'usuari" @@ -2760,7 +2777,7 @@ "description": "Labels the domain name email forwarder service option" }, "forwarderDomainNameHint": { - "message": "Choose a domain that is supported by the selected service", + "message": "Tria un domini admès pel servei seleccionat", "description": "Guidance provided for email forwarding services that support multiple email domains." }, "forwarderError": { @@ -2792,7 +2809,7 @@ } }, "forwaderInvalidToken": { - "message": "Invalid $SERVICENAME$ API token", + "message": "API token de $SERVICENAME$ invàlid", "description": "Displayed when the user's API token is empty or rejected by the forwarding service.", "placeholders": { "servicename": { @@ -2802,7 +2819,7 @@ } }, "forwaderInvalidTokenWithMessage": { - "message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$", + "message": "API token de $SERVICENAME$ invàlid: $ERRORMESSAGE$", "description": "Displayed when the user's API token is rejected by the forwarding service with an error message.", "placeholders": { "servicename": { @@ -2816,7 +2833,7 @@ } }, "forwaderInvalidOperation": { - "message": "$SERVICENAME$ refused your request. Please contact your service provider for assistance.", + "message": "$SERVICENAME$ t'ha rebutjat la petició. Contacta amb el teu proveïdor de serveis per assistència.", "description": "Displayed when the user is forbidden from using the API by the forwarding service.", "placeholders": { "servicename": { @@ -2826,7 +2843,7 @@ } }, "forwaderInvalidOperationWithMessage": { - "message": "$SERVICENAME$ refused your request: $ERRORMESSAGE$", + "message": "$SERVICENAME$ us ha rebutjat la petició: $ERRORMESSAGE$", "description": "Displayed when the user is forbidden from using the API by the forwarding service with an error message.", "placeholders": { "servicename": { @@ -2840,7 +2857,7 @@ } }, "forwarderNoAccountId": { - "message": "Unable to obtain $SERVICENAME$ masked email account ID.", + "message": "No es pot obtenir l'ID de compte de correu electrònic emmascarat de $SERVICENAME$.", "description": "Displayed when the forwarding service fails to return an account ID.", "placeholders": { "servicename": { @@ -2850,7 +2867,7 @@ } }, "forwarderNoDomain": { - "message": "Invalid $SERVICENAME$ domain.", + "message": "Domini de $SERVICENAME$ invàlid.", "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", "placeholders": { "servicename": { @@ -2860,7 +2877,7 @@ } }, "forwarderNoUrl": { - "message": "Invalid $SERVICENAME$ url.", + "message": "Url de $SERVICENAME$ invàlid.", "description": "Displayed when the url of the forwarding service wasn't supplied.", "placeholders": { "servicename": { @@ -2870,7 +2887,7 @@ } }, "forwarderUnknownError": { - "message": "Unknown $SERVICENAME$ error occurred.", + "message": "Hi ha hagut un error desconegut amb $SERVICENAME$.", "description": "Displayed when the forwarding service failed due to an unknown error.", "placeholders": { "servicename": { @@ -2880,7 +2897,7 @@ } }, "forwarderUnknownForwarder": { - "message": "Unknown forwarder: '$SERVICENAME$'.", + "message": "Remitent desconegut: «$SERVICENAME$».", "description": "Displayed when the forwarding service is not supported.", "placeholders": { "servicename": { @@ -2948,13 +2965,13 @@ "message": "S'ha enviat una notificació al vostre dispositiu" }, "notificationSentDevicePart1": { - "message": "Unlock Bitwarden on your device or on the " + "message": "Desbloqueja Bitwarden en el teu dispositiu o en el " }, "notificationSentDeviceAnchor": { "message": "aplicació web" }, "notificationSentDevicePart2": { - "message": "Make sure the Fingerprint phrase matches the one below before approving." + "message": "Assegura't que la frase d'empremta digital encaixa amb la d'aquí sota abans d'aprovar-la." }, "needAnotherOptionV1": { "message": "Necessiteu una altra opció?" @@ -2985,7 +3002,7 @@ "description": "'Character count' describes a feature that displays a number next to each character of the password." }, "areYouTryingToAccessYourAccount": { - "message": "Are you trying to access your account?" + "message": "Intentes accedir al teu compte?" }, "accessAttemptBy": { "message": "Intent d'inici de sessió per $EMAIL$", @@ -3046,7 +3063,7 @@ "message": "Aquesta sol·licitud ja no és vàlida." }, "confirmAccessAttempt": { - "message": "Confirm access attempt for $EMAIL$", + "message": "Confirma l'intent d'accés de $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -3058,7 +3075,7 @@ "message": "S'ha sol·licitat inici de sessió" }, "accountAccessRequested": { - "message": "Account access requested" + "message": "Accés al compte demanat" }, "creatingAccountOn": { "message": "Creant compte en" @@ -3106,10 +3123,10 @@ "message": "Accedint a" }, "accessTokenUnableToBeDecrypted": { - "message": "You have been logged out because your access token could not be decrypted. Please log in again to resolve this issue." + "message": "Se t'ha tancat la sessió perquè el teu token d'accés no es podia desxifrar. Torna a iniciar la sessió per resoldre aquest problema." }, "refreshTokenSecureStorageRetrievalFailure": { - "message": "You have been logged out because your refresh token could not be retrieved. Please log in again to resolve this issue." + "message": "Se t'ha tancat la sessió perquè el teu token d'actualització no es podia recuperar. Torna a iniciar la sessió per resoldre aquest problema." }, "masterPasswordHint": { "message": "La contrasenya mestra no es pot recuperar si la oblideu!" @@ -3130,16 +3147,16 @@ "message": "Actualització de configuració recomanada" }, "rememberThisDeviceToMakeFutureLoginsSeamless": { - "message": "Remember this device to make future logins seamless" + "message": "Recorda aquest dispositiu per futurs inicis de sessió sense interrupcions" }, "deviceApprovalRequired": { "message": "Cal l'aprovació del dispositiu. Seleccioneu una opció d'aprovació a continuació:" }, "deviceApprovalRequiredV2": { - "message": "Device approval required" + "message": "Cal aprovació del dispositiu" }, "selectAnApprovalOptionBelow": { - "message": "Select an approval option below" + "message": "Tria una opció d'aprovació a sota" }, "rememberThisDevice": { "message": "Recorda aquest dispositiu" @@ -3154,10 +3171,10 @@ "message": "Sol·liciteu l'aprovació de l'administrador" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "No s'ha pogut finalitzar l'inici de sessió" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Cal iniciar sessió en un dispositiu de confiança o demanar al teu administrador que t'assigni una contrasenya." }, "region": { "message": "Regió" @@ -3194,34 +3211,34 @@ "message": "Falta el correu electrònic de l'usuari" }, "activeUserEmailNotFoundLoggingYouOut": { - "message": "Active user email not found. Logging you out." + "message": "No s'ha trobat el correu electrònic de l'usuari actiu. Se't tancarà la sessió." }, "deviceTrusted": { "message": "Dispositiu de confiança" }, "trustOrganization": { - "message": "Trust organization" + "message": "Confia en l'organització" }, "trust": { "message": "Confiar" }, "doNotTrust": { - "message": "Do not trust" + "message": "No hi confiïs" }, "organizationNotTrusted": { - "message": "Organization is not trusted" + "message": "L'organització no és de confiança" }, "emergencyAccessTrustWarning": { - "message": "For the security of your account, only confirm if you have granted emergency access to this user and their fingerprint matches what is displayed in their account" + "message": "Per la seguretat del teu compte, confirma només si tens garantit l'accés a aquest usuari i la seva empremta coincideix amb el que es mostra al seu compte" }, "orgTrustWarning": { - "message": "For the security of your account, only proceed if you are a member of this organization, have account recovery enabled, and the fingerprint displayed below matches the organization's fingerprint." + "message": "Per la seguretat del teu compte, confirma només si ets un membre d'aquesta organització, tens un compte de recuperació activat i l'empremta de sota coincideix amb la de l'organització." }, "orgTrustWarning1": { - "message": "This organization has an Enterprise policy that will enroll you in account recovery. Enrollment will allow organization administrators to change your password. Only proceed if you recognize this organization and the fingerprint phrase displayed below matches the organization's fingerprint." + "message": "Aquesta organització té una política d'Empresa que t'inscriurà com a compte de recuperació. La inscripció permetrà als administradors de l'organització canviar la teva contrasenya. Continua només si coneixes l'organització i la frase d'empremta digital mostrada a sota coincideix amb l'empremta de l'organització." }, "trustUser": { - "message": "Trust user" + "message": "Confia en l'usuari" }, "inputRequired": { "message": "L'entrada és obligatòria." @@ -3388,13 +3405,13 @@ "message": "Es requereix l'inici de sessió en dos passos de DUO al vostre compte." }, "duoTwoFactorRequiredPageSubtitle": { - "message": "Duo two-step login is required for your account. Follow the steps below to finish logging in." + "message": "Cal l'inici de sessió en dos passos de Duo al vostre compte. Seguiu els passos de sota per finalitzar l'inici de sessió." }, "followTheStepsBelowToFinishLoggingIn": { - "message": "Follow the steps below to finish logging in." + "message": "Seguiu els passos de sota per finalitzar l'inici de sessió." }, "followTheStepsBelowToFinishLoggingInWithSecurityKey": { - "message": "Follow the steps below to finish logging in with your security key." + "message": "Seguiu els passos de sota per finalitzar l'inici de sessió amb la clau de seguretat." }, "launchDuo": { "message": "Inicia Duo al navegador" @@ -3551,27 +3568,27 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "Bitwarden empra la detecció de coincidències URI pels suggeriments d'autoemplenament.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "«Expressió regular» és una opció avançada amb més risc d'exposar credencials.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "«Comença amb» és una opció avançada amb més risc d'exposar credencials.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "Més sobre la detecció de coincidències", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Opcions avançades", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "Advertència", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3642,33 +3659,33 @@ "message": "Sends de text" }, "ssoError": { - "message": "No free ports could be found for the sso login." + "message": "No s'ha trobat cap port lliure per a l'inici de sessió sso." }, "securePasswordGenerated": { - "message": "Secure password generated! Don't forget to also update your password on the website." + "message": "Contrasenya segura generada! No us oblideu d'actualitzar-vos la contrasenya al web." }, "useGeneratorHelpTextPartOne": { - "message": "Use the generator", + "message": "Feu servir el generador", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "useGeneratorHelpTextPartTwo": { - "message": "to create a strong unique password", + "message": "per crear una contrasenya única forta", "description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'" }, "biometricsStatusHelptextUnlockNeeded": { - "message": "Biometric unlock is unavailable because PIN or password unlock is required first." + "message": "El desbloqueig per dades biomètriques no està disponible perquè cal primer desbloquejar el PIN o la contrasenya." }, "biometricsStatusHelptextHardwareUnavailable": { - "message": "Biometric unlock is currently unavailable." + "message": "El desbloqueig per dades biomètriques no està disponible ara." }, "biometricsStatusHelptextAutoSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "El desbloqueig per dades biomètriques no està disponible per uns fitxers del sistema mal configurats." }, "biometricsStatusHelptextManualSetupNeeded": { - "message": "Biometric unlock is unavailable due to misconfigured system files." + "message": "El desbloqueig per dades biomètriques no està disponible per uns fitxers del sistema mal configurats." }, "biometricsStatusHelptextNotEnabledLocally": { - "message": "Biometric unlock is unavailable because it is not enabled for $EMAIL$ in the Bitwarden desktop app.", + "message": "El desbloqueig per dades biomètriques no està disponible perquè no s'ha activat per a $EMAIL$ a l'app d'escriptori de Bitwarden.", "placeholders": { "email": { "content": "$1", @@ -3677,7 +3694,7 @@ } }, "biometricsStatusHelptextUnavailableReasonUnknown": { - "message": "Biometric unlock is currently unavailable for an unknown reason." + "message": "El desbloqueig per dades biomètriques no està disponible ara per motius desconeguts." }, "itemDetails": { "message": "Detalls de l'element" @@ -3707,19 +3724,19 @@ "message": "Denega" }, "sshkeyApprovalTitle": { - "message": "Confirm SSH key usage" + "message": "Confirma l'ús de la clau SSH" }, "agentForwardingWarningTitle": { - "message": "Warning: Agent Forwarding" + "message": "Advertència: Reenviament de l'Agent" }, "agentForwardingWarningText": { - "message": "This request comes from a remote device that you are logged into" + "message": "Aquesta petició ve d'un dispositiu remot on teniu iniciada la sessió" }, "sshkeyApprovalMessageInfix": { - "message": "is requesting access to" + "message": "sol·licita accés a" }, "sshkeyApprovalMessageSuffix": { - "message": "in order to" + "message": "per" }, "sshActionLogin": { "message": "authenticate to a server" @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index 8c725808a98..a21f9b9258e 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopírovat ověřovací kód (TOTP)" }, + "copyFieldCipherName": { + "message": "Kopírovat $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Délka" }, @@ -1425,6 +1439,9 @@ "message": "Kopírovat bezpečnostní kód", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "číslo karty" + }, "premiumMembership": { "message": "Prémiové členství" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Povolit zkratku automatického psaní" + }, + "enableAutotypeDescription": { + "message": "Bitwarden neověřuje umístění vstupu. Před použitím zkratky se ujistěte, že jste ve správném okně a poli." } } diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index 3b3afba9415..e3db70bf152 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index cf60c7a04cb..47df4e98b3f 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiér bekræftelseskode (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Længde" }, @@ -1425,6 +1439,9 @@ "message": "Kopiér bekræftelseskode", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium-medlemskab" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 6e2b172b97c..1f60be15374 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Verifizierungscode (TOTP) kopieren" }, + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ kopieren", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Länge" }, @@ -1425,6 +1439,9 @@ "message": "Sicherheitscode kopieren", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "Kartennummer" + }, "premiumMembership": { "message": "Premium-Mitgliedschaft" }, @@ -2408,13 +2425,13 @@ "message": "Dein Master-Passwort entspricht nicht einer oder mehreren Richtlinien deiner Organisation. Um auf den Tresor zugreifen zu können, musst du dein Master-Passwort jetzt aktualisieren. Wenn du fortfährst, wirst du von deiner aktuellen Sitzung abgemeldet und musst dich erneut anmelden. Aktive Sitzungen auf anderen Geräten können noch bis zu einer Stunde lang aktiv bleiben." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Nachdem du dein Passwort geändert hast, musst du dich mit deinem neuen Passwort anmelden. Aktive Sitzungen auf anderen Geräten werden innerhalb einer Stunde abgemeldet." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Ändere dein Master-Passwort, um die Kontowiederherstellung abzuschließen." }, "updateMasterPasswordSubtitle": { - "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + "message": "Dein Master-Passwort entspricht nicht den Anforderungen dieser Organisation. Ändere dein Master-Passwort, um fortzufahren." }, "tdeDisabledMasterPasswordRequired": { "message": "Deine Organisation hat die vertrauenswürdige Geräteverschlüsselung deaktiviert. Bitte lege ein Master-Passwort fest, um auf deinen Tresor zuzugreifen." @@ -3154,10 +3171,10 @@ "message": "Admin-Genehmigung anfragen" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "Anmeldung kann nicht abgeschlossen werden" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Du musst dich auf einem vertrauenswürdigen Gerät anmelden oder deinem Administrator bitten, dir ein Passwort zuzuweisen." }, "region": { "message": "Region" @@ -3551,27 +3568,27 @@ "description": "Label indicating the most common import formats" }, "uriMatchDefaultStrategyHint": { - "message": "URI match detection is how Bitwarden identifies autofill suggestions.", + "message": "Die URI-Übereinstimmungserkennung ist die Methode, mit der Bitwarden Auto-Ausfüllen-Vorschläge erkennt.", "description": "Explains to the user that URI match detection determines how Bitwarden suggests autofill options, and clarifies that this default strategy applies when no specific match detection is set for a login item." }, "regExAdvancedOptionWarning": { - "message": "\"Regular expression\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Regulärer Ausdruck\" ist eine erweiterte Option mit erhöhtem Risiko der Kompromittierung von Zugangsdaten.", "description": "Content for dialog which warns a user when selecting 'regular expression' matching strategy as a cipher match strategy" }, "startsWithAdvancedOptionWarning": { - "message": "\"Starts with\" is an advanced option with increased risk of exposing credentials.", + "message": "\"Beginnt mit\" ist eine erweiterte Option mit erhöhtem Risiko der Kompromittierung von Zugangsdaten.", "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "Mehr über die Übereinstimmungs-Erkennung", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Erweiterte Optionen", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "Warnung", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Auto-Schreiben Tastenkombination aktivieren" + }, + "enableAutotypeDescription": { + "message": "Bitwarden überprüft die Eingabestellen nicht. Vergewissere dich, dass du dich im richtigen Fenster und Feld befindest, bevor du die Tastenkombination verwendest." } } diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 239351d406d..2f2a3cf914c 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Αντιγραφή κωδικού επαλήθευσης (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Μήκος" }, @@ -1425,6 +1439,9 @@ "message": "Αντιγραφή κωδικού ασφαλείας", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Συνδρομή Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 1ad0dcf308f..e5e6dcb2882 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -1813,9 +1813,6 @@ "unlockWithWindowsHello": { "message": "Unlock with Windows Hello" }, - "additionalWindowsHelloSettings": { - "message": "Additional Windows Hello settings" - }, "unlockWithPolkit": { "message": "Unlock with system authentication" }, @@ -1831,12 +1828,6 @@ "touchIdConsentMessage": { "message": "unlock your vault" }, - "autoPromptWindowsHello": { - "message": "Ask for Windows Hello on app start" - }, - "autoPromptPolkit": { - "message": "Ask for system authentication on launch" - }, "autoPromptTouchId": { "message": "Ask for Touch ID on app start" }, @@ -1846,9 +1837,6 @@ "requirePasswordWithoutPinOnStart": { "message": "Require password on app start" }, - "recommendedForSecurity": { - "message": "Recommended for security." - }, "lockWithMasterPassOnRestart1": { "message": "Lock with master password on restart" }, diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index 57ada476677..f73e373d825 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 6c9d211bf13..ee0e0dc276f 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy Verification Code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 26e6aefb83c..5bfde4d51c0 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopii la kontrolan kodon (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Longo" }, @@ -1425,6 +1439,9 @@ "message": "Kopii sekurigan kodon", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index eb02eca59ba..f839e9c8634 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -190,7 +190,7 @@ "message": "Clave pública" }, "sshFingerprint": { - "message": "Fingerprint" + "message": "Huella digital" }, "sshKeyAlgorithm": { "message": "Tipo de clave" @@ -229,7 +229,7 @@ "message": "Por favor, desbloquea tu caja fuerte para aprobar la solicitud de clave SSH." }, "sshAgentUnlockTimeout": { - "message": "SSH key request timed out." + "message": "La solicitud de clave SSH ha expirado." }, "enableSshAgent": { "message": "Habilitar agente SSH" @@ -244,7 +244,7 @@ "message": "Solicitar autorización al usar el agente SSH" }, "sshAgentPromptBehaviorDesc": { - "message": "Choose how to handle SSH-agent authorization requests." + "message": "Elige como gestionar las solicitudes de autorización del agente SSH." }, "sshAgentPromptBehaviorHelp": { "message": "Recordar autorizaciones SSH" @@ -467,7 +467,7 @@ "message": "Use checkboxes if you'd like to autofill a form's checkbox, like a remember email" }, "linkedHelpText": { - "message": "Use a linked field when you are experiencing autofill issues for a specific website." + "message": "Usa un campo enlazado cuando estés experimentando problemas de autocompletado para un sitio web específico." }, "linkedLabelHelpText": { "message": "Enter the the field's html id, name, aria-label, or placeholder." @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copiar código de verificación (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Longitud" }, @@ -1022,7 +1036,7 @@ "message": "Tiempo de autenticación agotado" }, "authenticationSessionTimedOut": { - "message": "The authentication session timed out. Please restart the login process." + "message": "La sesión de autenticación ha expirado. Por favor, inicia de nuevo el proceso de inicio de sesión." }, "selfHostBaseUrl": { "message": "URL del servidor autoalojado", @@ -1425,6 +1439,9 @@ "message": "Copiar código de seguridad", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Membresía Premium" }, @@ -2393,7 +2410,7 @@ "message": "Esta acción está protegida. Para continuar, vuelva a introducir su contraseña maestra para verificar su identidad." }, "masterPasswordSuccessfullySet": { - "message": "Master password successfully set" + "message": "Contraseña maestra establecida correctamente" }, "updatedMasterPassword": { "message": "Contraseña maestra actualizada" @@ -2408,13 +2425,13 @@ "message": "Tu contraseña maestra no cumple con una o más de las políticas de tu organización. Para acceder a la caja fuerte, debes actualizar tu contraseña maestra ahora. Proceder te desconectará de tu sesión actual, requiriendo que vuelva a iniciar sesión. Las sesiones activas en otros dispositivos pueden seguir estando activas durante hasta una hora." }, "changePasswordWarning": { - "message": "After changing your password, you will need to log in with your new password. Active sessions on other devices will be logged out within one hour." + "message": "Tras cambiar tu contraseña tendrás que iniciar sesión con tu nueva contraseña. Las sesiones activas en otros dispositivos se cerrarán en una hora." }, "accountRecoveryUpdateMasterPasswordSubtitle": { - "message": "Change your master password to complete account recovery." + "message": "Cambia tu contraseña maestra para completar la recuperación de la cuenta." }, "updateMasterPasswordSubtitle": { - "message": "Your master password does not meet this organization’s requirements. Change your master password to continue." + "message": "Tu contraseña maestra no cumple con los requisitos de esta organización. Cambia tu contraseña maestra para continuar." }, "tdeDisabledMasterPasswordRequired": { "message": "Your organization has disabled trusted device encryption. Please set a master password to access your vault." @@ -2528,7 +2545,7 @@ "message": "Contraseña maestra eliminada." }, "removeMasterPasswordForOrganizationUserKeyConnector": { - "message": "A master password is no longer required for members of the following organization. Please confirm the domain below with your organization administrator." + "message": "Ya no es necesaria una contraseña maestra para los miembros de la siguiente organización. Por favor, confirma el dominio que aparece a continuación con el administrador de tu organización." }, "organizationName": { "message": "Nombre de la organización" @@ -2597,7 +2614,7 @@ } }, "exportingIndividualVaultWithAttachmentsDescription": { - "message": "Only the individual vault items including attachments associated with $EMAIL$ will be exported. Organization vault items will not be included", + "message": "Solo los elementos individuales de la caja fuerte, incluyendo adjuntos asociados a $EMAIL$, serán exportados. Los elementos de la caja fuerte de la organización no se incluirán", "placeholders": { "email": { "content": "$1", @@ -2954,7 +2971,7 @@ "message": "aplicación web" }, "notificationSentDevicePart2": { - "message": "Make sure the Fingerprint phrase matches the one below before approving." + "message": "Asegúrate de que la frase de la Huella digital coincide con la siguiente antes de aprobar." }, "needAnotherOptionV1": { "message": "¿Necesitas otra opción?" @@ -3154,10 +3171,10 @@ "message": "Solicitar aprobación del administrador" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "No se puede completar el inicio de sesión" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { - "message": "You need to log in on a trusted device or ask your administrator to assign you a password." + "message": "Necesitas iniciar sesión en un dispositivo de confianza o pedir a tu administrador que te asigne una contraseña." }, "region": { "message": "Región" @@ -3212,10 +3229,10 @@ "message": "La organización no es de confianza" }, "emergencyAccessTrustWarning": { - "message": "For the security of your account, only confirm if you have granted emergency access to this user and their fingerprint matches what is displayed in their account" + "message": "Por la seguridad de tu cuenta, confirma únicamente si has otorgado acceso de emergencia a este usuario y que su huella digital coincida con la mostrada en su cuenta" }, "orgTrustWarning": { - "message": "For the security of your account, only proceed if you are a member of this organization, have account recovery enabled, and the fingerprint displayed below matches the organization's fingerprint." + "message": "Por la seguridad de tu cuenta, procede únicamente si eres un miembro de esta organización, tienes la recuperación de la cuenta activada y la huella digital mostrada a continuación coincide con la huella digital de la organización." }, "orgTrustWarning1": { "message": "This organization has an Enterprise policy that will enroll you in account recovery. Enrollment will allow organization administrators to change your password. Only proceed if you recognize this organization and the fingerprint phrase displayed below matches the organization's fingerprint." @@ -3567,11 +3584,11 @@ "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { - "message": "Advanced options", + "message": "Opciones avanzadas", "description": "Advanced option placeholder for uri option component" }, "warningCapitalized": { - "message": "Warning", + "message": "Advertencia", "description": "Warning (should maintain locale-relevant capitalization)" }, "success": { @@ -3764,7 +3781,7 @@ "message": "Actualización de la extensión requerida" }, "updateBrowserOrDisableFingerprintDialogMessage": { - "message": "The browser extension you are using is out of date. Please update it or disable browser integration fingerprint validation in the desktop app settings." + "message": "La extensión del navegador que estás utilizando está desactualizada. Por favor, actualízala o desactiva la integración del navegador de la validación de la huella digital en los ajustes de la aplicación de escritorio." }, "changeAtRiskPassword": { "message": "Cambiar contraseña en riesgo" @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Activar atajo de autoescritura" + }, + "enableAutotypeDescription": { + "message": "Bitwarden no valida las ubicaciones de entrada, asegúrate de que estás en la ventana y en el capo correctos antes de usar el atajo." } } diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index 4b848d9ef5c..be7628d2d34 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopeeri Kinnituskood (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Pikkus" }, @@ -1425,6 +1439,9 @@ "message": "Kopeeri turvakood", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Preemium versioon" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index aae6880294d..0c4b2f4d836 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiatu egiaztatze-kodea (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Luzera" }, @@ -1425,6 +1439,9 @@ "message": "Kopiatu segurtasun-kodea", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium bazkidea" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 4b9696887be..8aefda20bf4 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "کپی کد تأیید (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "طول" }, @@ -1425,6 +1439,9 @@ "message": "کپی کد امنیتی", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "عضویت پرمیوم" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index 6c13f322aca..b334bc61ece 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopioi todennuskoodi (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Pituus" }, @@ -1425,6 +1439,9 @@ "message": "Kopioi turvakoodi", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium-jäsenyys" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index cfa39fd71f3..723d324bf70 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopyahin ang verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Kahabaan" }, @@ -1425,6 +1439,9 @@ "message": "Kopyahin ang code ng seguridad", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Pagiging miyembro ng premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index 387c25ec44c..b06308b2906 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copier le code de vérification (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Longueur" }, @@ -1425,6 +1439,9 @@ "message": "Copier le code de sécurité", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Adhésion Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index 304d07ee3cd..3d240ff77e8 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 11a736eeaaa..5b76be7fff3 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "העתקת קוד אימות (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "אורך" }, @@ -1425,6 +1439,9 @@ "message": "העתק קוד אבטחה", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "חברות פרימיום" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "הפעלת קיצור הקלדה אוטומטית" + }, + "enableAutotypeDescription": { + "message": "Bitwarden לא מאמת את מקומות הקלט, נא לוודא שזה החלון והשדה הנכונים בטרם שימוש בקיצור הדרך." } } diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 3d3a2c4d701..77b416118c9 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 699e4ad347d..b86e57a4811 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiraj kôd za provjeru (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Duljina" }, @@ -1425,6 +1439,9 @@ "message": "Kopiraj kontrolni broj", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium članstvo" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index cd30ee6edaa..0f5e14596d7 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Ellenőrző kód másolása (TOTP)" }, + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ másolása", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Hossz" }, @@ -1425,6 +1439,9 @@ "message": "Biztonsági kód másolása", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kártya szám" + }, "premiumMembership": { "message": "Prémium tagság" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Automatikus típusú parancsikon engedélyezése" + }, + "enableAutotypeDescription": { + "message": "A Bitwarden nem érvényesíti a beviteli helyeket, győződjünk meg róla, hogy a megfelelő ablakban és mezőben vagyunk, mielőtt a parancsikont használnánk." } } diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 0634ad80722..f4627f805e0 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Salin Kode Verifikasi (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Panjang" }, @@ -1425,6 +1439,9 @@ "message": "Salin Kode Keamanan", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Keanggotaan Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index 0476024f926..b89b25a745c 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copia codice di verifica (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lunghezza" }, @@ -1425,6 +1439,9 @@ "message": "Copia codice di sicurezza", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Abbonamento Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 7b8eddc693b..19a91367567 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "認証コード (TOTP) をコピー" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "長さ" }, @@ -1425,6 +1439,9 @@ "message": "セキュリティコードのコピー", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "プレミアム会員" }, @@ -3680,25 +3697,25 @@ "message": "生体認証によるロック解除は、不明な理由により現在利用できません。" }, "itemDetails": { - "message": "Item details" + "message": "アイテムの詳細" }, "itemName": { - "message": "Item name" + "message": "アイテム名" }, "loginCredentials": { - "message": "Login credentials" + "message": "ログイン資格情報" }, "additionalOptions": { - "message": "Additional options" + "message": "追加のオプション" }, "itemHistory": { - "message": "Item history" + "message": "アイテムの履歴" }, "lastEdited": { - "message": "Last edited" + "message": "直近の編集" }, "upload": { - "message": "Upload" + "message": "アップロード" }, "authorize": { "message": "認可" @@ -3782,10 +3799,10 @@ "message": "移動" }, "newFolder": { - "message": "New folder" + "message": "新しいフォルダー" }, "folderName": { - "message": "Folder Name" + "message": "フォルダー名" }, "folderHintText": { "message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums" @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index 7b98da76026..5f9d2fe17b3 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "სიგრძე" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index 304d07ee3cd..3d240ff77e8 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 8a1798ce386..b7664ad90bf 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "ನಕಲಿಸಿ ಪರಿಶೀಲನೆ ಕೋಡ್ (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "ಉದ್ದ" }, @@ -1425,6 +1439,9 @@ "message": "ಭದ್ರತಾ ಕೋಡ್ ಅನ್ನು ನಕಲಿಸಿ", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "ಪ್ರೀಮಿಯಂ ಸದಸ್ಯತ್ವ" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index 9127f4f76a9..ca23d5107c7 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "인증 코드 (TOTP) 복사" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "길이" }, @@ -1425,6 +1439,9 @@ "message": "보안 코드 복사", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "프리미엄 멤버십" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 84e5a9d36a6..99c63ab4dab 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopijuoti patvirtinimo kodą (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Ilgis" }, @@ -1425,6 +1439,9 @@ "message": "Kopijuoti saugos kodą", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium narystė" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index d1bf2382e58..0849bf29b45 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Ievietot Apliecinājuma kodu (TOTP) starpliktuvē" }, + "copyFieldCipherName": { + "message": "Ievietot starpliktuvē $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Garums" }, @@ -1425,6 +1439,9 @@ "message": "Ievietot drošības kodu starpliktuvē", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kartes numurs" + }, "premiumMembership": { "message": "Premium dalība" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Iespējot automātiskās ievades saīsni" + }, + "enableAutotypeDescription": { + "message": "Bitwarden nepārbauda ievades atrašanās vietas, jāpārliecinās, ka atrodies pareizajā logā un laukā, pirms saīsnes izmantošanas." } } diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 98794eed175..0929250c06f 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Iskopiraj Verifikacioni Kod (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Dužina" }, @@ -1425,6 +1439,9 @@ "message": "Kopiraj siguronosni kod", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premijum članstvo" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 9cb27605db5..a77ab04c0aa 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "ദൈര്‍ഘ്യം" }, @@ -1425,6 +1439,9 @@ "message": "സുരക്ഷാ കോഡ് പകർത്തുക", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "പ്രീമിയം അംഗത്വം" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index 304d07ee3cd..3d240ff77e8 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index 4629ba25d93..b09ea6cdbf2 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index 53125c8e290..dfa381fc3d0 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopier verifiseringskode (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lengde" }, @@ -1425,6 +1439,9 @@ "message": "Kopier sikkerhetskoden", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium-medlemskap" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index 8ea29998406..56ccc79775c 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "प्रमाणीकरण कोड (TOTP) प्रतिलिपि गर्नुहोस्" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "लम्बाइ" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 90669dd1c93..5301982ecdc 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Verificatiecode kopiëren (TOTP)" }, + "copyFieldCipherName": { + "message": "$FIELD$, $CIPHERNAME$ kopiëren", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lengte" }, @@ -1425,6 +1439,9 @@ "message": "Beveiligingscode kopiëren", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kaartnummer" + }, "premiumMembership": { "message": "Premium-abonnement" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Snelkoppeling autotype inschakelen" + }, + "enableAutotypeDescription": { + "message": "Bitwarden valideert de invoerlocaties niet, zorg ervoor dat je je in het juiste venster en veld bevindt voordat je de snelkoppeling gebruikt." } } diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index af6a64710a7..4c86afccbeb 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopier verifiseringskoden (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lengd" }, @@ -1425,6 +1439,9 @@ "message": "Kopier tryggleikskode", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium-tinging" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index 3ce27e673b7..6db35fd307e 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index b09bc908c47..9852c85554a 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiuj kod weryfikacyjny (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Długość" }, @@ -1425,6 +1439,9 @@ "message": "Kopiuj kod zabezpieczający", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Konto Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index ab65e0a4912..5e570920f55 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copiar Código de Verificação (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Comprimento" }, @@ -1425,6 +1439,9 @@ "message": "Copiar Código de Segurança", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Assinatura Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 2b5d7e00f61..d3764bad580 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copiar código de verificação (TOTP)" }, + "copyFieldCipherName": { + "message": "Copiar $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Comprimento" }, @@ -1425,6 +1439,9 @@ "message": "Copiar código de segurança", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "número do cartão" + }, "premiumMembership": { "message": "Subscrição Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Ativar o atalho de introdução automática" + }, + "enableAutotypeDescription": { + "message": "O Bitwarden não valida a introdução de localizações. Certifique-se de que está na janela e no campo corretos antes de utilizar o atalho." } } diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index e3608836d26..41a92900d63 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copiere cod de verificare (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Lungime" }, @@ -1425,6 +1439,9 @@ "message": "Copiere cod de securitate", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Abonament Premium" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 8991d3dacb0..b87ffc3cbcd 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Скопировать код подтверждения (TOTP)" }, + "copyFieldCipherName": { + "message": "Копировать $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Длина" }, @@ -1425,6 +1439,9 @@ "message": "Скопировать код безопасности", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "номер карты" + }, "premiumMembership": { "message": "Премиум" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Включить автоввод ярлыка" + }, + "enableAutotypeDescription": { + "message": "Bitwarden не проверяет местоположение ввода, поэтому, прежде чем использовать ярлык, убедитесь, что вы находитесь в нужном окне и поле." } } diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index b50d0252f61..5567654af99 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index 383e35f2826..49651fbcb7e 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopírovať overovací kód (TOTP)" }, + "copyFieldCipherName": { + "message": "Kopírovať $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Dĺžka" }, @@ -1425,6 +1439,9 @@ "message": "Kopírovať bezpečnostný kód", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "číslo karty" + }, "premiumMembership": { "message": "Prémiové členstvo" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Povoliť skratku automatického písania" + }, + "enableAutotypeDescription": { + "message": "Bitwarden neoveruje miesto stupu, pred použitím skratky sa uistite, že ste v správnom okne a poli." } } diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index db25a4623ee..23bbae2d523 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiraj verifikacijsko kodo (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Dolžina" }, @@ -1425,6 +1439,9 @@ "message": "Kopiraj varnostno kodo", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium članstvo" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 514276fb136..c69b4ca8340 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Копирај потврдни код (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Дужина" }, @@ -1425,6 +1439,9 @@ "message": "Копирај сигурносни код", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Премијум чланство" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index 20140cb7ae0..54fb7f1f643 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Kopiera verifieringskod (TOTP)" }, + "copyFieldCipherName": { + "message": "Kopiera $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Längd" }, @@ -1425,6 +1439,9 @@ "message": "Kopiera säkerhetskod", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kortnummer" + }, "premiumMembership": { "message": "Premium-medlemskap" }, @@ -1489,7 +1506,7 @@ "message": "Lösenordshistorik" }, "generatorHistory": { - "message": "Generatorns historia" + "message": "Generatorns historik" }, "clearGeneratorHistoryTitle": { "message": "Rensa generatorhistorik" @@ -3333,10 +3350,10 @@ "message": "Nyckel" }, "passkeyNotCopied": { - "message": "Nyckeln kommer inte att kopieras" + "message": "Inloggningsnyckeln kommer inte att kopieras" }, "passkeyNotCopiedAlert": { - "message": "Nyckeln kommer inte att kopieras till det klonade objektet. Vill du klona det här objektet?" + "message": "Inloggningsnyckeln kommer inte att kopieras till det klonade objektet. Vill du klona det här objektet?" }, "aliasDomain": { "message": "Aliasdomän" @@ -3587,10 +3604,10 @@ "message": "Inaktivera hårdvaruacceleration och starta om" }, "removePasskey": { - "message": "Ta bort nyckel" + "message": "Ta bort inloggningsnyckel" }, "passkeyRemoved": { - "message": "Nyckel borttagen" + "message": "Inloggningsnyckel borttagen" }, "errorAssigningTargetCollection": { "message": "Fel vid tilldelning av målsamling." @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Aktivera genväg för automatisk inmatning" + }, + "enableAutotypeDescription": { + "message": "Bitwarden validerar inte inmatningsplatser, så se till att du är i rätt fönster och fält innan du använder genvägen." } } diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index 304d07ee3cd..3d240ff77e8 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Copy verification code (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Length" }, @@ -1425,6 +1439,9 @@ "message": "Copy security code", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index 678346257f2..031c9bb6364 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "คัดลอกรหัสยืนยัน (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "ความยาว" }, @@ -1425,6 +1439,9 @@ "message": "คัดลอกรหัสรักษาความปลอดภัย", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Premium Membership" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 255f03025d0..b95c585c28f 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Doğrulama kodunu kopyala (TOTP)" }, + "copyFieldCipherName": { + "message": "Kopyala: $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Uzunluk" }, @@ -1425,6 +1439,9 @@ "message": "Güvenlik kodunu kopyala", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "kart numarası" + }, "premiumMembership": { "message": "Premium üyelik" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index 649b3af622f..724959446d6 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Копіювати код підтвердження (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Довжина" }, @@ -1425,6 +1439,9 @@ "message": "Копіювати код безпеки", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "card number" + }, "premiumMembership": { "message": "Преміум статус" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 42246285f80..d0ff3cca7bc 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "Sao chép mã xác thực (TOTP)" }, + "copyFieldCipherName": { + "message": "Sao chép $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "Độ dài" }, @@ -1425,6 +1439,9 @@ "message": "Sao chép mã bảo mật", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "số thẻ" + }, "premiumMembership": { "message": "Thành viên Cao Cấp" }, @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Bật phím tắt tự động điền" + }, + "enableAutotypeDescription": { + "message": "Bitwarden không kiểm tra vị trí nhập liệu, hãy đảm bảo bạn đang ở trong đúng cửa sổ và trường nhập liệu trước khi dùng phím tắt." } } diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 75d8925c4f7..c0bb7e0f0d3 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "复制验证码 (TOTP)" }, + "copyFieldCipherName": { + "message": "复制 $FIELD$、$CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "长度" }, @@ -1425,6 +1439,9 @@ "message": "复制安全码", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "卡号" + }, "premiumMembership": { "message": "高级会员" }, @@ -3154,7 +3171,7 @@ "message": "请求管理员批准" }, "unableToCompleteLogin": { - "message": "Unable to complete login" + "message": "无法完成登录" }, "loginOnTrustedDeviceOrAskAdminToAssignPassword": { "message": "You need to log in on a trusted device or ask your administrator to assign you a password." @@ -3563,7 +3580,7 @@ "description": "Content for dialog which warns a user when selecting 'starts with' matching strategy as a cipher match strategy" }, "uriMatchWarningDialogLink": { - "message": "More about match detection", + "message": "更多关于匹配检测", "description": "Link to match detection docs on warning dialog for advance match strategy" }, "uriAdvancedOption": { @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "启用自动类型快捷方式" + }, + "enableAutotypeDescription": { + "message": "Bitwarden 不验证输入位置,请确保您在使用快捷键之前在正确的窗口和字段中。" } } diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 88762ea9260..c2253c56760 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -24,7 +24,7 @@ "message": "身分" }, "typeNote": { - "message": "Note" + "message": "備註" }, "typeSecureNote": { "message": "安全筆記" @@ -241,22 +241,22 @@ "message": "SSH代理是一個針對開發者的服務,它能夠直接從 Bitwarden 密碼庫簽發SSH請求。" }, "sshAgentPromptBehavior": { - "message": "Ask for authorization when using SSH agent" + "message": "使用 SSH 代理程式時要求授權" }, "sshAgentPromptBehaviorDesc": { - "message": "Choose how to handle SSH-agent authorization requests." + "message": "選擇如何處理 SSH 代理程式的授權要求。" }, "sshAgentPromptBehaviorHelp": { - "message": "Remember SSH authorizations" + "message": "記住 SSH 授權" }, "sshAgentPromptBehaviorAlways": { - "message": "Always" + "message": "總是" }, "sshAgentPromptBehaviorNever": { - "message": "Never" + "message": "永不" }, "sshAgentPromptBehaviorRememberUntilLock": { - "message": "Remember until vault is locked" + "message": "記住直到密碼庫鎖定為止" }, "premiumRequired": { "message": "需要進階會員資格" @@ -409,16 +409,16 @@ "message": "驗證器金鑰 (TOTP)" }, "authenticatorKey": { - "message": "Authenticator key" + "message": "驗證器金鑰" }, "autofillOptions": { - "message": "Autofill options" + "message": "自動填入選項" }, "websiteUri": { - "message": "Website (URI)" + "message": "網站 (URI)" }, "websiteUriCount": { - "message": "Website (URI) $COUNT$", + "message": "網站 (URI) $COUNT$ 個", "description": "Label for an input field that contains a website URI. The input field is part of a list of fields, and the count indicates the position of the field in the list.", "placeholders": { "count": { @@ -428,43 +428,43 @@ } }, "websiteAdded": { - "message": "Website added" + "message": "已新增網站" }, "addWebsite": { - "message": "Add website" + "message": "新增網站" }, "deleteWebsite": { - "message": "Delete website" + "message": "刪除網站" }, "owner": { - "message": "Owner" + "message": "擁有者" }, "addField": { - "message": "Add field" + "message": "新增欄位" }, "editField": { - "message": "Edit field" + "message": "編輯欄位" }, "permanentlyDeleteAttachmentConfirmation": { - "message": "Are you sure you want to permanently delete this attachment?" + "message": "你確定要永久刪除此附件嗎?" }, "fieldType": { - "message": "Field type" + "message": "欄位類別" }, "fieldLabel": { - "message": "Field label" + "message": "欄位標籤" }, "add": { - "message": "Add" + "message": "新增" }, "textHelpText": { - "message": "Use text fields for data like security questions" + "message": "像安全問題之類的資料 請使用文本框" }, "hiddenHelpText": { - "message": "Use hidden fields for sensitive data like a password" + "message": "敏感資料 如同密碼 使用隱藏字段" }, "checkBoxHelpText": { - "message": "Use checkboxes if you'd like to autofill a form's checkbox, like a remember email" + "message": "如果您想自動填充表單的復選框,例如「記住電子郵件」,請使用復選框" }, "linkedHelpText": { "message": "Use a linked field when you are experiencing autofill issues for a specific website." @@ -572,6 +572,20 @@ "copyVerificationCodeTotp": { "message": "複製驗證碼 (TOTP)" }, + "copyFieldCipherName": { + "message": "Copy $FIELD$, $CIPHERNAME$", + "description": "Title for a button that copies a field value to the clipboard.", + "placeholders": { + "field": { + "content": "$1", + "example": "Username" + }, + "ciphername": { + "content": "$2", + "example": "Login Item" + } + } + }, "length": { "message": "長度" }, @@ -734,10 +748,10 @@ "message": "Enter the code sent to your email" }, "enterTheCodeFromYourAuthenticatorApp": { - "message": "Enter the code from your authenticator app" + "message": "請輸入您驗證器應用程式中的代碼" }, "pressYourYubiKeyToAuthenticate": { - "message": "Press your YubiKey to authenticate" + "message": "請輕觸您的 YubiKey 以進行驗證" }, "logInWithPasskey": { "message": "以通行密鑰 (passkey) 登入" @@ -792,7 +806,7 @@ "message": "主密碼提示" }, "passwordStrengthScore": { - "message": "Password strength score $SCORE$", + "message": "密碼強度分數 $SCORE$", "placeholders": { "score": { "content": "$1", @@ -907,7 +921,7 @@ "message": "驗證已被取消或時間過長。請再試一次。" }, "openInNewTab": { - "message": "Open in new tab" + "message": "在新分頁開啟" }, "invalidVerificationCode": { "message": "無效的驗證碼" @@ -925,14 +939,14 @@ } }, "dontAskAgainOnThisDeviceFor30Days": { - "message": "Don't ask again on this device for 30 days" + "message": "30 天內不要再於這部裝置上詢問" }, "selectAnotherMethod": { - "message": "Select another method", + "message": "選擇其他方法", "description": "Select another two-step login method" }, "useYourRecoveryCode": { - "message": "Use your recovery code" + "message": "使用您的復原碼" }, "insertU2f": { "message": "將您的安全鑰匙插入電腦的 USB 連接埠,然後觸摸其按鈕(如有的話)。" @@ -965,13 +979,13 @@ "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "verifyYourIdentity": { - "message": "Verify your Identity" + "message": "驗證您的身分" }, "weDontRecognizeThisDevice": { - "message": "We don't recognize this device. Enter the code sent to your email to verify your identity." + "message": "我們無法辨識這部裝置。請輸入傳送到您電子郵件的驗證碼,以驗證您的身分。" }, "continueLoggingIn": { - "message": "Continue logging in" + "message": "繼續登入" }, "webAuthnTitle": { "message": "FIDO2 WebAuthn" @@ -998,7 +1012,7 @@ "message": "兩步驟登入選項" }, "selectTwoStepLoginMethod": { - "message": "Select two-step login method" + "message": "選取兩步驟登入方式" }, "selfHostedEnvironment": { "message": "自我裝載環境" @@ -1056,7 +1070,7 @@ "message": "否" }, "location": { - "message": "Location" + "message": "位置" }, "overwritePassword": { "message": "覆寫密碼" @@ -1425,6 +1439,9 @@ "message": "複製安全代碼", "description": "Copy credit card security code (CVV)" }, + "cardNumber": { + "message": "信用卡號碼" + }, "premiumMembership": { "message": "進階會員" }, @@ -1717,10 +1734,10 @@ "message": "帳戶已限制" }, "restrictCardTypeImport": { - "message": "Cannot import card item types" + "message": "無法匯入卡片項目類別" }, "restrictCardTypeImportDesc": { - "message": "A policy set by 1 or more organizations prevents you from importing cards to your vaults." + "message": "由於一或多個組織設有政策,您無法匯入卡片至您的保險庫。" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { "message": "「檔案密碼」與「確認檔案密碼」不一致。" @@ -3997,5 +4014,11 @@ } } } + }, + "enableAutotype": { + "message": "Enable autotype shortcut" + }, + "enableAutotypeDescription": { + "message": "Bitwarden does not validate input locations, be sure you are in the right window and field before using the shortcut." } } diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 8c92131617a..9b5aa0b31e9 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -12,6 +12,7 @@ import { AccountServiceImplementation } from "@bitwarden/common/auth/services/ac import { ClientType } from "@bitwarden/common/enums"; import { EncryptServiceImplementation } from "@bitwarden/common/key-management/crypto/services/encrypt.service.implementation"; import { RegionConfig } from "@bitwarden/common/platform/abstractions/environment.service"; +import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; import { Message, MessageSender } from "@bitwarden/common/platform/messaging"; // eslint-disable-next-line no-restricted-imports -- For dependency creation import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal"; @@ -58,6 +59,7 @@ import { EphemeralValueStorageService } from "./platform/services/ephemeral-valu import { I18nMainService } from "./platform/services/i18n.main.service"; import { SSOLocalhostCallbackService } from "./platform/services/sso-localhost-callback.service"; import { ElectronMainMessagingService } from "./services/electron-main-messaging.service"; +import { MainSdkLoadService } from "./services/main-sdk-load-service"; import { isMacAppStore } from "./utils"; export class Main { @@ -88,6 +90,7 @@ export class Main { desktopAutofillSettingsService: DesktopAutofillSettingsService; versionMain: VersionMain; sshAgentService: MainSshAgentService; + sdkLoadService: SdkLoadService; mainDesktopAutotypeService: MainDesktopAutotypeService; constructor() { @@ -144,6 +147,8 @@ export class Main { this.i18nService = new I18nMainService("en", "./locales/", globalStateProvider); + this.sdkLoadService = new MainSdkLoadService(); + this.mainCryptoFunctionService = new NodeCryptoFunctionService(); const stateEventRegistrarService = new StateEventRegistrarService( @@ -196,6 +201,16 @@ export class Main { this.logService, true, ); + + this.windowMain = new WindowMain( + biometricStateService, + this.logService, + this.storageService, + this.desktopSettingsService, + (arg) => this.processDeepLink(arg), + (win) => this.trayMain.setupWindowListeners(win), + ); + this.biometricsService = new MainBiometricsService( this.i18nService, this.windowMain, @@ -206,14 +221,6 @@ export class Main { this.mainCryptoFunctionService, ); - this.windowMain = new WindowMain( - biometricStateService, - this.logService, - this.storageService, - this.desktopSettingsService, - (arg) => this.processDeepLink(arg), - (win) => this.trayMain.setupWindowListeners(win), - ); this.messagingMain = new MessagingMain(this, this.desktopSettingsService); this.updaterMain = new UpdaterMain(this.i18nService, this.windowMain); @@ -386,6 +393,8 @@ export class Main { this.windowMain.win.on("minimize", () => { this.messagingService.send("windowHidden"); }); + + await this.sdkLoadService.loadAndInit(); }, (e: any) => { this.logService.error("Error while running migrations:", e); diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 2cc106d07b0..01872408a10 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/desktop", - "version": "2025.7.1", + "version": "2025.7.0", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 8457cb23f74..0128692f3b4 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -2,7 +2,7 @@ "name": "@bitwarden/desktop", "productName": "Bitwarden", "description": "A secure and free password manager for all of your devices.", - "version": "2025.7.1", + "version": "2025.7.0", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/apps/desktop/src/scss/base.scss b/apps/desktop/src/scss/base.scss index 494e91529ee..a95d82dacd4 100644 --- a/apps/desktop/src/scss/base.scss +++ b/apps/desktop/src/scss/base.scss @@ -66,7 +66,7 @@ a { } } -input:not(bit-form-field input), +input:not(bit-form-field input, input[bitcheckbox]), select, textarea:not(bit-form-field textarea) { @include themify($themes) { diff --git a/apps/desktop/src/services/main-sdk-load-service.ts b/apps/desktop/src/services/main-sdk-load-service.ts new file mode 100644 index 00000000000..847505f68fe --- /dev/null +++ b/apps/desktop/src/services/main-sdk-load-service.ts @@ -0,0 +1,9 @@ +import { SdkLoadService } from "@bitwarden/common/platform/abstractions/sdk/sdk-load.service"; +import * as sdk from "@bitwarden/sdk-internal"; + +export class MainSdkLoadService extends SdkLoadService { + async load(): Promise { + const module = await import("@bitwarden/sdk-internal/bitwarden_wasm_internal_bg.wasm"); + (sdk as any).init(module); + } +} diff --git a/apps/desktop/tsconfig.json b/apps/desktop/tsconfig.json index 7db3e84e451..70a59ad164c 100644 --- a/apps/desktop/tsconfig.json +++ b/apps/desktop/tsconfig.json @@ -3,5 +3,6 @@ "angularCompilerOptions": { "strictTemplates": true }, - "include": ["src", "../../libs/common/src/key-management/crypto/services/encrypt.worker.ts"] + "include": ["src", "../../libs/common/src/key-management/crypto/services/encrypt.worker.ts"], + "exclude": ["src/**/*.spec.ts"] } diff --git a/apps/desktop/webpack.main.js b/apps/desktop/webpack.main.js index 25a68d8c867..166fba95d52 100644 --- a/apps/desktop/webpack.main.js +++ b/apps/desktop/webpack.main.js @@ -65,6 +65,9 @@ const main = { }, ], }, + experiments: { + asyncWebAssembly: true, + }, plugins: [ new CopyWebpackPlugin({ patterns: [ diff --git a/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html b/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html index dc5d4c7929e..50d34227b56 100644 --- a/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html +++ b/apps/web/src/app/admin-console/organizations/collections/vault-header/vault-header.component.html @@ -25,62 +25,67 @@ - - - - + @if ( + collection != null && (canEditCollection || canDeleteCollection || canViewCollectionInfo) + ) { + + + + + + + + + + + - - - - - - - - - + + + } = {}) { + Object.assign(this, partial); + } + + static fromResponse(response: EmergencyAccessGranteeDetailsResponse) { + return new GranteeEmergencyAccess({ + id: response.id, + granteeId: response.granteeId, + name: response.name, + email: response.email, + type: response.type, + status: response.status, + waitTimeDays: response.waitTimeDays, + creationDate: response.creationDate, + avatarColor: response.avatarColor, + }); + } } export class GrantorEmergencyAccess { @@ -28,6 +50,24 @@ export class GrantorEmergencyAccess { waitTimeDays: number; creationDate: string; avatarColor: string; + + constructor(partial: Partial = {}) { + Object.assign(this, partial); + } + + static fromResponse(response: EmergencyAccessGrantorDetailsResponse) { + return new GrantorEmergencyAccess({ + id: response.id, + grantorId: response.grantorId, + name: response.name, + email: response.email, + type: response.type, + status: response.status, + waitTimeDays: response.waitTimeDays, + creationDate: response.creationDate, + avatarColor: response.avatarColor, + }); + } } export class TakeoverTypeEmergencyAccess { diff --git a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.spec.ts b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.spec.ts index 752e9dc1ce0..05373534ce7 100644 --- a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.spec.ts +++ b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.spec.ts @@ -22,9 +22,11 @@ import { KdfType, KeyService } from "@bitwarden/key-management"; import { EmergencyAccessStatusType } from "../enums/emergency-access-status-type"; import { EmergencyAccessType } from "../enums/emergency-access-type"; +import { GranteeEmergencyAccess, GrantorEmergencyAccess } from "../models/emergency-access"; import { EmergencyAccessPasswordRequest } from "../request/emergency-access-password.request"; import { EmergencyAccessGranteeDetailsResponse, + EmergencyAccessGrantorDetailsResponse, EmergencyAccessTakeoverResponse, } from "../response/emergency-access.response"; @@ -242,11 +244,19 @@ describe("EmergencyAccessService", () => { const mockEmergencyAccess = { data: [ - createMockEmergencyAccess("0", "EA 0", EmergencyAccessStatusType.Invited), - createMockEmergencyAccess("1", "EA 1", EmergencyAccessStatusType.Accepted), - createMockEmergencyAccess("2", "EA 2", EmergencyAccessStatusType.Confirmed), - createMockEmergencyAccess("3", "EA 3", EmergencyAccessStatusType.RecoveryInitiated), - createMockEmergencyAccess("4", "EA 4", EmergencyAccessStatusType.RecoveryApproved), + createMockEmergencyAccessGranteeDetails("0", "EA 0", EmergencyAccessStatusType.Invited), + createMockEmergencyAccessGranteeDetails("1", "EA 1", EmergencyAccessStatusType.Accepted), + createMockEmergencyAccessGranteeDetails("2", "EA 2", EmergencyAccessStatusType.Confirmed), + createMockEmergencyAccessGranteeDetails( + "3", + "EA 3", + EmergencyAccessStatusType.RecoveryInitiated, + ), + createMockEmergencyAccessGranteeDetails( + "4", + "EA 4", + EmergencyAccessStatusType.RecoveryApproved, + ), ], } as ListResponse; @@ -295,9 +305,113 @@ describe("EmergencyAccessService", () => { ).rejects.toThrow("New user key is required for rotation."); }); }); + + describe("getEmergencyAccessTrusted", () => { + it("should return an empty array if no emergency access is granted", async () => { + emergencyAccessApiService.getEmergencyAccessTrusted.mockResolvedValue({ + data: [], + } as ListResponse); + + const result = await emergencyAccessService.getEmergencyAccessTrusted(); + + expect(result).toEqual([]); + }); + + it("should return an empty array if the API returns an empty response", async () => { + emergencyAccessApiService.getEmergencyAccessTrusted.mockResolvedValue( + null as unknown as ListResponse, + ); + + const result = await emergencyAccessService.getEmergencyAccessTrusted(); + + expect(result).toEqual([]); + }); + + it("should return a list of trusted emergency access contacts", async () => { + const mockEmergencyAccess = [ + createMockEmergencyAccessGranteeDetails("1", "EA 1", EmergencyAccessStatusType.Invited), + createMockEmergencyAccessGranteeDetails("2", "EA 2", EmergencyAccessStatusType.Invited), + createMockEmergencyAccessGranteeDetails("3", "EA 3", EmergencyAccessStatusType.Accepted), + createMockEmergencyAccessGranteeDetails("4", "EA 4", EmergencyAccessStatusType.Confirmed), + createMockEmergencyAccessGranteeDetails( + "5", + "EA 5", + EmergencyAccessStatusType.RecoveryInitiated, + ), + ]; + emergencyAccessApiService.getEmergencyAccessTrusted.mockResolvedValue({ + data: mockEmergencyAccess, + } as ListResponse); + + const result = await emergencyAccessService.getEmergencyAccessTrusted(); + + expect(result).toHaveLength(mockEmergencyAccess.length); + + result.forEach((access, index) => { + expect(access).toBeInstanceOf(GranteeEmergencyAccess); + + expect(access.id).toBe(mockEmergencyAccess[index].id); + expect(access.name).toBe(mockEmergencyAccess[index].name); + expect(access.status).toBe(mockEmergencyAccess[index].status); + expect(access.type).toBe(mockEmergencyAccess[index].type); + }); + }); + }); + + describe("getEmergencyAccessGranted", () => { + it("should return an empty array if no emergency access is granted", async () => { + emergencyAccessApiService.getEmergencyAccessGranted.mockResolvedValue({ + data: [], + } as ListResponse); + + const result = await emergencyAccessService.getEmergencyAccessGranted(); + + expect(result).toEqual([]); + }); + + it("should return an empty array if the API returns an empty response", async () => { + emergencyAccessApiService.getEmergencyAccessGranted.mockResolvedValue( + null as unknown as ListResponse, + ); + + const result = await emergencyAccessService.getEmergencyAccessGranted(); + + expect(result).toEqual([]); + }); + + it("should return a list of granted emergency access contacts", async () => { + const mockEmergencyAccess = [ + createMockEmergencyAccessGrantorDetails("1", "EA 1", EmergencyAccessStatusType.Invited), + createMockEmergencyAccessGrantorDetails("2", "EA 2", EmergencyAccessStatusType.Invited), + createMockEmergencyAccessGrantorDetails("3", "EA 3", EmergencyAccessStatusType.Accepted), + createMockEmergencyAccessGrantorDetails("4", "EA 4", EmergencyAccessStatusType.Confirmed), + createMockEmergencyAccessGrantorDetails( + "5", + "EA 5", + EmergencyAccessStatusType.RecoveryInitiated, + ), + ]; + emergencyAccessApiService.getEmergencyAccessGranted.mockResolvedValue({ + data: mockEmergencyAccess, + } as ListResponse); + + const result = await emergencyAccessService.getEmergencyAccessGranted(); + + expect(result).toHaveLength(mockEmergencyAccess.length); + + result.forEach((access, index) => { + expect(access).toBeInstanceOf(GrantorEmergencyAccess); + + expect(access.id).toBe(mockEmergencyAccess[index].id); + expect(access.name).toBe(mockEmergencyAccess[index].name); + expect(access.status).toBe(mockEmergencyAccess[index].status); + expect(access.type).toBe(mockEmergencyAccess[index].type); + }); + }); + }); }); -function createMockEmergencyAccess( +function createMockEmergencyAccessGranteeDetails( id: string, name: string, status: EmergencyAccessStatusType, @@ -309,3 +423,16 @@ function createMockEmergencyAccess( emergencyAccess.status = status; return emergencyAccess; } + +function createMockEmergencyAccessGrantorDetails( + id: string, + name: string, + status: EmergencyAccessStatusType, +): EmergencyAccessGrantorDetailsResponse { + const emergencyAccess = new EmergencyAccessGrantorDetailsResponse({}); + emergencyAccess.id = id; + emergencyAccess.name = name; + emergencyAccess.type = 0; + emergencyAccess.status = status; + return emergencyAccess; +} diff --git a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts index 673ab7443f9..a814af32505 100644 --- a/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts +++ b/apps/web/src/app/auth/emergency-access/services/emergency-access.service.ts @@ -77,14 +77,22 @@ export class EmergencyAccessService * Gets all emergency access that the user has been granted. */ async getEmergencyAccessTrusted(): Promise { - return (await this.emergencyAccessApiService.getEmergencyAccessTrusted()).data; + const listResponse = await this.emergencyAccessApiService.getEmergencyAccessTrusted(); + if (!listResponse || listResponse.data.length === 0) { + return []; + } + return listResponse.data.map((response) => GranteeEmergencyAccess.fromResponse(response)); } /** * Gets all emergency access that the user has granted. */ async getEmergencyAccessGranted(): Promise { - return (await this.emergencyAccessApiService.getEmergencyAccessGranted()).data; + const listResponse = await this.emergencyAccessApiService.getEmergencyAccessGranted(); + if (!listResponse || listResponse.data.length === 0) { + return []; + } + return listResponse.data.map((response) => GrantorEmergencyAccess.fromResponse(response)); } /** diff --git a/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts b/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts index efd0055fb95..ff5156ba636 100644 --- a/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts +++ b/apps/web/src/app/billing/payment/components/change-payment-method-dialog.component.ts @@ -28,7 +28,11 @@ type DialogResult = {{ "changePaymentMethod" | i18n }}
- +
diff --git a/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts b/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts index 4f5b2e3b15c..b73c3297e9e 100644 --- a/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts +++ b/apps/web/src/app/billing/payment/components/enter-payment-method.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from "@angular/core"; import { FormControl, FormGroup, Validators } from "@angular/forms"; -import { BehaviorSubject, startWith, Subject, takeUntil } from "rxjs"; +import { map, Observable, of, startWith, Subject, takeUntil } from "rxjs"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; @@ -48,7 +48,7 @@ type PaymentMethodFormGroup = FormGroup<{ {{ "creditCard" | i18n }} - @if (showBankAccount) { + @if (showBankAccount$ | async) { @@ -226,20 +226,12 @@ type PaymentMethodFormGroup = FormGroup<{ export class EnterPaymentMethodComponent implements OnInit { @Input({ required: true }) group!: PaymentMethodFormGroup; - private showBankAccountSubject = new BehaviorSubject(true); - showBankAccount$ = this.showBankAccountSubject.asObservable(); - @Input() - set showBankAccount(value: boolean) { - this.showBankAccountSubject.next(value); - } - get showBankAccount(): boolean { - return this.showBankAccountSubject.value; - } - - @Input() showPayPal: boolean = true; - @Input() showAccountCredit: boolean = false; - @Input() includeBillingAddress: boolean = false; + @Input() private showBankAccount = true; + @Input() showPayPal = true; + @Input() showAccountCredit = false; + @Input() includeBillingAddress = false; + protected showBankAccount$!: Observable; protected selectableCountries = selectableCountries; private destroy$ = new Subject(); @@ -267,7 +259,16 @@ export class EnterPaymentMethodComponent implements OnInit { } if (!this.includeBillingAddress) { + this.showBankAccount$ = of(this.showBankAccount); this.group.controls.billingAddress.disable(); + } else { + this.group.controls.billingAddress.patchValue({ + country: "US", + }); + this.showBankAccount$ = this.group.controls.billingAddress.controls.country.valueChanges.pipe( + startWith(this.group.controls.billingAddress.controls.country.value), + map((country) => this.showBankAccount && country === "US"), + ); } this.group.controls.type.valueChanges diff --git a/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.html b/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.html index 0355c938bce..ad2886b1e59 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-collection-row.component.html @@ -1,14 +1,15 @@ - + @if (this.canEditCollection || this.canDeleteCollection) { + + }