diff --git a/.eslintrc.json b/.eslintrc.json index 3a1c197326d..fae64d869e8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ "browser": true, "webextensions": true }, - "plugins": ["@typescript-eslint", "rxjs", "rxjs-angular"], + "plugins": ["@typescript-eslint", "rxjs", "rxjs-angular", "import"], "parser": "@typescript-eslint/parser", "parserOptions": { "project": ["./tsconfig.eslint.json"], @@ -18,6 +18,16 @@ "prettier", "plugin:rxjs/recommended" ], + "settings": { + "import/parsers": { + "@typescript-eslint/parser": [".ts"] + }, + "import/resolver": { + "typescript": { + "alwaysTryTypes": true + } + } + }, "rules": { "@typescript-eslint/no-explicit-any": "off", // TODO: This should be re-enabled "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], @@ -65,6 +75,27 @@ "selector": "CallExpression[callee.name='svgIcon']" } ], - "curly": ["error", "all"] + "curly": ["error", "all"], + "import/namespace": ["off"], // This doesn't resolve namespace imports correctly, but TS will throw for this anyway + "import/no-restricted-paths": [ + "error", + { + "zones": [ + // Do not allow angular/node/electron code to be imported into common + { + "target": "./libs/common/**/*", + "from": "./libs/angular/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/node/**/*" + }, + { + "target": "./libs/common/**/*", + "from": "./libs/electron/**/*" + } + ] + } + ] } } diff --git a/.github/workflows/build-web-ee.yml b/.github/workflows/build-web-ee.yml new file mode 100644 index 00000000000..678ccd83200 --- /dev/null +++ b/.github/workflows/build-web-ee.yml @@ -0,0 +1,16 @@ +--- +name: Build Web for EE + +on: + workflow_dispatch: + +jobs: + stub: + name: stub + runs-on: ubuntu-20.04 + steps: + - name: Checkout repo + uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 + + - name: Stub + run: print 'This is only a stub' diff --git a/.github/workflows/build-web.yml b/.github/workflows/build-web.yml index 35d6bf8b2f0..94396b75709 100644 --- a/.github/workflows/build-web.yml +++ b/.github/workflows/build-web.yml @@ -34,7 +34,7 @@ on: jobs: cloc: name: CLOC - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 @@ -51,7 +51,7 @@ jobs: setup: name: Setup - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: version: ${{ steps.version.outputs.value }} steps: @@ -62,20 +62,31 @@ jobs: id: version run: echo "::set-output name=value::${GITHUB_SHA:0:7}" - - build-oss-selfhost: - name: Build OSS zip - runs-on: ubuntu-20.04 + build-artifacts: + name: Build artifacts + runs-on: ubuntu-22.04 needs: - setup env: _VERSION: ${{ needs.setup.outputs.version }} + strategy: + matrix: + include: + - name: "selfhosted-open-source" + npm_command: "dist:oss:selfhost" + - name: "cloud-COMMERCIAL" + npm_command: "dist:bit:cloud" + - name: "selfhosted-COMMERCIAL" + npm_command: "dist:bit:selfhost" + - name: "cloud-QA" + npm_command: "build:bit:qa" + steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - name: Set up Node - uses: actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # v3.1.1 + uses: actions/setup-node@2fddd8803e2f5c9604345a0b591c3020ee971a93 # v3.4.1 with: cache: 'npm' cache-dependency-path: '**/package-lock.json' @@ -94,127 +105,57 @@ jobs: - name: Install dependencies run: npm ci - - name: Build OSS selfhost + - name: Setup QA metadata working-directory: apps/web + if: matrix.name == 'cloud-QA' run: | - npm run dist:oss:selfhost - zip -r web-$_VERSION-selfhosted-open-source.zip build + VERSION=$( jq -r ".version" package.json) + jq --arg version "$VERSION - ${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp + mv package.json.tmp package.json - - name: Upload build artifact + - name: Build ${{ matrix.name }} + working-directory: apps/web + run: npm run ${{ matrix.npm_command }} + + - name: Upload ${{ matrix.name }} artifact uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0 with: - name: web-${{ env._VERSION }}-selfhosted-open-source.zip - path: apps/web/web-${{ env._VERSION }}-selfhosted-open-source.zip + name: web-${{ env._VERSION }}-${{ matrix.name }}.zip + path: apps/web/build if-no-files-found: error - - build-cloud: - name: Build Cloud zip - runs-on: ubuntu-20.04 + build-commercial-selfhost-image: + name: Build self-host docker image + runs-on: ubuntu-22.04 needs: - setup + - build-artifacts env: _VERSION: ${{ needs.setup.outputs.version }} + steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - name: Set up Node - uses: actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # v3.1.1 - with: - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - node-version: "16" - - - name: Print environment - run: | - whoami - node --version - npm --version - gulp --version - docker --version - echo "GitHub ref: $GITHUB_REF" - echo "GitHub event: $GITHUB_EVENT" - - - name: Install dependencies - run: npm ci - - - name: Build Cloud - working-directory: apps/web - run: | - npm run dist:bit:cloud - zip -r web-$_VERSION-cloud-COMMERCIAL.zip build - - - name: Upload build artifact - uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0 - with: - name: web-${{ env._VERSION }}-cloud-COMMERCIAL.zip - path: apps/web/web-${{ env._VERSION }}-cloud-COMMERCIAL.zip - if-no-files-found: error - - - build-commercial-selfhost: - name: Build SelfHost Docker image - runs-on: ubuntu-20.04 - needs: - - setup - env: - _VERSION: ${{ needs.setup.outputs.version }} - steps: - - name: Checkout repo - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - - name: Set up Node - uses: actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # v3.1.1 - with: - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - node-version: "16" - - - name: Print environment - run: | - whoami - node --version - npm --version - gulp --version - docker --version - echo "GitHub ref: $GITHUB_REF" - echo "GitHub event: $GITHUB_EVENT" - - name: Setup DCT - if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-web' + if: github.ref == 'refs/heads/master' || + github.ref == 'refs/heads/rc' || + github.ref == 'refs/heads/hotfix-rc-web' id: setup-dct uses: bitwarden/gh-actions/setup-docker-trust@a8c384a05a974c05c48374c818b004be221d43ff with: azure-creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} azure-keyvault-name: "bitwarden-prod-kv" - - name: Install dependencies - run: npm ci - - - name: Build - working-directory: apps/web - run: | - echo -e "# Building Web\n" - echo "Building app" - echo "npm version $(npm --version)" - - npm run dist:bit:selfhost - zip -r web-$_VERSION-selfhosted-COMMERCIAL.zip build - - - name: Upload build artifact - uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # v3.0.0 + - name: Download selfhosted-COMMERCIAL artifact + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 with: name: web-${{ env._VERSION }}-selfhosted-COMMERCIAL.zip - path: apps/web/web-${{ env._VERSION }}-selfhosted-COMMERCIAL.zip - if-no-files-found: error + path: apps/web/build - name: Build Docker image working-directory: apps/web - run: | - echo -e "\nBuilding Docker image" - docker --version - docker build -t bitwarden/web . + run: docker build -t bitwarden/web . - name: Tag rc branch if: github.ref == 'refs/heads/rc' @@ -229,7 +170,9 @@ jobs: run: docker tag bitwarden/web bitwarden/web:hotfix-rc-web - name: List Docker images - if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-web' + if: github.ref == 'refs/heads/master' || + github.ref == 'refs/heads/rc' || + github.ref == 'refs/heads/hotfix-rc-web' run: docker images - name: Push rc image @@ -254,7 +197,9 @@ jobs: DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE: ${{ steps.setup-dct.outputs.dct-delegate-repo-passphrase }} - name: Log out of Docker - if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-web' + if: github.ref == 'refs/heads/master' || + github.ref == 'refs/heads/rc' || + github.ref == 'refs/heads/hotfix-rc-web' run: | docker logout echo "DOCKER_CONTENT_TRUST=0" >> $GITHUB_ENV @@ -289,33 +234,18 @@ jobs: - name: Log out of Docker run: docker logout - build-qa: name: Build Docker images for QA environment - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: - setup + - build-artifacts + env: + _VERSION: ${{ needs.setup.outputs.version }} steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - name: Set up Node - uses: actions/setup-node@56337c425554a6be30cdef71bf441f15be286854 # v3.1.1 - with: - cache: 'npm' - cache-dependency-path: '**/package-lock.json' - node-version: "16" - - - name: Print environment - run: | - whoami - node --version - npm --version - gulp --version - docker --version - echo "GitHub ref: $GITHUB_REF" - echo "GitHub event: $GITHUB_EVENT" - - name: Login to Azure uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 with: @@ -324,24 +254,15 @@ jobs: - name: Log into container registry run: az acr login -n bitwardenqa - - name: Install dependencies - run: npm ci + - name: Download cloud-QA artifact + uses: actions/download-artifact@fb598a63ae348fa914e94cd0ff38f362e927b741 + with: + name: web-${{ env._VERSION }}-cloud-QA.zip + path: apps/web/build - - name: Build + - name: Build Docker image working-directory: apps/web run: | - echo -e "# Building Web\n" - echo "Building app" - echo "npm version $(npm --version)" - VERSION=$( jq -r ".version" package.json) - jq --arg version "$VERSION - ${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp - mv package.json.tmp package.json - - npm run build:bit:qa - - echo "{\"commit_hash\": \"$GITHUB_SHA\", \"ref\": \"$GITHUB_REF\"}" | jq . > build/info.json - - echo -e "\nBuilding Docker image" docker --version docker build -t bitwardenqa.azurecr.io/web . @@ -371,9 +292,6 @@ jobs: if: github.ref == 'refs/heads/master' run: docker tag bitwardenqa.azurecr.io/web bitwardenqa.azurecr.io/web:dev - - name: List Docker images - run: docker images - - name: Push image env: IMAGE_TAG: ${{ steps.image-tag.outputs.value }} @@ -391,11 +309,8 @@ jobs: name: Crowdin Push if: github.ref == 'refs/heads/master' needs: - - build-oss-selfhost - - build-cloud - - build-commercial-selfhost - - build-qa - runs-on: ubuntu-20.04 + - build-artifacts + runs-on: ubuntu-22.04 steps: - name: Checkout repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 # v2.3.4 @@ -435,13 +350,12 @@ jobs: check-failures: name: Check for failures if: always() - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: - cloc - setup - - build-oss-selfhost - - build-cloud - - build-commercial-selfhost + - build-artifacts + - build-commercial-selfhost-image - build-qa - crowdin-push steps: @@ -450,9 +364,8 @@ jobs: env: CLOC_STATUS: ${{ needs.cloc.result }} SETUP_STATUS: ${{ needs.setup.result }} - BUILD_OSS_SELFHOST_STATUS: ${{ needs.build-oss-selfhost.result }} - BUILD_CLOUD_STATUS: ${{ needs.build-cloud.result }} - BUILD_COMMERCIAL_SELFHOST_STATUS: ${{ needs.build-commercial-selfhost.result }} + ARTIFACT_STATUS: ${{ needs.build-artifacts.result }} + BUILD_SELFHOST_STATUS: ${{ needs.build-commercial-selfhost-image.result }} BUILD_QA_STATUS: ${{ needs.build-qa.result }} CROWDIN_PUSH_STATUS: ${{ needs.crowdin-push.result }} run: | @@ -460,11 +373,9 @@ jobs: exit 1 elif [ "$SETUP_STATUS" = "failure" ]; then exit 1 - elif [ "$BUILD_OSS_SELFHOST_STATUS" = "failure" ]; then + elif [ "$ARTIFACT_STATUS" = "failure" ]; then exit 1 - elif [ "$BUILD_CLOUD_STATUS" = "failure" ]; then - exit 1 - elif [ "$BUILD_COMMERCIAL_SELFHOST_STATUS" = "failure" ]; then + elif [ "$BUILD_SELFHOST_STATUS" = "failure" ]; then exit 1 elif [ "$BUILD_QA_STATUS" = "failure" ]; then exit 1 diff --git a/.github/workflows/release-qa-web.yml b/.github/workflows/release-qa-web.yml index ed15f49f984..f02286be2f7 100644 --- a/.github/workflows/release-qa-web.yml +++ b/.github/workflows/release-qa-web.yml @@ -2,79 +2,9 @@ name: QA - Web Release on: - workflow_dispatch: - inputs: - image_extension: - description: "Image tag extension" - required: false - -env: - _QA_CLUSTER_RESOURCE_GROUP: "bw-env-qa" - _QA_CLUSTER_NAME: "bw-aks-qa" - _QA_K8S_NAMESPACE: "bw-qa" - _QA_K8S_APP_NAME: "bw-web" + workflow_dispatch: {} jobs: - deploy: - name: Deploy QA Web - runs-on: ubuntu-20.04 - steps: - - name: Checkout Repo - uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 - - - name: Setup - run: export PATH=$PATH:~/work/web/web - - - name: Login to Azure - uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 - with: - creds: ${{ secrets.AZURE_QA_KV_CREDENTIALS }} - - - name: Retrieve secrets - id: retrieve-secrets - env: - KEYVAULT: bitwarden-qa-kv - SECRETS: | - qa-aks-kubectl-credentials - run: | - for i in ${SECRETS//,/ } - do - VALUE=$(az keyvault secret show --vault-name $KEYVAULT --name $i --query value --output tsv) - echo "::add-mask::$VALUE" - echo "::set-output name=$i::$VALUE" - done - - - name: Login with qa-aks-kubectl-credentials SP - uses: Azure/login@ec3c14589bd3e9312b3cc8c41e6860e258df9010 # v1.1 - with: - creds: ${{ env.qa-aks-kubectl-credentials }} - - - name: Setup AKS access - run: | - echo "---az install---" - az aks install-cli --install-location ./kubectl --kubelogin-install-location ./kubelogin - echo "---az get-creds---" - az aks get-credentials -n $_QA_CLUSTER_NAME -g $_QA_CLUSTER_RESOURCE_GROUP - - - name: Get image tag - id: image_tag - run: | - IMAGE_TAG=$(echo "${GITHUB_REF:11}" | sed "s#/#-#g") - TAG_EXTENSION=${{ github.event.inputs.image_extension }} - - if [[ $TAG_EXTENSION ]]; then - IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION - fi - echo "::set-output name=value::$IMAGE_TAG" - - - name: Deploy Web image - env: - IMAGE_TAG: ${{ steps.image_tag.outputs.value }} - run: | - kubectl set image -n $_QA_K8S_NAMESPACE deployment/web web=bitwardenqa.azurecr.io/web:$IMAGE_TAG --record - kubectl rollout restart -n $_QA_K8S_NAMESPACE deployment/web - kubectl rollout status deployment/web -n $_QA_K8S_NAMESPACE - cfpages-deploy: name: Deploy Web Vault to QA CloudFlare Pages branch runs-on: ubuntu-20.04 @@ -104,15 +34,11 @@ jobs: uses: bitwarden/gh-actions/download-artifacts@850faad0cf6c02a8c0dc46eddde2363fbd6c373a with: workflow: build-web.yml - path: apps/web + path: apps/web/build workflow_conclusion: success branch: ${{ github.ref_name }} - artifacts: web-*-cloud-COMMERCIAL.zip + artifacts: web-*-cloud-QA.zip - # This should result in a build directory in the current working directory - - name: Unzip build asset - working-directory: apps/web - run: unzip web-*-cloud-COMMERCIAL.zip - name: Checkout Repo uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v3.0.2 diff --git a/.prettierignore b/.prettierignore index 8790a1e73ff..b1c9359fa1e 100644 --- a/.prettierignore +++ b/.prettierignore @@ -27,3 +27,6 @@ libs/.github # Github Workflows .github/workflows + +# Forked library files +libs/common/src/types/deep-jsonify.ts diff --git a/LICENSE_BITWARDEN.txt b/LICENSE_BITWARDEN.txt index fd037c06793..08e09f28639 100644 --- a/LICENSE_BITWARDEN.txt +++ b/LICENSE_BITWARDEN.txt @@ -16,7 +16,7 @@ entity on behalf of whom you are acting (as applicable, "You" or "Your"). 1. DEFINITIONS -"Bitwarden Software" means the Bitwarden server software, libraries, and +"Bitwarden Software" means the Bitwarden client software, libraries, and Commercial Modules. "Commercial Modules" means the modules designed to work with and enhance the diff --git a/apps/browser/package.json b/apps/browser/package.json index 0bc496a190a..57414631013 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2022.9.0", + "version": "2022.9.1", "scripts": { "build": "webpack", "build:mv3": "cross-env MANIFEST_VERSION=3 webpack", diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index bbcdf2e2b26..a6fb87d2305 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -157,7 +157,7 @@ "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { - "message": "Two-step login" + "message": "تسجيل الدخول بخطوتين" }, "logOut": { "message": "تسجيل الخروج" @@ -258,7 +258,7 @@ "description": "Make the first letter of a work uppercase." }, "includeNumber": { - "message": "Include Number" + "message": "تضمين الرقم" }, "minNumbers": { "message": "الحد الأدنى من الأرقام" @@ -315,7 +315,7 @@ "message": "عرض العنصر" }, "launch": { - "message": "Launch" + "message": "بدء" }, "website": { "message": "الموقع الإلكتروني" @@ -327,7 +327,7 @@ "message": "إدارة" }, "other": { - "message": "Other" + "message": "الأخرى" }, "rateExtension": { "message": "قيِّم هذه الإضافة" @@ -412,7 +412,7 @@ "message": "مطلقاً" }, "security": { - "message": "Security" + "message": "الأمان" }, "errorOccurred": { "message": "لقد حدث خطأ ما" @@ -488,10 +488,10 @@ "message": "تغيير كلمة المرور الرئيسية" }, "changeMasterPasswordConfirmation": { - "message": "You can change your master password on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "يمكنك تغيير كلمة المرور الرئيسية من خزنة الويب في bitwarden.com. هل تريد زيارة الموقع الآن؟" }, "twoStepLoginConfirmation": { - "message": "Two-step login makes your account more secure by requiring you to verify your login with another device such as a security key, authenticator app, SMS, phone call, or email. Two-step login can be enabled on the bitwarden.com web vault. Do you want to visit the website now?" + "message": "تسجيل الدخول بخطوتين يجعل حسابك أكثر أمنا من خلال مطالبتك بالتحقق من تسجيل الدخول باستخدام جهاز آخر مثل مفتاح الأمان، تطبيق المصادقة، الرسائل القصيرة، المكالمة الهاتفية، أو البريد الإلكتروني. يمكن تمكين تسجيل الدخول بخطوتين على خزنة الويب bitwarden.com. هل تريد زيارة الموقع الآن؟" }, "editedFolder": { "message": "Edited folder" @@ -500,13 +500,13 @@ "message": "هل أنت متأكد من حذف هذا المجلّد؟" }, "deletedFolder": { - "message": "Deleted folder" + "message": "تم حذف المجلد" }, "gettingStartedTutorial": { - "message": "Getting Started Tutorial" + "message": "لنبدأ نتعلم معاً" }, "gettingStartedTutorialVideo": { - "message": "Watch our getting started tutorial to learn how to get the most out of the browser extension." + "message": "مشاهدة دروس البَدْء تمكنك من الحصول على أقصى أستفادة من ملحق المتصفح." }, "syncingComplete": { "message": "تم إكمال المزامنة" @@ -531,31 +531,31 @@ } }, "newUri": { - "message": "New URI" + "message": "رابط جديد" }, "addedItem": { - "message": "Added item" + "message": "تمت إضافة العنصر" }, "editedItem": { - "message": "Edited item" + "message": "تم تعديل العنصر" }, "deleteItemConfirmation": { - "message": "Do you really want to send to the trash?" + "message": "هل تريد حقاً أن ترسل إلى سلة المهملات؟" }, "deletedItem": { "message": "تم إرسال العنصر إلى سلة المهملات" }, "overwritePassword": { - "message": "Overwrite Password" + "message": "الكتابة فوق كلمة المرور" }, "overwritePasswordConfirmation": { - "message": "Are you sure you want to overwrite the current password?" + "message": "هل أنت متأكد من أنك تريد الكتابة فوق كلمة المرور الموجودة؟" }, "overwriteUsername": { - "message": "Overwrite Username" + "message": "الكتابة فوق اسم المستخدم" }, "overwriteUsernameConfirmation": { - "message": "Are you sure you want to overwrite the current username?" + "message": "هل أنت متأكد من أنك تريد الكتابة فوق اسم المستخدم الموجود؟" }, "searchFolder": { "message": "إبحث في المجلّد" @@ -589,15 +589,15 @@ "message": "List identity items on the Tab page for easy auto-fill." }, "clearClipboard": { - "message": "Clear clipboard", + "message": "مسح الحافظة", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { - "message": "Automatically clear copied values from your clipboard.", + "message": "مسح القيم المنسوخة تلقائيًا من حافظتك.", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "notificationAddDesc": { - "message": "Should Bitwarden remember this password for you?" + "message": "هل يجب على Bitwarden تذكر كلمة المرور هذه لك؟" }, "notificationAddSave": { "message": "حفظ" @@ -683,10 +683,10 @@ "message": "Move to Organization" }, "share": { - "message": "Share" + "message": "مشاركة" }, "movedItemToOrg": { - "message": "$ITEMNAME$ moved to $ORGNAME$", + "message": "$ITEMNAME$ انتقل إلى $ORGNAME$", "placeholders": { "itemname": { "content": "$1", @@ -699,16 +699,16 @@ } }, "moveToOrgDesc": { - "message": "Choose an organization that you wish to move this item to. Moving to an organization transfers ownership of the item to that organization. You will no longer be the direct owner of this item once it has been moved." + "message": "اختر المؤسسة التي ترغب في نقل هذا العنصر إليها. يؤدي النقل إلى مؤسسة إلى نقل ملكية العنصر إلى تلك المؤسسة. لن تكون المالك المباشر لهذا العنصر بعد نقله." }, "learnMore": { - "message": "Learn more" + "message": "معرفة المزيد" }, "authenticatorKeyTotp": { - "message": "Authenticator Key (TOTP)" + "message": "مفتاح المصادقة (TOTP)" }, "verificationCodeTotp": { - "message": "Verification Code (TOTP)" + "message": "رمز التحقق (TOTP)" }, "copyVerificationCode": { "message": "Copy Verification Code" @@ -1124,16 +1124,16 @@ "message": "Dr" }, "firstName": { - "message": "First Name" + "message": "الاسم الأول" }, "middleName": { - "message": "Middle Name" + "message": "الاسم الأوسط" }, "lastName": { - "message": "Last Name" + "message": "الاسم الأخير" }, "fullName": { - "message": "Full Name" + "message": "الاسم الكامل" }, "identityName": { "message": "Identity Name" @@ -1289,7 +1289,7 @@ "description": "The URI of one of the current open tabs in the browser." }, "organization": { - "message": "Organization", + "message": "المؤسسة", "description": "An entity of multiple related people (ex. a team or business organization)." }, "types": { @@ -1672,17 +1672,17 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "expirationDate": { - "message": "Expiration Date" + "message": "تاريخ انتهاء الصلاحية" }, "expirationDateDesc": { "message": "If set, access to this Send will expire on the specified date and time.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "oneDay": { - "message": "1 day" + "message": "يوم واحد" }, "days": { - "message": "$DAYS$ days", + "message": "$DAYS$ أيام", "placeholders": { "days": { "content": "$1", @@ -1731,7 +1731,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "newPassword": { - "message": "New Password" + "message": "كلمة المرور الجديدة" }, "sendDisabled": { "message": "Send Disabled", @@ -1766,7 +1766,7 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read '**To use a calendar style date picker ** click here to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage2": { - "message": "click here", + "message": "انقر هنا", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'To use a calendar style date picker **click here** to pop out your window.'" }, "sendFirefoxCustomDatePopoutMessage3": { @@ -1798,37 +1798,37 @@ "message": "Master password re-prompt" }, "passwordConfirmation": { - "message": "Master password confirmation" + "message": "تأكيد كلمة المرور الرئيسية" }, "passwordConfirmationDesc": { - "message": "This action is protected. To continue, please re-enter your master password to verify your identity." + "message": "هذا الإجراء محمي. للاستمرار، يرجى إعادة إدخال كلمة المرور الرئيسية للتحقق من هويتك." }, "emailVerificationRequired": { - "message": "Email Verification Required" + "message": "تأكيد البريد الإلكتروني مطلوب" }, "emailVerificationRequiredDesc": { - "message": "You must verify your email to use this feature. You can verify your email in the web vault." + "message": "يجب عليك تأكيد بريدك الإلكتروني لاستخدام هذه الميزة. يمكنك تأكيد بريدك الإلكتروني في خزنة الويب." }, "updatedMasterPassword": { "message": "Updated Master Password" }, "updateMasterPassword": { - "message": "Update Master Password" + "message": "تحديث كلمة المرور الرئيسية" }, "updateMasterPasswordWarning": { - "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + "message": "تم تغيير كلمة المرور الرئيسية الخاصة بك مؤخرًا من قبل مسؤول في مؤسستك. من أجل الوصول إلى الخزنة، يجب عليك تحديثها الآن. سيتم تسجيل خروجك من الجلسة الحالية، مما يتطلب منك تسجيل الدخول مرة أخرى. قد تظل الجلسات النشطة على أجهزة أخرى نشطة لمدة تصل إلى ساعة واحدة." }, "resetPasswordPolicyAutoEnroll": { - "message": "Automatic Enrollment" + "message": "التسجيل التلقائي" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + "message": "هذه المؤسسة لديها سياسة تقوم تلقائياً بتسجيلك في إعادة تعيين كلمة المرور. هذا التسجيل سيسمح لمسؤولي المؤسسة بتغيير كلمة المرور الرئيسية الخاصة بك." }, "selectFolder": { "message": "Select folder..." }, "ssoCompleteRegistration": { - "message": "In order to complete logging in with SSO, please set a master password to access and protect your vault." + "message": "من أجل إكمال تسجيل الدخول باستخدام SSO، يرجى تعيين كلمة المرور الرئيسية للوصول لخزنتك وحمايتها." }, "hours": { "message": "ساعات" @@ -1837,7 +1837,7 @@ "message": "دقائق" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "message": "سياسات مؤسستك تؤثر على مهلة الخزنة الخاص بك. الحد الأقصى المسموح به لمهلة الخزنة هو $HOURS$ ساعة/ساعات و $MINUTES$ دقيقة/دقائق", "placeholders": { "hours": { "content": "$1", @@ -1850,19 +1850,19 @@ } }, "vaultTimeoutTooLarge": { - "message": "Your vault timeout exceeds the restrictions set by your organization." + "message": "مهلة خزنتك تتجاوز القيود التي تضعها مؤسستك." }, "vaultExportDisabled": { - "message": "Vault Export Disabled" + "message": "تصدير الخزنة مُعطّل" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "واحدة أو أكثر من سياسات المؤسسة تمنعك من تصدير خزانتك الشخصية." }, "copyCustomFieldNameInvalidElement": { - "message": "Unable to identify a valid form element. Try inspecting the HTML instead." + "message": "غير قادر على التعرف على نموذج صالح. حاول فحص HTML بدلا من ذلك." }, "copyCustomFieldNameNotUnique": { - "message": "No unique identifier found." + "message": "لم يتم العثور على معرف فريد." }, "convertOrganizationEncryptionDesc": { "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", @@ -1923,10 +1923,10 @@ "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { - "message": "Use your email provider's sub-addressing capabilities." + "message": "استخدم قدرات العنوان الفرعي لمزود البريد الإلكتروني الخاص بك." }, "catchallEmail": { - "message": "Catch-all Email" + "message": "تجميع كل البريد الإلكتروني" }, "catchallEmailDesc": { "message": "Use your domain's configured catch-all inbox." @@ -1950,10 +1950,10 @@ "message": "الخدمة" }, "forwardedEmail": { - "message": "Forwarded Email Alias" + "message": "إعادة توجيه الاسم المستعار للبريد الإلكتروني" }, "forwardedEmailDesc": { - "message": "Generate an email alias with an external forwarding service." + "message": "إنشاء بريد إلكتروني مستعار مع خدمة إعادة توجيه خارجية." }, "hostname": { "message": "اسم المضيف", @@ -1993,7 +1993,7 @@ "message": "تم تعديل الإعدادات" }, "environmentEditedClick": { - "message": "Click here" + "message": "انقر هنا" }, "environmentEditedReset": { "message": "لإعادة تعيين الإعدادات المُعدة مسبقاً" @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "آخر ظهور في $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index b132e0c464a..e7f0f7a8015 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -20,7 +20,7 @@ "message": "Увайсці" }, "enterpriseSingleSignOn": { - "message": "Адзіны ўваход у карпаратыўную сістэму (SSO)." + "message": "Адзіны ўваход прадпрыемства (SSO)" }, "cancel": { "message": "Скасаваць" @@ -32,7 +32,7 @@ "message": "Адправіць" }, "emailAddress": { - "message": "Адрас эл. пошты" + "message": "Адрас электроннай пошты" }, "masterPass": { "message": "Асноўны пароль" @@ -41,7 +41,7 @@ "message": "Асноўны пароль — ключ да вашага бяспечнага сховішча. Ён вельмі важны, таму не забывайце яго. Аднавіць асноўны пароль немагчыма." }, "masterPassHintDesc": { - "message": "Падказка да асноўнага пароля можа дапамагчы вам яго ўспомніць." + "message": "Падказка да асноўнага пароля можа дапамагчы вам успомніць яго, калі вы яго забылі." }, "reTypeMasterPass": { "message": "Увядзіце асноўны пароль паўторна" @@ -71,34 +71,34 @@ "message": "Бягучая ўкладка" }, "copyPassword": { - "message": "Капіяваць пароль" + "message": "Скапіяваць пароль" }, "copyNote": { - "message": "Капіяваць нататку" + "message": "Скапіяваць нататку" }, "copyUri": { - "message": "Капіяваць URI" + "message": "Скапіяваць URI" }, "copyUsername": { - "message": "Капіяваць імя карыстальніка" + "message": "Скапіяваць імя карыстальніка" }, "copyNumber": { - "message": "Капіяваць нумар" + "message": "Скапіяваць нумар" }, "copySecurityCode": { - "message": "Капіяваць код бяспекі" + "message": "Скапіяваць код бяспекі" }, "autoFill": { "message": "Аўтазапаўненне" }, "generatePasswordCopied": { - "message": "Стварыць пароль (з капіяваннем)" + "message": "Генерыраваць пароль (з капіяваннем)" }, "copyElementIdentifier": { "message": "Скапіяваць назву карыстальніцкага пароля" }, "noMatchingLogins": { - "message": "Няма падыходных уліковых даных." + "message": "Няма адпаведных лагінаў." }, "unlockVaultMenu": { "message": "Разблакіраваць сховішча" @@ -110,7 +110,7 @@ "message": "Няма ўліковых даных, даступных для аўтазапаўнення ў бягучую ўкладку браўзера." }, "addLogin": { - "message": "Дадаць ўліковыя даныя" + "message": "Дадаць лагін" }, "addItem": { "message": "Дадаць элемент" @@ -119,10 +119,10 @@ "message": "Падказка да пароля" }, "enterEmailToGetHint": { - "message": "Увядзіце адрас электроннай пошты ўліковага запісу для атрымання падказкі для асноўнага пароля." + "message": "Увядзіце адрас электроннай пошты ўліковага запісу для атрымання падказкі да асноўнага пароля." }, "getMasterPasswordHint": { - "message": "Атрымаць падказку для асноўнага пароля" + "message": "Атрымаць падказку да асноўнага пароля" }, "continue": { "message": "Працягнуць" @@ -208,23 +208,23 @@ "message": "Генератар пароляў" }, "generator": { - "message": "Згенерыраваць", + "message": "Генератар", "description": "Short for 'Password Generator'." }, "passGenInfo": { - "message": "Аўтаматычна ствараць моцныя, унікальныя паролі для вашых уліковых даных." + "message": "Аўтаматычна генерыруйце надзейныя і ўнікальныя паролі для вашых лагінаў." }, "bitWebVault": { "message": "Вэб-сховішча Bitwarden" }, "importItems": { - "message": "Імпарт элементаў" + "message": "Імпартаванне элементаў" }, "select": { "message": "Выбраць" }, "generatePassword": { - "message": "Стварыць пароль" + "message": "Генерыраваць пароль" }, "regeneratePassword": { "message": "Стварыць новы пароль" @@ -254,17 +254,17 @@ "message": "Раздзяляльнік слоў" }, "capitalize": { - "message": "З вялікай літары", + "message": "Вялікія літары", "description": "Make the first letter of a work uppercase." }, "includeNumber": { "message": "Уключыць лічбу" }, "minNumbers": { - "message": "Мін. колькасць лічбаў" + "message": "Мінімум лічбаў" }, "minSpecial": { - "message": "Мін. колькасць сімвалаў" + "message": "Мінімум спецыяльных сімвалаў" }, "avoidAmbChar": { "message": "Пазбягаць неадназначных сімвалаў" @@ -300,10 +300,10 @@ "message": "Нататкі" }, "note": { - "message": "Нататкі" + "message": "Нататка" }, "editItem": { - "message": "Рэдагаванне элемента" + "message": "Рэдагаваць элемент" }, "folder": { "message": "Папка" @@ -324,7 +324,7 @@ "message": "Пераключыць бачнасць" }, "manage": { - "message": "Кіраваць" + "message": "Кіраванне" }, "other": { "message": "Iншае" @@ -348,7 +348,7 @@ "message": "Разблакіраваць" }, "loggedInAsOn": { - "message": "Выкананы ўваход на $HOSTNAME$ як $EMAIL$.", + "message": "Вы ўвайшлі як $HOSTNAME$ у $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -403,7 +403,7 @@ "message": "4 гадзіны" }, "onLocked": { - "message": "Разам з камп'ютарам" + "message": "Пры блакіраванні сістэмы" }, "onRestart": { "message": "Пры перазапуску браўзера" @@ -433,7 +433,7 @@ "message": "Асноўны пароль павінен быць даўжынёй не менш за 8 сімвалаў." }, "masterPassDoesntMatch": { - "message": "Асноўныя паролі не супадаюць." + "message": "Пацвярджэнне асноўнага пароля не супадае." }, "newAccountCreated": { "message": "Ваш уліковы запіс створаны! Вы можаце ўвайсці." @@ -448,7 +448,7 @@ "message": "Памылковы праверачны код" }, "valueCopied": { - "message": "$VALUE$ скапіяваны(-а)", + "message": "$VALUE$ скапіяваны", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -458,10 +458,10 @@ } }, "autofillError": { - "message": "Не ўдаецца аўтаматычна запоўніць выбраны элемент на гэтай старонцы. Скапіюйце і ўстаўце інфармацыю ўручную." + "message": "Немагчыма аўтазапоўніць выбраны элемент на гэтай старонцы. Скапіюйце і ўстаўце інфармацыю ўручную." }, "loggedOut": { - "message": "Вы выйшлі са сховішча" + "message": "Вы выйшлі" }, "loginExpired": { "message": "Скончыўся тэрмін дзеяння вашага сеансу." @@ -479,7 +479,7 @@ "message": "Адбылася нечаканая памылка." }, "nameRequired": { - "message": "Патрэбна назва." + "message": "Патрабуецца назва." }, "addedFolder": { "message": "Папка дададзена" @@ -503,7 +503,7 @@ "message": "Папка выдалена" }, "gettingStartedTutorial": { - "message": "Дапаможнік па пачатку працы" + "message": "Уводзіны ў карыстанне праграмай" }, "gettingStartedTutorialVideo": { "message": "Праглядзіце невялікі навучальны матэрыял, каб даведацца. як атрымаць максімальную аддачу ад пашырэння браўзера." @@ -540,7 +540,7 @@ "message": "Элемент адрэдагаваны" }, "deleteItemConfirmation": { - "message": "Вы ўпэўнены, што хочаце выдаліць гэты элемент?" + "message": "Вы ўпэўнены, што хочаце адправіць гэты элемент у сметніцу?" }, "deletedItem": { "message": "Выдалены элемент" @@ -574,19 +574,19 @@ "message": "Пытацца пры дадаванні лагіна" }, "addLoginNotificationDesc": { - "message": "Апавяшчэнне аб даданні ўліковых даных аўтаматычна прапануе вам захаваць новыя ўліковыя даныя ў сховішчы." + "message": "Пытацца пра дадаванне элемента, калі ён адсутнічае ў вашым сховішчы." }, "showCardsCurrentTab": { "message": "Паказваць карткі на старонцы з укладкамі" }, "showCardsCurrentTabDesc": { - "message": "Паказваць спіс элементаў на старонцы з укладкамі для лёгкага аўтазапаўнення." + "message": "Спіс элементаў картак на старонцы з укладкамі для лёгкага аўтазапаўнення." }, "showIdentitiesCurrentTab": { "message": "Паказваць пасведчанні на старонцы з укладкамі" }, "showIdentitiesCurrentTabDesc": { - "message": "Паказваць пасведчанні элементаў на старонцы з укладкамі для лёгкага аўтазапаўнення." + "message": "Спіс элементаў пасведчання на старонцы з укладкамі для лёгкага аўтазапаўнення." }, "clearClipboard": { "message": "Ачыстка буфера абмену", @@ -603,13 +603,13 @@ "message": "Так, захаваць зараз" }, "enableChangedPasswordNotification": { - "message": "Пытацца пра абнаўленні існуючых даных уваходу" + "message": "Пытацца пра абнаўленні існуючага лагіна" }, "changedPasswordNotificationDesc": { - "message": "Пытаць пра абнаўленне пароля ўваходу пры выяўленні змяненняў на вэб-сайце." + "message": "Пытацца пра абнаўленне пароля ад лагіна пры выяўленні змяненняў на вэб-сайце." }, "notificationChangeDesc": { - "message": "Вы хочаце абнавіць гэты пароль у Bitwarden?" + "message": "Хочаце абнавіць гэты пароль у Bitwarden?" }, "notificationChangeSave": { "message": "Так, абнавіць зараз" @@ -621,17 +621,17 @@ "message": "Выкарыстоўваць падвоены націск для доступу да генератара пароля і супастаўлення лагінаў для вэб-сайтаў. " }, "defaultUriMatchDetection": { - "message": "Выяўленне супадзення URI па змаўчанні", + "message": "Прадвызначанае выяўленне супадзення URI", "description": "Default URI match detection for auto-fill." }, "defaultUriMatchDetectionDesc": { - "message": "Выберыце спосаб па змаўчанні, які выкарыстоўваецца пры вызначэнні адпаведнасці URI для ўліковых даных пры выкананні такіх дзеянняў, як аўтаматычнае запаўненне." + "message": "Выберыце прадвызначаны спосаб вызначэння адпаведнасці URI для лагінаў пры выкананні такіх дзеянняў, як аўтаматычнае запаўненне." }, "theme": { "message": "Тэма" }, "themeDesc": { - "message": "Змена колеравай тэмы праграмы." + "message": "Змена каляровай тэмы праграмы." }, "dark": { "message": "Цёмная", @@ -646,7 +646,7 @@ "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Экспарт сховішча" + "message": "Экспартаваць сховішча" }, "fileFormat": { "message": "Фармат файла" @@ -656,7 +656,7 @@ "description": "WARNING (should stay in capitalized letters if the language permits)" }, "confirmVaultExport": { - "message": "Пацвердзіць экспарт сховішча" + "message": "Пацвердзіць экспартаванне сховішча" }, "exportWarningDesc": { "message": "Экспартуемы файл утрымлівае даныя вашага сховішча ў незашыфраваным фармаце. Яго не варта захоўваць ці адпраўляць па небяспечным каналам (напрыклад, па электроннай пошце). Выдаліце яго адразу пасля выкарыстання." @@ -668,7 +668,7 @@ "message": "Ключы шыфравання з'яўляюцца ўнікальнымі для кожнага ўліковага запісу Bitwarden, таму нельга імпартаваць зашыфраванае сховішча ў іншы ўліковы запіс." }, "exportMasterPassword": { - "message": "Увядзіце ваш асноўны пароль для экспарту даных са сховішча." + "message": "Увядзіце ваш асноўны пароль для экспартавання даных сховішча." }, "shared": { "message": "Абагуленыя" @@ -705,13 +705,13 @@ "message": "Даведацца больш" }, "authenticatorKeyTotp": { - "message": "Ключ праверкі сапраўднасці (TOTP)" + "message": "Ключ аўтэнтыфікацыі (TOTP)" }, "verificationCodeTotp": { "message": "Код праверкі (TOTP)" }, "copyVerificationCode": { - "message": "Капіяваць код праверкі" + "message": "Скапіяваць праверачны код" }, "attachments": { "message": "Далучэнні" @@ -753,7 +753,7 @@ "message": "Прэміяльны статус" }, "premiumManage": { - "message": "Кіраванне статусам" + "message": "Кіраваць статусам" }, "premiumManageAlert": { "message": "Вы можаце кіраваць сваім статусам на bitwarden.com. Перайсці на сайт зараз?" @@ -798,7 +798,7 @@ "message": "Дзякуем вам за падтрымку Bitwarden." }, "premiumPrice": { - "message": "Усяго толькі за $PRICE$ на год!", + "message": "Усяго за $PRICE$ у год!", "placeholders": { "price": { "content": "$1", @@ -810,13 +810,13 @@ "message": "Абнаўленне завершана" }, "enableAutoTotpCopy": { - "message": "Капіяваць TOTP аўтаматычна" + "message": "Скапіяваць TOTP аўтаматычна" }, "disableAutoTotpCopyDesc": { - "message": "Калі да вашых уліковых даных прымацаваны ключ праверкі сапраўднасці, то код пацвярджэння TOTP будзе скапіяваны пры аўтазапаўненні ўліковых даных." + "message": "Калі ў лагіна ёсць ключ аўтэнтыфікацыі, то праверачны код TOTP будзе скапіяваны ў буфер абмену пры аўтазапаўненні ўваходу." }, "enableAutoBiometricsPrompt": { - "message": "Запытваць біяметрыю пры запуску" + "message": "Пытацца пра біяметрыю пры запуску" }, "premiumRequired": { "message": "Патрабуецца прэміяльны статус" @@ -825,10 +825,10 @@ "message": "Для выкарыстання гэтай функцыі патрабуецца прэміяльны статус." }, "enterVerificationCodeApp": { - "message": "Увядзіце 6 лічбаў кода праверкі з вашай праграмы праверкі сапраўднасці." + "message": "Увядзіце 6 лічбаў праверачнага кода з вашай праграмы аўтэнтыфікацыі." }, "enterVerificationCodeEmail": { - "message": "Увядзіце 6 лічбаў кода праверкі, які быў адпраўлены на $EMAIL$.", + "message": "Увядзіце 6 лічбаў праверачнага кода, які быў адпраўлены на $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -855,10 +855,10 @@ "message": "Выкарыстоўваць іншы метад двухэтапнага ўваходу" }, "insertYubiKey": { - "message": "Устаўце ваш YubiKey ў порт USB вашага камп'ютара, затым націсніце на кнопку." + "message": "Устаўце свой YubiKey у порт USB камп'ютара, а потым націсніце на кнопку." }, "insertU2f": { - "message": "Устаўце ваш ключ бяспекі ў порт USB вашага камп'ютара. Калі на ім ёсць кнопка, націсніце на яе." + "message": "Устаўце ваш ключ бяспекі ў порт USB камп'ютара. Калі на ім ёсць кнопка, націсніце на яе." }, "webAuthnNewTab": { "message": "Каб пачаць праверку WebAuthn 2FA, націсніце кнопку знізу для адкрыцця новай укладкі і прытрымлівайцеся інструкцый, якія паказаны ў новай укладцы." @@ -882,13 +882,13 @@ "message": "Параметры двухэтапнага ўваходу" }, "recoveryCodeDesc": { - "message": "Згубілі доступ да ўсіх варыянтаў двухэтапнага ўваходу? Скарыстайцеся кодам аднаўлення, каб адключыць двухэтапны ўваход для вашага ўліковага запісу." + "message": "Згубілі доступ да ўсіх варыянтаў доступу пастаўшчыкоў двухэтапнай аўтэнтыфікацыі? Скарыстайцеся кодам аднаўлення, каб адключыць праверку пастаўшчыкоў двухэтапнай аўтэнтыфікацыі для вашага ўліковага запісу." }, "recoveryCodeTitle": { "message": "Код аднаўлення" }, "authenticatorAppTitle": { - "message": "Праграма праверкі сапраўднасці" + "message": "Праграма аўтэнтыфікацыі" }, "authenticatorAppDesc": { "message": "Выкарыстоўвайце праграму для праверкі сапраўднасці (напрыклад, Authy або Google Authenticator) для стварэння кодаў праверкі на аснове часу.", @@ -927,22 +927,22 @@ "message": "Увядзіце асноўны URL-адрас на вашым серверы." }, "customEnvironment": { - "message": "Налады асяроддзя" + "message": "Карыстальніцкае асяроддзе" }, "customEnvironmentFooter": { - "message": "Для вопытных карыстальнікаў. Можна ўвесці URL-адрасы асобна для кжонай службы." + "message": "Для дасведчаных карыстальнікаў. Можна ўвесці URL-адрасы асобна для кожнай службы." }, "baseUrl": { "message": "URL-адрас сервера" }, "apiUrl": { - "message": "API URL-адраса сервера" + "message": "Сервер URL-адраса API" }, "webVaultUrl": { "message": "URL-адрас сервера вэб-сховішча" }, "identityUrl": { - "message": "URL-адрас сервера ідэнтыфікацыі" + "message": "URL-адрас сервера пасведчання" }, "notificationsUrl": { "message": "URL-адрас сервера апавяшчэнняў" @@ -954,22 +954,22 @@ "message": "URL-адрас сервера асяроддзя захаваны." }, "enableAutoFillOnPageLoad": { - "message": "Уключыць аўтазапаўненне пры загрузцы старонкі" + "message": "Аўтазапаўненне пры загрузцы старонкі" }, "enableAutoFillOnPageLoadDesc": { - "message": "Пры выяўленні формы ўваходу выконваецца аўтазапаўненне падчас загрузкі вэб-старонкі." + "message": "Калі выяўлена форма ўваходу, то будзе выканана яе аўтазапаўненне падчас загрузкі вэб-старонкі." }, "experimentalFeature": { "message": "Гэта эксперыментальная функцыя. Выкарыстоўвайце на свой страх і рызыку." }, "defaultAutoFillOnPageLoad": { - "message": "Прадвызначана налада аўтазапаўнення для элементаў уваходу" + "message": "Прадвызначаная налада аўтазапаўнення для элементаў уваходу" }, "defaultAutoFillOnPageLoadDesc": { "message": "Вы можаце выключыць аўтазапаўненне на старонцы загрузцы для асобных элементаў уваходу ў меню \"Рэдагаваць\"." }, "itemAutoFillOnPageLoad": { - "message": "Аўтазапаўненне пры загрузцы (калі ўключана ў параметрах праграмы)" + "message": "Аўтазапаўненне пры загрузцы старонкі (калі ўключана ў параметрах праграмы)" }, "autoFillOnPageLoadUseDefault": { "message": "Выкарыстоўваць прадвызначаныя налады" @@ -987,10 +987,10 @@ "message": "Адкрыць сховішча ў бакавой панэлі" }, "commandAutofillDesc": { - "message": "Аўтазапаўненне апошніх скарыстаных уліковых даных для бягучага вэб-сайта." + "message": "Аўтазапаўненне апошняга скарыстанага лагіна для бягучага вэб-сайта" }, "commandGeneratePasswordDesc": { - "message": "Стварыць і капіяваць новы выпадковы парольу буфер абмену." + "message": "Генерыраваць і скапіяваць новы выпадковы пароль у буфер абмену" }, "commandLockVaultDesc": { "message": "Заблакіраваць сховішча" @@ -1002,7 +1002,7 @@ "message": "Карыстальніцкія палі" }, "copyValue": { - "message": "Капіяваць значэнне" + "message": "Скапіяваць значэнне" }, "value": { "message": "Значэнне" @@ -1020,7 +1020,7 @@ "message": "Схавана" }, "cfTypeBoolean": { - "message": "Лагічнае" + "message": "Булева" }, "cfTypeLinked": { "message": "Звязана", @@ -1031,7 +1031,7 @@ "description": "This describes a value that is 'linked' (tied) to another value." }, "popup2faCloseMessage": { - "message": "Націск за межамі гэтага акна для прагляду кода праверкі з электроннай пошты прывядзе да яго закрыцця. Адкрыць bitwarden у новым акне?" + "message": "Націск за межамі ўсплывальнага акна для прагляду праверачнага кода прывядзе да яго закрыцця. Адкрыць гэта ўсплывальнае акно ў новым акне, якое не закрыецца?" }, "popupU2fCloseMessage": { "message": "Гэты браўзар не можа апрацоўваць запыты U2F у гэтым усплывальным акне. Вы хочаце адкрыць гэта ўсплывальнае акно ў новым акне, каб мець магчымасць увайсці ў сістэму, выкарыстоўваючы U2F?" @@ -1058,10 +1058,10 @@ "message": "Тып карткі" }, "expirationMonth": { - "message": "Месяц заканчэння" + "message": "Месяц завяршэння" }, "expirationYear": { - "message": "Год заканчэння" + "message": "Год завяршэння" }, "expiration": { "message": "Тэрмін дзеяння" @@ -1079,7 +1079,7 @@ "message": "Красавік" }, "may": { - "message": "Май" + "message": "Травень" }, "june": { "message": "Чэрвень" @@ -1121,7 +1121,7 @@ "message": "Пані" }, "dr": { - "message": "Док." + "message": "Доктар" }, "firstName": { "message": "Імя" @@ -1136,7 +1136,7 @@ "message": "Поўнае імя" }, "identityName": { - "message": "Імя" + "message": "Імя пасведчання" }, "company": { "message": "Кампанія" @@ -1160,13 +1160,13 @@ "message": "Адрас" }, "address1": { - "message": "Радок адрасу 1" + "message": "Адрас 1" }, "address2": { - "message": "Радок адрасу 2" + "message": "Адрас 2" }, "address3": { - "message": "Радок адрасу 3" + "message": "Адрас 3" }, "cityTown": { "message": "Горад / Пасёлак" @@ -1184,7 +1184,7 @@ "message": "Тып" }, "typeLogin": { - "message": "Уліковыя даныя" + "message": "Лагін" }, "typeLogins": { "message": "Уліковыя даныя" @@ -1223,7 +1223,7 @@ "message": "Пасведчанні" }, "logins": { - "message": "Уліковыя даныя" + "message": "Лагіны" }, "secureNotes": { "message": "Бяспечныя нататкі" @@ -1256,7 +1256,7 @@ "description": "Domain name. Ex. website.com" }, "host": { - "message": "Хост", + "message": "Вузел", "description": "A URL's host value. For example, the host of https://sub.domain.com:443 is 'sub.domain.com:443'." }, "exact": { @@ -1274,7 +1274,7 @@ "description": "URI match detection for auto-fill." }, "defaultMatchDetection": { - "message": "Метад выяўлення па змаўчанні", + "message": "Прадвызначаны метад выяўлення", "description": "Default URI match detection for auto-fill." }, "toggleOptions": { @@ -1285,7 +1285,7 @@ "description": "Toggle the display of the URIs of the currently open tabs in the browser." }, "currentUri": { - "message": "Бягучы URI укладкі", + "message": "Бягучы URI", "description": "The URI of one of the current open tabs in the browser." }, "organization": { @@ -1305,7 +1305,7 @@ "message": "Выдаліць" }, "default": { - "message": "Па змаўчанні" + "message": "Прадвызначана" }, "dateUpdated": { "message": "Абноўлена", @@ -1316,7 +1316,7 @@ "description": "ex. Date this password was updated" }, "neverLockWarning": { - "message": "Вы ўпэўнены, што хочаце адключыць блакіроўку сховішча? У гэтым выпадку ключ шыфравання вашага сховішча будзе захаваны на вашай прыладзе. Адключаючы блакіроўку, вы павінны пераканацца, што ваша прылада надзейна абаронена." + "message": "Вы ўпэўнены, што хочаце адключыць блакіроўку сховішча? Прызначыўшы параметр блакіравання \"Ніколі\", ключ шыфравання будзе захоўвацца на вашай прыладзе. Калі вы выкарыстоўваеце гэты параметр, вы павінны быць упэўнены ў тым, што ваша прылада надзейна абаронена." }, "noOrganizationsList": { "message": "Вы не з'яўляецеся членам якой-небудзь арганізацыі. Арганізацыі дазваляюць бяспечна абменьвацца элементамі з іншымі карыстальнікамі." @@ -1331,7 +1331,7 @@ "message": "Каму належыць гэты элемент?" }, "strong": { - "message": "Моцны", + "message": "Надзейны", "description": "ex. A strong password. Scale: Weak -> Good -> Strong" }, "good": { @@ -1339,14 +1339,14 @@ "description": "ex. A good password. Scale: Weak -> Good -> Strong" }, "weak": { - "message": "Слабы", + "message": "Ненадзейны", "description": "ex. A weak password. Scale: Weak -> Good -> Strong" }, "weakMasterPassword": { "message": "Слабы асноўны пароль" }, "weakMasterPasswordDesc": { - "message": "Асноўны пароль, выбраны вамі, з'яўляецца слабым. Для належнай абароны ўліковага запісу Bitwarden, вы павінны выкарыстоўваць моцны асноўны пароль (або парольную фразу). Вы ўпэўнены, што хочаце выкарыстоўваць гэты асноўны пароль?" + "message": "Асноўны пароль, які вы выбралі з'яўляецца ненадзейным. Для належнай абароны ўліковага запісу Bitwarden, вы павінны выкарыстоўваць надзейны асноўны пароль (або парольную фразу). Вы ўпэўнены, што хочаце выкарыстоўваць гэты асноўны пароль?" }, "pin": { "message": "PIN-код", @@ -1374,7 +1374,7 @@ "message": "Для ўключэння біяметрыі ў браўзеры, пацвердзіце гэта ў праграме Bitwarden на сваім камп'ютары." }, "lockWithMasterPassOnRestart": { - "message": "Блакіраваць асноўным паролем пры перазапуску браўзера" + "message": "Заблакіраваць асноўным паролем пры перазапуску браўзера" }, "selectOneCollection": { "message": "Вы павінны выбраць прынамсі адну калекцыю." @@ -1386,7 +1386,7 @@ "message": "Кланіраваць" }, "passwordGeneratorPolicyInEffect": { - "message": "На налады генератара ўплываюць адна або некалькі палітык арганізацый." + "message": "Адна або больш палітык арганізацыі ўплывае на налады генератара." }, "vaultTimeoutAction": { "message": "Дзеянне пры тайм-аўце" @@ -1415,19 +1415,19 @@ "message": "Аднавіць элемент" }, "restoreItemConfirmation": { - "message": "Вы сапраўды жадаеце аднавіць гэты элемент?" + "message": "Вы ўпэўнены, што хочаце аднавіць гэты элемент?" }, "restoredItem": { "message": "Элемент адноўлены" }, "vaultTimeoutLogOutConfirmation": { - "message": "Выхад з сістэмы выдаліць доступ да сховішча і спатрабуе праверку сапраўднасці анлайн па заканчэнні перыяду чакання. Вы сапраўды жадаеце ўключыць гэтую наладу?" + "message": "Выхад з сістэмы скасуе ўсе магчымасці доступу да сховішча і запатрабуе аўтэнтыфікацыю праз інтэрнэт пасля завяршэння часу чакання. Вы ўпэўнены, што хочаце выкарыстоўваць гэты параметр?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "Пацвярджэнне дзеяння для тайм-аута" }, "autoFillAndSave": { - "message": "Запоўніць і захаваць" + "message": "Аўтазапоўніць і захаваць" }, "autoFillSuccessAndSavedUri": { "message": "Аўтазапоўнены элемент і захаваны URI" @@ -1439,7 +1439,7 @@ "message": "Задаць асноўны пароль" }, "masterPasswordPolicyInEffect": { - "message": "Згодна з адной або некалькімі палітыкамі арганізацыі неабходна, каб ваш асноўны пароль адказваў наступным патрабаванням:" + "message": "Адна або больш палітык арганізацыі патрабуе, каб ваш асноўны пароль адпавядаў наступным патрабаванням:" }, "policyInEffectMinComplexity": { "message": "Мінімальны ўзровень складанасці $SCORE$", @@ -1460,13 +1460,13 @@ } }, "policyInEffectUppercase": { - "message": "Уключыць адну ці больш прапісных літар" + "message": "Уключыць адну або некалькі вялікіх літар" }, "policyInEffectLowercase": { - "message": "Уключыць адну ці больш малых літар" + "message": "Уключыць адну або некалькі малых літар" }, "policyInEffectNumbers": { - "message": "Уключыць адну ці больш лічбаў" + "message": "Уключыць адну або некалькі лічбаў" }, "policyInEffectSpecial": { "message": "Уключаць хаця б адзін з наступных спецыяльных сімвалаў $CHARS$", @@ -1481,7 +1481,7 @@ "message": "Ваш новы асноўны пароль не адпавядае патрабаванням палітыкі арганізацыі." }, "acceptPolicies": { - "message": "Ставіўшы гэты сцяжок вы пагаджаецеся з наступным:" + "message": "Ставячы гэты сцяжок, вы пагаджаецеся з наступным:" }, "acceptPoliciesRequired": { "message": "Умовы выкарыстання і Палітыка прыватнасці не былі пацверджаны." @@ -1496,7 +1496,7 @@ "message": "Падказка для пароля не можа супадаць з паролем." }, "ok": { - "message": "ОК" + "message": "Добра" }, "desktopSyncVerificationTitle": { "message": "Праверка сінхранізацыі на камп'ютары" @@ -1538,7 +1538,7 @@ "message": "Біяметрыя не ўключана" }, "biometricsNotEnabledDesc": { - "message": "Для актывацыі біяметрыі ў браўзеры спачатку неабходна ўключыць біяметрыю ў праграме на камп'ютары." + "message": "Для актывацыі біяметрыі ў браўзеры неабходна спачатку ўключыць яе ў наладах праграмы для камп'ютара." }, "biometricsNotSupportedTitle": { "message": "Біяметрыя не падтрымліваецца" @@ -1559,7 +1559,7 @@ "message": "Гэта дзеянне немагчыма выканаць у бакавой панэлі. Паспрабуйце паўтарыць гэта дзеянне ва ўсплывальным або асобным акне." }, "personalOwnershipSubmitError": { - "message": "У адпаведнасці з карпаратыўнай палітыкай вам забаронена захоўваць элементы ў асабістым сховішчы. Змяніце параметры ўласнасці на арганізацыю і выберыце з даступных калекцый." + "message": "У адпаведнасці з палітыкай прадпрыемства вам забаронена захоўваць элементы ў асабістым сховішчы. Змяніце параметры ўласнасці на арганізацыю і выберыце з даступных калекцый." }, "personalOwnershipPolicyInEffect": { "message": "Палітыка арганізацыі ўплывае на вашы параметры ўласнасці." @@ -1615,7 +1615,7 @@ "message": "Абаронена паролем" }, "copySendLink": { - "message": "Капіяваць спасылку Send", + "message": "Скапіяваць спасылку на Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { @@ -1628,7 +1628,7 @@ "message": "Пароль выдалены" }, "deletedSend": { - "message": "Выдалены Send", + "message": "Send выдалены", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLink": { @@ -1682,7 +1682,7 @@ "message": "1 дзень" }, "days": { - "message": "$DAYS$ дзён", + "message": "Дзён: $DAYS$", "placeholders": { "days": { "content": "$1", @@ -1697,7 +1697,7 @@ "message": "Максімальная колькасць доступаў" }, "maximumAccessCountDesc": { - "message": "Калі зададзена, то карыстальнікі больш не змогуць атрымаць доступ да гэтага Send пасля таго, як будзе дасягнута максімальная колькасць зваротаў.", + "message": "Калі прызначана, то карыстальнікі больш не змогуць атрымаць доступ да гэтага Send пасля таго, як будзе дасягнута максімальная колькасць зваротаў.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendPasswordDesc": { @@ -1738,7 +1738,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "У адпаведнасці з карпаратыўнай палітыкай, вы можаце выдаліць толькі бягучы Send.", + "message": "У адпаведнасці з палітыкай прадпрыемства, вы можаце выдаліць толькі бягучы Send.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { @@ -1746,7 +1746,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Адрэдагаваны Send", + "message": "Send адрэдагаваны", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendLinuxChromiumFileWarning": { @@ -1756,7 +1756,7 @@ "message": "Для выбару файла з выкарыстаннем Firefox неабходна адкрыць пашырэнне на бакавой панэлі або перайсці ў новае акно, націснуўшы на гэты банэр." }, "sendSafariFileWarning": { - "message": "Для выбару файла з выкарыстаннем Safari неабходна перайсці ў асобнае акно, націснуўшы на гэты банэр." + "message": "Для выбару файла з выкарыстаннем Safari неабходна перайсці ў новае акно, націснуўшы на гэты банэр." }, "sendFileCalloutHeader": { "message": "Перад тым, як пачаць" @@ -1795,7 +1795,7 @@ "message": "Адна або больш палітык арганізацыі ўплываюць на параметры Send." }, "passwordPrompt": { - "message": "Паўторны запыт галоўнага пароля" + "message": "Паўторны запыт асноўнага пароля" }, "passwordConfirmation": { "message": "Пацвярджэнне асноўнага пароля" @@ -1828,7 +1828,7 @@ "message": "Выбраць папку..." }, "ssoCompleteRegistration": { - "message": "Для завяршэння ўваходу праз SSO, задайце асноўны пароль для доступу і абароны вашаго сховішча." + "message": "Для завяршэння працэсу ўваходу з дапамогай SSO, прызначце асноўны пароль для доступу да вашага сховішча і яго абароны." }, "hours": { "message": "Гадзіны" @@ -1859,13 +1859,13 @@ "message": "Адна або больш палітык арганізацыі не дазваляюць вам экспартаваць асабістае сховішча." }, "copyCustomFieldNameInvalidElement": { - "message": "Не атрымалася ідэнтыфікаваць дзеючы элемент формы. Паспрабуйце замест гэтага праверыць HTML." + "message": "Немагчыма ідэнтыфікаваць дзеючы элемент формы. Паспрабуйце замест гэтага праверыць HTML." }, "copyCustomFieldNameNotUnique": { "message": "Не знойдзены ўнікальны ідэнтыфікатар." }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ выкарыстоўвае SSO з уласным серверам ключоў. Для аўтарызацыі ўдзельнікам гэтай арганізацыі больш няма неабходнасці выкарыстоўваць асноўны пароль.", + "message": "$ORGANIZATION$ выкарыстоўвае SSO з уласным серверам ключоў. Асноўны пароль для ўдзельнікаў гэтай арганізацыі больш не патрабуецца.", "placeholders": { "organization": { "content": "$1", @@ -1874,7 +1874,7 @@ } }, "leaveOrganization": { - "message": "Пакінуць арганізацыю" + "message": "Выйсці з арганізацыі" }, "removeMasterPassword": { "message": "Выдаліць асноўны пароль" @@ -1883,7 +1883,7 @@ "message": "Асноўны пароль выдалены." }, "leaveOrganizationConfirmation": { - "message": "Вы ўпэўнены, што хочаце пакінуць гэту арганізацыю?" + "message": "Вы ўпэўнены, што хочаце выйсці з гэтай арганізацыі?" }, "leftOrganization": { "message": "Вы пакінулі арганізацыю." @@ -1898,7 +1898,7 @@ "message": "Экспартаванне асабістага сховішча" }, "exportingPersonalVaultDescription": { - "message": "Толькі элементы асабістага сховішча, якія звязаны з $EMAIL$ будуць экспартаваныя. Элементы сховішча арганізацыі не будуць уключаны.", + "message": "Будуць экспартаваны толькі асабістыя элементы сховішча, якія звязаны з $EMAIL$. Элементы сховішча арганізацыі не будуць уключаны.", "placeholders": { "email": { "content": "$1", @@ -1975,7 +1975,7 @@ "message": "Арганізацыя адключана." }, "disabledOrganizationFilterError": { - "message": "Элементы ў адключаных арганізацыя недаступны. Звяжыцеся з уладальнікам вашай арганізацыі для атрымання дапамогі." + "message": "Доступ да элементаў у адключаных арганізацыях немагчымы. Звяжыце з уладальнікам арганізацыі для атрымання дапамогі." }, "cardBrandMir": { "message": "Mir" @@ -1999,16 +1999,16 @@ "message": "для скіду да прадвызначаных наладаў" }, "serverVersion": { - "message": "Server Version" + "message": "Версія сервера" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Уласнае размяшчэнне" }, "thirdParty": { - "message": "Third-Party" + "message": "Іншы пастаўшчык" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Падлучэнне да сервера іншага пастаўшчыка $SERVERNAME$. Калі ласка, праверце памылкі з дапамогай афіцыйнага сервера або паведаміце пра іх пастаўшчыку сервера.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "апошні раз быў(-ла) $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 7c3f497daba..f9507f48823 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -2002,7 +2002,7 @@ "message": "Версия на сървъра" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Собствен хостинг" }, "thirdParty": { "message": "Third-Party" @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "последно видян на $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index f4574ce9c6d..fe994510046 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -1999,16 +1999,16 @@ "message": "per restablir els paràmetres preconfigurats" }, "serverVersion": { - "message": "Server Version" + "message": "Versió del servidor" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Autoallotjat" }, "thirdParty": { - "message": "Third-Party" + "message": "Tercers" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Connectat a la implementació del servidor de tercers, $SERVERNAME$. Verifiqueu els errors utilitzant el servidor oficial o comuniqueu-los al servidor de tercers.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "vist per última vegada el $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index 7bade191dd1..3a4879980f2 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -1999,16 +1999,16 @@ "message": "for at nulstille til forudkonfigurerede indstillinger" }, "serverVersion": { - "message": "Server Version" + "message": "Server version" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Selv-hostet" }, "thirdParty": { - "message": "Third-Party" + "message": "Tredjepart" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Forbundet til tredjepartsserverimplementering, $SERVERNAME$. Kontrollér venligst fejl ved hjælp af den officielle server, eller rapportér dem til tredjepartsserveren.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "sidst set den $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index 859b6523592..0c00c4d6658 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -149,7 +149,7 @@ "message": "Master-Passwort ändern" }, "fingerprintPhrase": { - "message": "Prüfschlüssel", + "message": "Fingerabdruck-Phrase", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "yourAccountsFingerprint": { @@ -193,7 +193,7 @@ "message": "Es gibt keine Ordner zum Anzeigen." }, "helpFeedback": { - "message": "Hilfe & Rückmeldung" + "message": "Hilfe & Feedback" }, "sync": { "message": "Synchronisierung" @@ -215,7 +215,7 @@ "message": "Generiert automatisch ein starkes und einzigartiges Passwort." }, "bitWebVault": { - "message": "Bitwarden Web-Datenspeicher" + "message": "Bitwarden Web-Tresor" }, "importItems": { "message": "Einträge importieren" @@ -1436,7 +1436,7 @@ "message": "Automatisch ausgefüllter Eintrag" }, "setMasterPassword": { - "message": "Masterpasswort festlegen" + "message": "Master-Passwort festlegen" }, "masterPasswordPolicyInEffect": { "message": "Eine oder mehrere Organisationsrichtlinien erfordern, dass dein Masterpasswort die folgenden Anforderungen erfüllt:" @@ -2002,7 +2002,7 @@ "message": "Server-Version" }, "selfHosted": { - "message": "Selbstverwaltet" + "message": "Selbst-gehostet" }, "thirdParty": { "message": "Drittanbieter" diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 378c6c28167..6674489c638 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -1999,7 +1999,7 @@ "message": "επαναφορά στις προ-ρυθμισμένες ρυθμίσεις" }, "serverVersion": { - "message": "Server Version" + "message": "Έκδοση διακομιστή" }, "selfHosted": { "message": "Self-Hosted" diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index a23bfa56501..3749bb4ae00 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "last seen on: $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 619efc76b98..9af529421b1 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -56,7 +56,7 @@ "message": "Kutxa gotorra" }, "myVault": { - "message": "Nire kutxa gotorra" + "message": "Kutxa gotorra" }, "allVaults": { "message": "Kutxa gotor guztiak" @@ -1999,16 +1999,16 @@ "message": "ezarpen lehenetsiak ezartzeko" }, "serverVersion": { - "message": "Server Version" + "message": "Zerbitzariaren bertsioa" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Ostatatze propioduna" }, "thirdParty": { - "message": "Third-Party" + "message": "Hirugarrenen aplikazioak" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Hirugarrenen zerbitzariaren inplementaziora konektatuta, $SERVERNAME$. Mesedez, egiaztatu akatsak zerbitzari ofiziala erabiliz, edo galdetu hirugarren zerbitzariari.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "Azkenekoz ikusia: $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 347de759123..069bf8c9384 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -1999,16 +1999,16 @@ "message": "per ritornare alle impostazioni preconfigurate" }, "serverVersion": { - "message": "Server Version" + "message": "Versione Server" }, "selfHosted": { "message": "Self-Hosted" }, "thirdParty": { - "message": "Third-Party" + "message": "Terze parti" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Connesso a una implementazione server di terze parti, $SERVERNAME$. Controlla i bug utilizzando il server ufficiale o segnalali al server di terze parti.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "visto l'ultima volta il $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index ea449c6cc97..a85bcbf7e6d 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -430,7 +430,7 @@ "message": "마스터 비밀번호를 재입력해야 합니다." }, "masterPasswordMinlength": { - "message": "Master password must be at least 8 characters long." + "message": "마스터 비밀번호는 최소 8자 이상이어야 합니다." }, "masterPassDoesntMatch": { "message": "마스터 비밀번호 확인과 마스터 비밀번호가 일치하지 않습니다." diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 63a46fb97dd..622634bb936 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -1999,16 +1999,16 @@ "message": "lai atiestatītu pirmsuzstādītos iestatījumus" }, "serverVersion": { - "message": "Server Version" + "message": "Servera versija" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Pašizvietots" }, "thirdParty": { - "message": "Third-Party" + "message": "Trešās puses" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "Savienots ar trešās puses izvietotu serveri $SERVERNAME$. Lūgums pārbaudīt nepilnību esamību oficiālajā serverī vai ziņot par tām trešās puses servera uzturētājiem.", "placeholders": { "servername": { "content": "$1", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "pēdējoreiz manīts $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index e6a0203e424..cc5e8dcff1c 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -406,7 +406,7 @@ "message": "Po zablokowaniu komputera" }, "onRestart": { - "message": "Po uruchomieniu przeglądarki" + "message": "Po restarcie przeglądarki" }, "never": { "message": "Nigdy" @@ -577,16 +577,16 @@ "message": "\"Dodaj powiadomienia logowania\" automatycznie wyświetla monit o zapisanie nowych danych logowania do sejfu przy każdym pierwszym logowaniu." }, "showCardsCurrentTab": { - "message": "Pokaż karty na stronie Karta" + "message": "Pokaż karty na stronie głównej" }, "showCardsCurrentTabDesc": { - "message": "Wyświetlaj elementy karty na stronie Karta, aby ułatwić autouzupełnianie." + "message": "Pokaż elementy karty na stronie głównej, aby ułatwić autouzupełnianie." }, "showIdentitiesCurrentTab": { - "message": "Pokaż tożsamości na stronie Karta" + "message": "Pokaż tożsamości na stronie głównej" }, "showIdentitiesCurrentTabDesc": { - "message": "Wyświetlaj elementy tożsamości na stronie Karta, aby ułatwić autouzupełnianie." + "message": "Pokaż elementy tożsamości na stronie głównej, aby ułatwić autouzupełnianie." }, "clearClipboard": { "message": "Wyczyść schowek", @@ -621,7 +621,7 @@ "message": "Użyj drugiego kliknięcia, aby uzyskać dostęp do generowania haseł i pasujących danych logowania do witryny. " }, "defaultUriMatchDetection": { - "message": "Domyślna metoda dopasowania adresu", + "message": "Domyślne wykrywanie dopasowania", "description": "Default URI match detection for auto-fill." }, "defaultUriMatchDetectionDesc": { @@ -1091,7 +1091,7 @@ "message": "Sierpień" }, "september": { - "message": "September" + "message": "Wrzesień" }, "october": { "message": "Październik" diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index a81faf65245..4de3a20245b 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -1969,19 +1969,19 @@ "message": "Erro de Key Connector: certifique-se de que a Key Connector está disponível e funcionando corretamente." }, "premiumSubcriptionRequired": { - "message": "Premium subscription required" + "message": "Assinatura Premium necessária" }, "organizationIsDisabled": { - "message": "Organization is disabled." + "message": "Organização está desabilitada." }, "disabledOrganizationFilterError": { - "message": "Items in disabled Organizations cannot be accessed. Contact your Organization owner for assistance." + "message": "Itens em Organizações Desativadas não podem ser acessados. Entre em contato com o proprietário da sua Organização para obter assistência." }, "cardBrandMir": { "message": "Mir" }, "loggingInTo": { - "message": "Logging in to $DOMAIN$", + "message": "Fazendo login em $DOMAIN$", "placeholders": { "domain": { "content": "$1", @@ -1990,22 +1990,22 @@ } }, "settingsEdited": { - "message": "Settings have been edited" + "message": "As configurações foram editadas" }, "environmentEditedClick": { - "message": "Click here" + "message": "Clique aqui" }, "environmentEditedReset": { - "message": "to reset to pre-configured settings" + "message": "para redefinir para as configurações pré-configuradas" }, "serverVersion": { - "message": "Server Version" + "message": "Versão do servidor" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Auto-hospedado" }, "thirdParty": { - "message": "Third-Party" + "message": "Terceiros" }, "thirdPartyServerMessage": { "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index e781475dd90..4b4ccdcd1d1 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -53,7 +53,7 @@ "message": "Zavihek" }, "vault": { - "message": "Vault" + "message": "Sef" }, "myVault": { "message": "Moj trezor" diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index b2b6ca8c7aa..ab2033e54f0 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -1999,13 +1999,13 @@ "message": "за рисетовање на подразумевана подешавања" }, "serverVersion": { - "message": "Server Version" + "message": "Верзија сервера" }, "selfHosted": { - "message": "Self-Hosted" + "message": "Личан хостинг" }, "thirdParty": { - "message": "Third-Party" + "message": "Трећа страна" }, "thirdPartyServerMessage": { "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", @@ -2017,7 +2017,7 @@ } }, "lastSeenOn": { - "message": "last seen on $DATE$", + "message": "последње виђено у $DATE$", "placeholders": { "date": { "content": "$1", diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index be7bbefb8dd..3e79a9e586d 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -146,10 +146,10 @@ "message": "Hesap" }, "changeMasterPassword": { - "message": "Ana Parolayı Değiştir" + "message": "Ana parolayı değiştir" }, "fingerprintPhrase": { - "message": "Özgün Cümle", + "message": "Parmak izi ifadesi", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "yourAccountsFingerprint": { @@ -157,10 +157,10 @@ "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "twoStepLogin": { - "message": "İki Aşamalı Giriş" + "message": "İki aşamalı giriş" }, "logOut": { - "message": "Çıkış Yap" + "message": "Çıkış yap" }, "about": { "message": "Hakkında" @@ -193,7 +193,7 @@ "message": "Listelenecek klasör yok." }, "helpFeedback": { - "message": "Yardım & Geribildirim" + "message": "Yardım ve geribildirim" }, "sync": { "message": "Eşitle" @@ -215,10 +215,10 @@ "message": "Hesaplarınız için otomatik olarak güçlü, özgün parolalar oluşturun." }, "bitWebVault": { - "message": "Bitwarden Web Kasası" + "message": "Bitwarden web kasası" }, "importItems": { - "message": "Hesapları İçe Aktar" + "message": "Hesapları içe aktar" }, "select": { "message": "Seç" @@ -367,7 +367,7 @@ "message": "Kasa zaman aşımı" }, "lockNow": { - "message": "Şimdi Kilitle" + "message": "Şimdi kilitle" }, "immediately": { "message": "Hemen" @@ -403,10 +403,10 @@ "message": "4 saat" }, "onLocked": { - "message": "Sistem Kilitliyken" + "message": "Sistem kilitlenince" }, "onRestart": { - "message": "Tarayıcı Yeniden Başlatıldığında" + "message": "Tarayıcı yeniden başlatılınca" }, "never": { "message": "Asla" @@ -574,7 +574,7 @@ "message": "Hesap eklemeyi öner" }, "addLoginNotificationDesc": { - "message": "\"Hesap Ekle Bildirimi\" otomatik olarak, ilk kez oturum açtığınız hesabınızı kasanıza kaydetmeniz için uyarı verir." + "message": "\"Hesap ekle\" bildirimi, ilk kez kullandığınız hesap bilgilerini kasanıza kaydetmek isteyip istemediğinizi otomatik olarak sorar." }, "showCardsCurrentTab": { "message": "Sekme sayfasında kartları göster" @@ -589,7 +589,7 @@ "message": "Kolay otomatik doldurma için sekme sayfasında kimlik öğelerini listele" }, "clearClipboard": { - "message": "Panoyu Temizle", + "message": "Panoyu temizle", "description": "Clipboard is the operating system thing where you copy/paste data to on your device." }, "clearClipboardDesc": { @@ -646,7 +646,7 @@ "description": "'Solarized' is a noun and the name of a color scheme. It should not be translated." }, "exportVault": { - "message": "Kasayı Dışa Aktar" + "message": "Kasayı dışa aktar" }, "fileFormat": { "message": "Dosya biçimi" @@ -750,7 +750,7 @@ "message": "Şifreleme anahtarınızı güncellemeden bu özelliği kullanamazsınız." }, "premiumMembership": { - "message": "Premium Üyelik" + "message": "Premium üyelik" }, "premiumManage": { "message": "Üyeliğimi yönet" @@ -966,7 +966,7 @@ "message": "Hesaplar için varsayılan otomatik doldurma ayarı" }, "defaultAutoFillOnPageLoadDesc": { - "message": "\"Sayfa yüklendiğinde otomatik doldur\"u açtıktan sonra her hesap için bu özelliği ayrı ayrı açıp kapatabilirsiniz. Bu ayar, özellikle ayarlama yapmadığınız hesaplarda kullanılacak varsayılan ayardır." + "message": "\"Sayfa yüklendiğinde otomatik doldur\"u her hesabın \"Düzenle\" görünümünden ayrı ayrı kapatabilirsiniz." }, "itemAutoFillOnPageLoad": { "message": "Sayfa yüklendiğinde otomatik doldur (seçeneklerde etkinleştirilmişse)" @@ -1898,7 +1898,7 @@ "message": "Kişisel Kasayı Dışa Aktar" }, "exportingPersonalVaultDescription": { - "message": "Yalnızca $EMAIL$ ile ilişkili kişisel kasa öğeleri dışa aktarılacaktır. Kuruluş kasası öğeleri dahil edilmeyecektir.", + "message": "Yalnızca $EMAIL$ ile ilişkili kişisel kasadaki kayıtlar dışa aktarılacaktır. Kuruluş kasasındaki kayıtlar dahil edilmeyecektir.", "placeholders": { "email": { "content": "$1", @@ -2008,7 +2008,7 @@ "message": "Üçüncü Taraf" }, "thirdPartyServerMessage": { - "message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.", + "message": "$SERVERNAME$ adresindeki üçüncü taraf sunucuya bağlandınız. Lütfen resmi sunucuyu kullanarak hataları doğrulayın veya üçüncü taraf sunucuya bildirin.", "placeholders": { "servername": { "content": "$1", diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index 40731c89ccb..d3a1ec4373d 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -567,7 +567,7 @@ "message": "搜索类型" }, "noneFolder": { - "message": "默认文件夹", + "message": "无文件夹", "description": "This is the folder for uncategorized items" }, "enableAddLoginNotification": { @@ -2008,7 +2008,7 @@ "message": "第三方" }, "thirdPartyServerMessage": { - "message": "已连接到第三方服务器,$SERVERNAME$。请使用官方服务器验证错误,或将其报告给第三方服务器。", + "message": "已连接到第三方服务器实现,$SERVERNAME$。请使用官方服务器验证错误,或将其报告给第三方服务器。", "placeholders": { "servername": { "content": "$1", diff --git a/apps/browser/src/background/main.background.ts b/apps/browser/src/background/main.background.ts index 99114bc007f..cf83b6e78d1 100644 --- a/apps/browser/src/background/main.background.ts +++ b/apps/browser/src/background/main.background.ts @@ -16,7 +16,7 @@ import { KeyConnectorService as KeyConnectorServiceAbstraction } from "@bitwarde import { LogService as LogServiceAbstraction } from "@bitwarden/common/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "@bitwarden/common/abstractions/messaging.service"; import { NotificationsService as NotificationsServiceAbstraction } from "@bitwarden/common/abstractions/notifications.service"; -import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService as OrganizationServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordGenerationService as PasswordGenerationServiceAbstraction } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyApiServiceAbstraction } from "@bitwarden/common/abstractions/policy/policy-api.service.abstraction"; @@ -27,6 +27,7 @@ import { SendService as SendServiceAbstraction } from "@bitwarden/common/abstrac import { SettingsService as SettingsServiceAbstraction } from "@bitwarden/common/abstractions/settings.service"; import { AbstractStorageService } from "@bitwarden/common/abstractions/storage.service"; import { SyncService as SyncServiceAbstraction } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; +import { SyncNotifierService as SyncNotifierServiceAbstraction } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction"; import { SystemService as SystemServiceAbstraction } from "@bitwarden/common/abstractions/system.service"; import { TokenService as TokenServiceAbstraction } from "@bitwarden/common/abstractions/token.service"; import { TotpService as TotpServiceAbstraction } from "@bitwarden/common/abstractions/totp.service"; @@ -58,7 +59,7 @@ import { FolderApiService } from "@bitwarden/common/services/folder/folder-api.s import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NotificationsService } from "@bitwarden/common/services/notifications.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; import { PolicyApiService } from "@bitwarden/common/services/policy/policy-api.service"; import { PolicyService } from "@bitwarden/common/services/policy/policy.service"; @@ -68,6 +69,7 @@ import { SendService } from "@bitwarden/common/services/send.service"; import { SettingsService } from "@bitwarden/common/services/settings.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { SyncService } from "@bitwarden/common/services/sync/sync.service"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; import { SystemService } from "@bitwarden/common/services/system.service"; import { TokenService } from "@bitwarden/common/services/token.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; @@ -158,6 +160,7 @@ export default class MainBackground { folderApiService: FolderApiServiceAbstraction; policyApiService: PolicyApiServiceAbstraction; userVerificationApiService: UserVerificationApiServiceAbstraction; + syncNotifierService: SyncNotifierServiceAbstraction; // Passed to the popup for Safari to workaround issues with theming, downloading, etc. backgroundWindow = window; @@ -298,7 +301,8 @@ export default class MainBackground { this.cryptoFunctionService, this.stateService ); - this.organizationService = new OrganizationService(this.stateService); + this.syncNotifierService = new SyncNotifierService(); + this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService); this.policyService = new PolicyService(this.stateService, this.organizationService); this.policyApiService = new PolicyApiService( this.policyService, @@ -388,9 +392,9 @@ export default class MainBackground { this.logService, this.keyConnectorService, this.stateService, - this.organizationService, this.providerService, this.folderApiService, + this.syncNotifierService, logoutCallback ); this.eventService = new EventService( diff --git a/apps/browser/src/background/service_factories/organization-service.factory.ts b/apps/browser/src/background/service_factories/organization-service.factory.ts index 87692e64391..2e7c31b596e 100644 --- a/apps/browser/src/background/service_factories/organization-service.factory.ts +++ b/apps/browser/src/background/service_factories/organization-service.factory.ts @@ -1,12 +1,17 @@ -import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; +import { OrganizationService as AbstractOrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { FactoryOptions, CachedServices, factory } from "./factory-options"; import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory"; +import { + syncNotifierServiceFactory, + SyncNotifierServiceInitOptions, +} from "./sync-notifier-service.factory"; type OrganizationServiceFactoryOptions = FactoryOptions; export type OrganizationServiceInitOptions = OrganizationServiceFactoryOptions & + SyncNotifierServiceInitOptions & StateServiceInitOptions; export function organizationServiceFactory( @@ -17,6 +22,10 @@ export function organizationServiceFactory( cache, "organizationService", opts, - async () => new OrganizationService(await stateServiceFactory(cache, opts)) + async () => + new OrganizationService( + await stateServiceFactory(cache, opts), + await syncNotifierServiceFactory(cache, opts) + ) ); } diff --git a/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts b/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts new file mode 100644 index 00000000000..58699bdff58 --- /dev/null +++ b/apps/browser/src/background/service_factories/sync-notifier-service.factory.ts @@ -0,0 +1,17 @@ +import { SyncNotifierService as AbstractSyncNotifierService } from "@bitwarden/common/abstractions/sync/syncNotifier.service.abstraction"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; + +import { FactoryOptions, CachedServices, factory } from "./factory-options"; + +type SyncNotifierServiceFactoryOptions = FactoryOptions; + +export type SyncNotifierServiceInitOptions = SyncNotifierServiceFactoryOptions; + +export function syncNotifierServiceFactory( + cache: { syncNotifierService?: AbstractSyncNotifierService } & CachedServices, + opts: SyncNotifierServiceInitOptions +): Promise { + return factory(cache, "syncNotifierService", opts, () => + Promise.resolve(new SyncNotifierService()) + ); +} diff --git a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts index c82f2700213..b177d118f82 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-sync.decorator.spec.ts @@ -19,6 +19,7 @@ describe("sessionSync decorator", () => { ctor: ctor, initializer: initializer, }), + testClass.testProperty.complete(), ]); }); }); diff --git a/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts b/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts index f2df60ad7a4..5286cece1bb 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-syncer.spec.ts @@ -5,6 +5,7 @@ import { BrowserApi } from "../../browser/browserApi"; import { StateService } from "../../services/abstractions/state.service"; import { SessionSyncer } from "./session-syncer"; +import { SyncedItemMetadata } from "./sync-item-metadata"; describe("session syncer", () => { const propertyKey = "behaviorSubject"; @@ -140,12 +141,14 @@ describe("session syncer", () => { }); it("should update from message on emit from another instance", async () => { + const builder = jest.fn(); + jest.spyOn(SyncedItemMetadata, "builder").mockReturnValue(builder); stateService.getFromSessionMemory.mockResolvedValue("test"); await sut.updateFromMessage({ command: `${sessionKey}_update`, id: "different_id" }); expect(stateService.getFromSessionMemory).toHaveBeenCalledTimes(1); - expect(stateService.getFromSessionMemory).toHaveBeenCalledWith(sessionKey); + expect(stateService.getFromSessionMemory).toHaveBeenCalledWith(sessionKey, builder); expect(nextSpy).toHaveBeenCalledTimes(1); expect(nextSpy).toHaveBeenCalledWith("test"); diff --git a/apps/browser/src/decorators/session-sync-observable/session-syncer.ts b/apps/browser/src/decorators/session-sync-observable/session-syncer.ts index 0c97b983f75..c757a44c7f2 100644 --- a/apps/browser/src/decorators/session-sync-observable/session-syncer.ts +++ b/apps/browser/src/decorators/session-sync-observable/session-syncer.ts @@ -66,8 +66,8 @@ export class SessionSyncer { if (message.command != this.updateMessageCommand || message.id === this.id) { return; } - const keyValuePair = await this.stateService.getFromSessionMemory(this.metaData.sessionKey); - const value = SyncedItemMetadata.buildFromKeyValuePair(keyValuePair, this.metaData); + const builder = SyncedItemMetadata.builder(this.metaData); + const value = await this.stateService.getFromSessionMemory(this.metaData.sessionKey, builder); this.ignoreNextUpdate = true; this.behaviorSubject.next(value); } diff --git a/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts b/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts index e225db61967..2b3f4715d46 100644 --- a/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts +++ b/apps/browser/src/decorators/session-sync-observable/sync-item-metadata.ts @@ -5,19 +5,15 @@ export class SyncedItemMetadata { initializer?: (keyValuePair: any) => any; initializeAsArray?: boolean; - static buildFromKeyValuePair(keyValuePair: any, metadata: SyncedItemMetadata): any { - const builder = SyncedItemMetadata.getBuilder(metadata); - + static builder(metadata: SyncedItemMetadata): (o: any) => any { + const itemBuilder = + metadata.initializer != null + ? metadata.initializer + : (o: any) => Object.assign(new metadata.ctor(), o); if (metadata.initializeAsArray) { - return keyValuePair.map((o: any) => builder(o)); + return (keyValuePair: any) => keyValuePair.map((o: any) => itemBuilder(o)); } else { - return builder(keyValuePair); + return (keyValuePair: any) => itemBuilder(keyValuePair); } } - - private static getBuilder(metadata: SyncedItemMetadata): (o: any) => any { - return metadata.initializer != null - ? metadata.initializer - : (o: any) => Object.assign(new metadata.ctor(), o); - } } diff --git a/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts b/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts index da65be04903..5cd869a5b67 100644 --- a/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts +++ b/apps/browser/src/decorators/session-sync-observable/synced-item-metadata.spec.ts @@ -1,59 +1,39 @@ import { SyncedItemMetadata } from "./sync-item-metadata"; -describe("build from key value pair", () => { +describe("builder", () => { const propertyKey = "propertyKey"; const key = "key"; const initializer = (s: any) => "used initializer"; class TestClass {} const ctor = TestClass; - it("should call initializer if provided", () => { - const actual = SyncedItemMetadata.buildFromKeyValuePair( - {}, - { - propertyKey, - sessionKey: "key", - initializer: initializer, - } - ); - - expect(actual).toEqual("used initializer"); + it("should use initializer if provided", () => { + const metadata = { propertyKey, sessionKey: key, initializer }; + const builder = SyncedItemMetadata.builder(metadata); + expect(builder({})).toBe("used initializer"); }); - it("should call ctor if provided", () => { - const expected = { provided: "value" }; - const actual = SyncedItemMetadata.buildFromKeyValuePair(expected, { - propertyKey, - sessionKey: key, - ctor: ctor, - }); - - expect(actual).toBeInstanceOf(ctor); - expect(actual).toEqual(expect.objectContaining(expected)); + it("should use ctor if initializer is not provided", () => { + const metadata = { propertyKey, sessionKey: key, ctor }; + const builder = SyncedItemMetadata.builder(metadata); + expect(builder({})).toBeInstanceOf(TestClass); }); - it("should prefer using initializer if both are provided", () => { - const actual = SyncedItemMetadata.buildFromKeyValuePair( - {}, - { - propertyKey, - sessionKey: key, - initializer: initializer, - ctor: ctor, - } - ); - - expect(actual).toEqual("used initializer"); + it("should prefer initializer over ctor", () => { + const metadata = { propertyKey, sessionKey: key, ctor, initializer }; + const builder = SyncedItemMetadata.builder(metadata); + expect(builder({})).toBe("used initializer"); }); it("should honor initialize as array", () => { - const actual = SyncedItemMetadata.buildFromKeyValuePair([1, 2], { + const metadata = { propertyKey, sessionKey: key, initializer: initializer, initializeAsArray: true, - }); - - expect(actual).toEqual(["used initializer", "used initializer"]); + }; + const builder = SyncedItemMetadata.builder(metadata); + expect(builder([{}])).toBeInstanceOf(Array); + expect(builder([{}])[0]).toBe("used initializer"); }); }); diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index 9d0b491481c..d29223559e0 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2022.9.0", + "version": "2022.9.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index 509fe467c65..68a9ff30c88 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2022.9.0", + "version": "2022.9.1", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/popup/accounts/login.component.html b/apps/browser/src/popup/accounts/login.component.html index 4c18805f452..1b32f63819a 100644 --- a/apps/browser/src/popup/accounts/login.component.html +++ b/apps/browser/src/popup/accounts/login.component.html @@ -1,4 +1,4 @@ -
+
@@ -18,15 +18,7 @@
- +
@@ -34,10 +26,8 @@
diff --git a/apps/browser/src/popup/accounts/login.component.ts b/apps/browser/src/popup/accounts/login.component.ts index 83c654d6737..5028af06bfb 100644 --- a/apps/browser/src/popup/accounts/login.component.ts +++ b/apps/browser/src/popup/accounts/login.component.ts @@ -1,10 +1,12 @@ import { Component, NgZone } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/components/login.component"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; @@ -30,7 +32,9 @@ export class LoginComponent extends BaseLoginComponent { protected cryptoFunctionService: CryptoFunctionService, syncService: SyncService, logService: LogService, - ngZone: NgZone + ngZone: NgZone, + formBuilder: FormBuilder, + formValidationErrorService: FormValidationErrorsService ) { super( authService, @@ -42,7 +46,9 @@ export class LoginComponent extends BaseLoginComponent { passwordGenerationService, cryptoFunctionService, logService, - ngZone + ngZone, + formBuilder, + formValidationErrorService ); super.onSuccessfulLogin = async () => { await syncService.fullSync(true); diff --git a/apps/browser/src/popup/components/cipher-row.component.html b/apps/browser/src/popup/components/cipher-row.component.html index fc78fd9ccfa..fce966adb4d 100644 --- a/apps/browser/src/popup/components/cipher-row.component.html +++ b/apps/browser/src/popup/components/cipher-row.component.html @@ -15,7 +15,7 @@
- {{ cipher.name }} + {{ cipher.name | ellipsis: 20 }} {{ "serverVersion" | i18n }}: {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

@@ -24,7 +24,7 @@ {{ "serverVersion" | i18n }} ({{ "thirdParty" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

@@ -36,7 +36,7 @@ {{ "serverVersion" | i18n }} ({{ "selfHosted" | i18n }}): {{ this.serverConfig?.version }} - ({{ "lastSeenOn" | i18n }}: {{ serverConfig.utcDate | date: "mediumDate" }}) + ({{ "lastSeenOn" | i18n: (serverConfig.utcDate | date: "mediumDate") }})

diff --git a/apps/browser/src/popup/vault/add-edit.component.ts b/apps/browser/src/popup/vault/add-edit.component.ts index f5062051c2e..d220a24a0d8 100644 --- a/apps/browser/src/popup/vault/add-edit.component.ts +++ b/apps/browser/src/popup/vault/add-edit.component.ts @@ -12,7 +12,7 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; diff --git a/apps/browser/src/popup/vault/ciphers.component.ts b/apps/browser/src/popup/vault/ciphers.component.ts index 4346ad7a668..60a92e238c2 100644 --- a/apps/browser/src/popup/vault/ciphers.component.ts +++ b/apps/browser/src/popup/vault/ciphers.component.ts @@ -10,7 +10,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { CipherType } from "@bitwarden/common/enums/cipherType"; @@ -78,7 +78,7 @@ export class CiphersComponent extends BaseCiphersComponent implements OnInit, On async ngOnInit() { this.searchTypeSearch = !this.platformUtilsService.isSafari(); - this.showOrganizations = await this.organizationService.hasOrganizations(); + this.showOrganizations = this.organizationService.hasOrganizations(); this.vaultFilter = this.vaultFilterService.getVaultFilter(); // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe this.route.queryParams.pipe(first()).subscribe(async (params) => { diff --git a/apps/browser/src/popup/vault/current-tab.component.ts b/apps/browser/src/popup/vault/current-tab.component.ts index 2f3569841f4..f3e97dd233d 100644 --- a/apps/browser/src/popup/vault/current-tab.component.ts +++ b/apps/browser/src/popup/vault/current-tab.component.ts @@ -4,7 +4,7 @@ import { Router } from "@angular/router"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; @@ -219,7 +219,7 @@ export class CurrentTabComponent implements OnInit, OnDestroy { const otherTypes: CipherType[] = []; const dontShowCards = await this.stateService.getDontShowCardsCurrentTab(); const dontShowIdentities = await this.stateService.getDontShowIdentitiesCurrentTab(); - this.showOrganizations = await this.organizationService.hasOrganizations(); + this.showOrganizations = this.organizationService.hasOrganizations(); if (!dontShowCards) { otherTypes.push(CipherType.Card); } diff --git a/apps/browser/src/popup/vault/share.component.html b/apps/browser/src/popup/vault/share.component.html index ad1447f6f65..dcec42415c0 100644 --- a/apps/browser/src/popup/vault/share.component.html +++ b/apps/browser/src/popup/vault/share.component.html @@ -1,70 +1,76 @@ -
-
- -
-

- {{ "moveToOrganization" | i18n }} -

-
- -
-
-
-
-
-
- {{ "noOrganizationsList" | i18n }} -
+ +
+
+
-
-
- - -
-
- -
-
-

- {{ "collections" | i18n }} -

-
-
- {{ "noCollectionsInList" | i18n }} -
-
-
-
+ {{ "moveToOrganization" | i18n }} + +
+ +
+
+
+
+
+
+ {{ "noOrganizationsList" | i18n }} +
+
+
+
+ + +
+
+
- -
+
+

+ {{ "collections" | i18n }} +

+
+
+ {{ "noCollectionsInList" | i18n }} +
+
+
+
+ + +
+
+
+ + diff --git a/apps/browser/src/popup/vault/share.component.ts b/apps/browser/src/popup/vault/share.component.ts index bfff215533e..112b432c0e0 100644 --- a/apps/browser/src/popup/vault/share.component.ts +++ b/apps/browser/src/popup/vault/share.component.ts @@ -7,7 +7,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; @Component({ diff --git a/apps/browser/src/popup/vault/vault-select.component.html b/apps/browser/src/popup/vault/vault-select.component.html index ec4d4ff9e3e..95d1effd7fd 100644 --- a/apps/browser/src/popup/vault/vault-select.component.html +++ b/apps/browser/src/popup/vault/vault-select.component.html @@ -1,64 +1,70 @@ -
- - - + + + +
+ + + diff --git a/apps/browser/src/popup/vault/vault-select.component.ts b/apps/browser/src/popup/vault/vault-select.component.ts index d12463f2c11..04ae04d0fab 100644 --- a/apps/browser/src/popup/vault/vault-select.component.ts +++ b/apps/browser/src/popup/vault/vault-select.component.ts @@ -5,19 +5,19 @@ import { Component, ElementRef, EventEmitter, - NgZone, OnInit, Output, TemplateRef, ViewChild, ViewContainerRef, HostListener, + OnDestroy, } from "@angular/core"; -import { merge } from "rxjs"; +import { BehaviorSubject, concatMap, map, merge, Observable, Subject, takeUntil } from "rxjs"; import { VaultFilter } from "@bitwarden/angular/vault/vault-filter/models/vault-filter.model"; -import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { Organization } from "@bitwarden/common/models/domain/organization"; @@ -47,20 +47,22 @@ import { VaultFilterService } from "../../services/vaultFilter.service"; ]), ], }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class VaultSelectComponent implements OnInit { +export class VaultSelectComponent implements OnInit, OnDestroy { @Output() onVaultSelectionChanged = new EventEmitter(); @ViewChild("toggleVaults", { read: ElementRef }) buttonRef: ElementRef; @ViewChild("vaultSelectorTemplate", { read: TemplateRef }) templateRef: TemplateRef; + private _selectedVault = new BehaviorSubject(null); + isOpen = false; loaded = false; - organizations: Organization[]; + organizations$: Observable; + selectedVault$: Observable = this._selectedVault.asObservable(); + vaultFilter: VaultFilter = new VaultFilter(); - vaultFilterDisplay = ""; - enforcePersonalOwnwership = false; + enforcePersonalOwnership = false; overlayPostition: ConnectedPosition[] = [ { originX: "start", @@ -71,22 +73,22 @@ export class VaultSelectComponent implements OnInit { ]; private overlayRef: OverlayRef; + private _destroy = new Subject(); - get show() { + shouldShow(organizations: Organization[]): boolean { return ( - (this.organizations.length > 0 && !this.enforcePersonalOwnwership) || - (this.organizations.length > 1 && this.enforcePersonalOwnwership) + (organizations.length > 0 && !this.enforcePersonalOwnership) || + (organizations.length > 1 && this.enforcePersonalOwnership) ); } constructor( private vaultFilterService: VaultFilterService, private i18nService: I18nService, - private ngZone: NgZone, - private broadcasterService: BroadcasterService, private overlay: Overlay, private viewContainerRef: ViewContainerRef, - private platformUtilsService: PlatformUtilsService + private platformUtilsService: PlatformUtilsService, + private organizationService: OrganizationService ) {} @HostListener("document:keydown.escape", ["$event"]) @@ -98,46 +100,45 @@ export class VaultSelectComponent implements OnInit { } async ngOnInit() { - await this.load(); - this.broadcasterService.subscribe(this.constructor.name, (message: any) => { - this.ngZone.run(async () => { - switch (message.command) { - case "syncCompleted": - await this.load(); - break; - default: - break; - } - }); - }); + this.organizations$ = this.organizationService.organizations$ + .pipe(takeUntil(this._destroy)) + .pipe(map((orgs) => orgs.sort((a, b) => a.name.localeCompare(b.name)))); + + this.organizations$ + .pipe( + concatMap(async (organizations) => { + this.enforcePersonalOwnership = + await this.vaultFilterService.checkForPersonalOwnershipPolicy(); + + if (this.shouldShow(organizations)) { + if (this.enforcePersonalOwnership && !this.vaultFilter.myVaultOnly) { + const firstOrganization = organizations[0]; + this._selectedVault.next(firstOrganization.name); + this.vaultFilterService.setVaultFilter(firstOrganization.id); + this.vaultFilter.selectedOrganizationId = firstOrganization.id; + } else if (this.vaultFilter.myVaultOnly) { + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); + } else if (this.vaultFilter.selectedOrganizationId != null) { + const selectedOrganization = organizations.find( + (o) => o.id === this.vaultFilter.selectedOrganizationId + ); + this._selectedVault.next(selectedOrganization.name); + } else { + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); + } + } + }) + ) + .pipe(takeUntil(this._destroy)) + .subscribe(); + + this.loaded = true; } - async load() { - this.vaultFilter = this.vaultFilterService.getVaultFilter(); - this.organizations = (await this.vaultFilterService.buildOrganizations()).sort((a, b) => - a.name.localeCompare(b.name) - ); - this.enforcePersonalOwnwership = - await this.vaultFilterService.checkForPersonalOwnershipPolicy(); - - if (this.show) { - if (this.enforcePersonalOwnwership && !this.vaultFilter.myVaultOnly) { - this.vaultFilterService.setVaultFilter(this.organizations[0].id); - this.vaultFilter.selectedOrganizationId = this.organizations[0].id; - this.vaultFilterDisplay = this.organizations.find( - (o) => o.id === this.vaultFilter.selectedOrganizationId - ).name; - } else if (this.vaultFilter.myVaultOnly) { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault); - } else if (this.vaultFilter.selectedOrganizationId != null) { - this.vaultFilterDisplay = this.organizations.find( - (o) => o.id === this.vaultFilter.selectedOrganizationId - ).name; - } else { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults); - } - } - this.loaded = true; + ngOnDestroy(): void { + this._destroy.next(); + this._destroy.complete(); + this._selectedVault.complete(); } openOverlay() { @@ -191,20 +192,20 @@ export class VaultSelectComponent implements OnInit { this.i18nService.t("disabledOrganizationFilterError") ); } else { - this.vaultFilterDisplay = organization.name; + this._selectedVault.next(organization.name); this.vaultFilterService.setVaultFilter(organization.id); this.onVaultSelectionChanged.emit(); this.close(); } } selectAllVaults() { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.allVaults); + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.allVaults)); this.vaultFilterService.setVaultFilter(this.vaultFilterService.allVaults); this.onVaultSelectionChanged.emit(); this.close(); } selectMyVault() { - this.vaultFilterDisplay = this.i18nService.t(this.vaultFilterService.myVault); + this._selectedVault.next(this.i18nService.t(this.vaultFilterService.myVault)); this.vaultFilterService.setVaultFilter(this.vaultFilterService.myVault); this.onVaultSelectionChanged.emit(); this.close(); diff --git a/apps/browser/src/popup/vault/view-custom-fields.component.html b/apps/browser/src/popup/vault/view-custom-fields.component.html index ebedd30776f..4fbca28734b 100644 --- a/apps/browser/src/popup/vault/view-custom-fields.component.html +++ b/apps/browser/src/popup/vault/view-custom-fields.component.html @@ -5,7 +5,14 @@
- {{ field.name }} + {{ field.name }} + {{ field.name }}
{{ field.value || " " }}
diff --git a/apps/browser/src/popup/vault/view.component.html b/apps/browser/src/popup/vault/view.component.html index e168879dd06..0b5d0fb1528 100644 --- a/apps/browser/src/popup/vault/view.component.html +++ b/apps/browser/src/popup/vault/view.component.html @@ -18,7 +18,13 @@
- +
@@ -139,7 +145,7 @@
-
+
{{ "verificationCodeTotp" | i18n }} @@ -195,12 +198,22 @@
- {{ "cardholderName" | i18n }} + {{ "cardholderName" | i18n }} {{ cipher.card.cardholderName }}
- {{ "number" | i18n }} + {{ "number" | i18n }} {{ cipher.card.maskedNumber | creditCardNumber: cipher.card.brand }} @@ -236,16 +249,31 @@
- {{ "brand" | i18n }} + {{ "brand" | i18n }} {{ cipher.card.brand }}
- {{ "expiration" | i18n }} + {{ "expiration" | i18n }} {{ cipher.card.expiration }}
- {{ "securityCode" | i18n }} + {{ "securityCode" | i18n }} {{ cipher.card.maskedCode }} {{ cipher.card.code }}
@@ -280,42 +308,98 @@
- {{ "identityName" | i18n }} + {{ "identityName" | i18n }} {{ cipher.identity.fullName }}
- {{ "username" | i18n }} + {{ "username" | i18n }} {{ cipher.identity.username }}
- {{ "company" | i18n }} + {{ "company" | i18n }} {{ cipher.identity.company }}
- {{ "ssn" | i18n }} + {{ "ssn" | i18n }} {{ cipher.identity.ssn }}
- {{ "passportNumber" | i18n }} + {{ "passportNumber" | i18n }} {{ cipher.identity.passportNumber }}
- {{ "licenseNumber" | i18n }} + {{ "licenseNumber" | i18n }} {{ cipher.identity.licenseNumber }}
- {{ "email" | i18n }} + {{ "email" | i18n }} {{ cipher.identity.email }}
- {{ "phone" | i18n }} + {{ "phone" | i18n }} {{ cipher.identity.phone }}
- {{ "address" | i18n }} + {{ "address" | i18n }}
{{ cipher.identity.address1 }}
{{ cipher.identity.address2 }}
{{ cipher.identity.address3 }}
@@ -332,12 +416,22 @@ *ngFor="let u of cipher.login.uris; let i = index" >
- - + +

- +

diff --git a/apps/browser/src/services/abstractions/state.service.ts b/apps/browser/src/services/abstractions/state.service.ts index ca2a5ced7fa..2f0112ff64f 100644 --- a/apps/browser/src/services/abstractions/state.service.ts +++ b/apps/browser/src/services/abstractions/state.service.ts @@ -1,3 +1,5 @@ +import { Jsonify } from "type-fest"; + import { StateService as BaseStateServiceAbstraction } from "@bitwarden/common/abstractions/state.service"; import { StorageOptions } from "@bitwarden/common/models/domain/storageOptions"; @@ -7,7 +9,7 @@ import { BrowserGroupingsComponentState } from "src/models/browserGroupingsCompo import { BrowserSendComponentState } from "src/models/browserSendComponentState"; export abstract class StateService extends BaseStateServiceAbstraction { - abstract getFromSessionMemory(key: string): Promise; + abstract getFromSessionMemory(key: string, deserializer?: (obj: Jsonify) => T): Promise; abstract setInSessionMemory(key: string, value: any): Promise; getBrowserGroupingComponentState: ( options?: StorageOptions diff --git a/apps/browser/src/services/localBackedSessionStorage.service.spec.ts b/apps/browser/src/services/localBackedSessionStorage.service.spec.ts index de88b6d8b2f..f7101ddae2e 100644 --- a/apps/browser/src/services/localBackedSessionStorage.service.spec.ts +++ b/apps/browser/src/services/localBackedSessionStorage.service.spec.ts @@ -96,6 +96,13 @@ describe("Browser Session Storage Service", () => { expect(cache.has("test")).toBe(true); expect(cache.get("test")).toEqual(session.test); }); + + it("should use a deserializer if provided", async () => { + const deserializer = jest.fn().mockReturnValue(testObj); + const result = await sut.get("test", { deserializer: deserializer }); + expect(deserializer).toHaveBeenCalledWith(session.test); + expect(result).toEqual(testObj); + }); }); }); }); diff --git a/apps/browser/src/services/localBackedSessionStorage.service.ts b/apps/browser/src/services/localBackedSessionStorage.service.ts index cdc7d4cf154..dea2e75a5ed 100644 --- a/apps/browser/src/services/localBackedSessionStorage.service.ts +++ b/apps/browser/src/services/localBackedSessionStorage.service.ts @@ -1,6 +1,12 @@ +import { Jsonify } from "type-fest"; + import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service"; -import { AbstractCachedStorageService } from "@bitwarden/common/abstractions/storage.service"; +import { + AbstractCachedStorageService, + MemoryStorageServiceInterface, +} from "@bitwarden/common/abstractions/storage.service"; import { EncString } from "@bitwarden/common/models/domain/encString"; +import { MemoryStorageOptions } from "@bitwarden/common/models/domain/storageOptions"; import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey"; import { devFlag } from "../decorators/dev-flag.decorator"; @@ -15,7 +21,10 @@ const keys = { sessionKey: "session", }; -export class LocalBackedSessionStorageService extends AbstractCachedStorageService { +export class LocalBackedSessionStorageService + extends AbstractCachedStorageService + implements MemoryStorageServiceInterface +{ private cache = new Map(); private localStorage = new BrowserLocalStorageService(); private sessionStorage = new BrowserMemoryStorageService(); @@ -27,21 +36,26 @@ export class LocalBackedSessionStorageService extends AbstractCachedStorageServi super(); } - async get(key: string): Promise { + async get(key: string, options?: MemoryStorageOptions): Promise { if (this.cache.has(key)) { return this.cache.get(key) as T; } - return await this.getBypassCache(key); + return await this.getBypassCache(key, options); } - async getBypassCache(key: string): Promise { + async getBypassCache(key: string, options?: MemoryStorageOptions): Promise { const session = await this.getLocalSession(await this.getSessionEncKey()); if (session == null || !Object.keys(session).includes(key)) { return null; } - this.cache.set(key, session[key]); + let value = session[key]; + if (options?.deserializer != null) { + value = options.deserializer(value as Jsonify); + } + + this.cache.set(key, value); return this.cache.get(key) as T; } diff --git a/apps/browser/src/services/state.service.spec.ts b/apps/browser/src/services/state.service.spec.ts index 60813c22931..f3b6c74a5e3 100644 --- a/apps/browser/src/services/state.service.spec.ts +++ b/apps/browser/src/services/state.service.spec.ts @@ -1,8 +1,8 @@ -import { Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; +import { Arg, Substitute, SubstituteOf } from "@fluffy-spoon/substitute"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { - AbstractCachedStorageService, + MemoryStorageServiceInterface, AbstractStorageService, } from "@bitwarden/common/abstractions/storage.service"; import { SendType } from "@bitwarden/common/enums/sendType"; @@ -49,7 +49,7 @@ describe("Browser State Service", () => { }); describe("direct memory storage access", () => { - let memoryStorageService: AbstractCachedStorageService; + let memoryStorageService: LocalBackedSessionStorageService; beforeEach(() => { // We need `AbstractCachedStorageService` in the prototype chain to correctly test cache bypass. @@ -79,12 +79,12 @@ describe("Browser State Service", () => { }); describe("state methods", () => { - let memoryStorageService: SubstituteOf; + let memoryStorageService: SubstituteOf; beforeEach(() => { memoryStorageService = Substitute.for(); const stateGetter = (key: string) => Promise.resolve(JSON.parse(JSON.stringify(state))); - memoryStorageService.get("state").mimicks(stateGetter); + memoryStorageService.get("state", Arg.any()).mimicks(stateGetter); sut = new StateService( diskStorageService, diff --git a/apps/browser/src/services/state.service.ts b/apps/browser/src/services/state.service.ts index 6685f495e06..78bc721031a 100644 --- a/apps/browser/src/services/state.service.ts +++ b/apps/browser/src/services/state.service.ts @@ -1,3 +1,5 @@ +import { Jsonify } from "type-fest"; + import { AbstractCachedStorageService } from "@bitwarden/common/abstractions/storage.service"; import { GlobalState } from "@bitwarden/common/models/domain/globalState"; import { StorageOptions } from "@bitwarden/common/models/domain/storageOptions"; @@ -17,9 +19,9 @@ export class StateService extends BaseStateService implements StateServiceAbstraction { - async getFromSessionMemory(key: string): Promise { + async getFromSessionMemory(key: string, deserializer?: (obj: Jsonify) => T): Promise { return this.memoryStorageService instanceof AbstractCachedStorageService - ? await this.memoryStorageService.getBypassCache(key) + ? await this.memoryStorageService.getBypassCache(key, { deserializer: deserializer }) : await this.memoryStorageService.get(key); } diff --git a/apps/browser/src/services/vaultFilter.service.ts b/apps/browser/src/services/vaultFilter.service.ts index b921a21292d..77016638d8f 100644 --- a/apps/browser/src/services/vaultFilter.service.ts +++ b/apps/browser/src/services/vaultFilter.service.ts @@ -3,7 +3,7 @@ import { VaultFilterService as BaseVaultFilterService } from "@bitwarden/angular import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherView } from "@bitwarden/common/models/view/cipherView"; diff --git a/apps/browser/store/locales/be/copy.resx b/apps/browser/store/locales/be/copy.resx index 76c10a400e4..f0f63d5394a 100644 --- a/apps/browser/store/locales/be/copy.resx +++ b/apps/browser/store/locales/be/copy.resx @@ -141,7 +141,7 @@ Bitwarden — гэта праграмнае забеспячэнне з адкр Сінхранізацыя і доступ да сховішча з некалькіх прылад - Кіруйце ўсімі вашымі імёнамі карыстальніка і паролямі з бяспечнага сховішча + Кіруйце ўсімі вашымі лагінамі і паролямі з бяспечнага сховішча Хутка і аўтаматычна запаўняйце свае ўліковыя даныя на любым вэб-сайце @@ -150,7 +150,7 @@ Bitwarden — гэта праграмнае забеспячэнне з адкр У вас ёсць зручны доступ да сховішча з кантэкстнага меню - Аўтаматычна генерыруйце моцныя, выпадковыя і бяспечныя паролі + Аўтаматычна генерыруйце надзейныя, выпадковыя і бяспечныя паролі Вашыя звесткі надзейна захоўваюцца, дзякуючы шыфраванню AES-256 diff --git a/apps/browser/store/locales/bg/copy.resx b/apps/browser/store/locales/bg/copy.resx index d632c325ce8..21a01a58e49 100644 --- a/apps/browser/store/locales/bg/copy.resx +++ b/apps/browser/store/locales/bg/copy.resx @@ -124,11 +124,32 @@ Сигурен и свободен управител на пароли за всички устройства - Bitwarden е най-лесният и надежден начин да съхранявате регистрации и пароли като ги синхронизирате на всички свои устройства. -Кражбата на пароли е тежък проблем. Сайтовете в Интернет, програмите и мобилните приложения биват атакувани всеки ден. Пробивите в сигурността са факт и паролите биват откраднати. Ако използвате една и съща парола в много програми или сайтове, злонамерени лица могат лесно да достъпят вашата е-поща, електронно банкиране и други важни регистрации. -Експертите по сигурността препоръчват да ползвате различна, случайно генерирана парола за всяка отделна регистрация. Как да управлявате всичките тези пароли? Bitwarden ви позволява лесно да ги създавате, съхранявате и ползвате. -Bitwarden съхранява всички данни в шифриран трезор, който се синхронизира на всички устройства, които ползвате. Шифрирането се извършва преди данните да напуснат устройството ви — така само вие имате достъп до тях. Дори и екипът на Bitwarden не може да прочете данните, дори и да се опита. Данните са защитени чрез AES с 256-битов ключ, контролни суми с добавени случайни данни и удължаване на ключа с PBKDF2 SHA-256. -Bitwarden е със 100% отворен код! Изходният код е наличен в сайта GitHub и всеки може да го преглежда, извърши одит и даже да допринесе за Bitwarden. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. + +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. + +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. + +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Сигурен и свободен управител на пароли за всички устройства diff --git a/apps/browser/store/locales/bn/copy.resx b/apps/browser/store/locales/bn/copy.resx index 3a40359b33f..a8eb4f7c756 100644 --- a/apps/browser/store/locales/bn/copy.resx +++ b/apps/browser/store/locales/bn/copy.resx @@ -124,11 +124,32 @@ আপনার সমস্ত ডিভাইসের জন্য একটি সুরক্ষিত এবং বিনামূল্যের পাসওয়ার্ড ব্যবস্থাপক - বিটওয়ার্ডেন আপনার সমস্ত লগইন এবং পাসওয়ার্ডগুলি সহজেই আপনার সমস্ত ডিভাইসের সাথে সিঙ্ক করার সময় সংরক্ষণ করার সবচেয়ে সহজ এবং নিরাপদ উপায়। -পাসওয়ার্ড চুরি একটি গুরুতর সমস্যা। আপনি যে ওয়েবসাইটগুলি এবং অ্যাপ্লিকেশনগুলি ব্যবহার করেন সেগুলি প্রতিদিন আক্রমণের শিকার হয়। সুরক্ষা লঙ্ঘন ঘটে এবং আপনার পাসওয়ার্ডগুলি চুরি হয়ে যায়। আপনি যখন অ্যাপ্লিকেশন এবং ওয়েবসাইট জুড়ে একই পাসওয়ার্ডগুলি পুনরায় ব্যবহার করেন হ্যাকাররা সহজেই আপনার ইমেল, ব্যাংক এবং অন্যান্য গুরুত্বপূর্ণ অ্যাকাউন্টগুলিতে ব্যাবহার করতে পারে। -সুরক্ষা বিশেষজ্ঞরা আপনার তৈরি প্রতিটি অ্যাকাউন্টের জন্য একটি পৃথক, এলোমেলোভাবে উৎপন্ন পাসওয়ার্ড ব্যবহার করার পরামর্শ দেয়। কিন্তু আপনি কীভাবে এই সমস্ত পাসওয়ার্ড পরিচালনা করবেন? Bitwarden আপনার পাসওয়ার্ডগুলি তৈরি, সঞ্চয় এবং ব্যাবহার করা আপনার পক্ষে সহজ করে তোলে। -Bitwarden আপনার সমস্ত লগইন একটি এনক্রিপ্ট করা ভল্টে সঞ্চয় করে যা আপনার সমস্ত ডিভাইস জুড়ে সিঙ্ক করে। যেহেতু আপনার ডিভাইসটি ছাড়ার আগে এটি সম্পূর্ণরূপে এনক্রিপ্ট করা হয়েছে, শুধুমাত্র আপনারই ডেটাতে ব্যাবহারাধিকার রয়েছে। এমনকি আমরা Bitwarden এর দল চাইলেও আপনার তথ্যগুলি পড়তে পারব না। আপনার ডেটা AES-256 বিট এনক্রিপশন, সল্টেড হ্যাশিং এবং PBKDF2 SHA-256 দিয়ে নামমুদ্রাম্কিত করা হয়েছে। -Bitwarden ১০০% মুক্ত সফ্টওয়্যার। Bitwarden এর উৎস কোডটি গিটহাবটিতে হোস্ট করা হয়েছে এবং Bitwarden কোডবেস সকলের পর্যালোচনা, নিরীক্ষণ এবং অবদানের জন্য মুক্ত। + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. + +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. + +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. + +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + আপনার সমস্ত ডিভাইসের জন্য একটি সুরক্ষিত এবং বিনামূল্যের পাসওয়ার্ড ব্যবস্থাপক diff --git a/apps/browser/store/locales/ca/copy.resx b/apps/browser/store/locales/ca/copy.resx index aaabe81d590..0bd454addb2 100644 --- a/apps/browser/store/locales/ca/copy.resx +++ b/apps/browser/store/locales/ca/copy.resx @@ -148,7 +148,8 @@ Traduccions globals Les traduccions de Bitwarden existeixen en 40 idiomes i creixen, gràcies a la nostra comunitat global. Aplicacions de plataforma creuada -Assegureu-vos i compartiu dades sensibles a la vostra caixa forta de Bitwarden des de qualsevol navegador, dispositiu mòbil o S.O. d'escriptori, i molt més. +Assegureu-vos i compartiu dades sensibles a la vostra caixa forta de Bitwarden des de qualsevol navegador, dispositiu mòbil o S.O. d'escriptori, i molt més. + Administrador de contrasenyes segur i gratuït per a tots els vostres dispositius diff --git a/apps/browser/store/locales/cs/copy.resx b/apps/browser/store/locales/cs/copy.resx index 36a54971d2c..76bd3a97397 100644 --- a/apps/browser/store/locales/cs/copy.resx +++ b/apps/browser/store/locales/cs/copy.resx @@ -124,13 +124,32 @@ Bezpečný a bezplatný správce hesel pro všechna vaše zařízení - bitwarden je nejjednodušší a nejbezpečnější způsob, jak uchovávat veškeré své přihlašovací údaje a zároveň je mít pohodlně synchronizované mezi všemi svými zařízeními. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Krádež hesla je velice vážný problém. Stránky a aplikace, které každodenně používáte, jsou často pod útokem a vaše hesla mohou být odcizena. Pokud používáte stejné heslo mezi více aplikacemi nebo stránkami, hackeři se mohou snadno dostat k vaší emailové schránce, bankovnímu účtu či do jiných důležitých účtů. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Bezpečnostní experti proto doporučují používat různá, silná a náhodně generovaná hesla pro každý účet zvlášť. Ale jak tato všechna hesla spravovat? bitwarden vám ulehčí jejich správu, ale také jejich generování nebo sdílení. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -bitwarden uchovává veškeré vaše přihlašovací údaje v zašifrovaném trezoru, který se synchronizuje mezi všemi vašimi zařízeními. Jelikož jsou zašifrována ještě před opuštěním vašeho zařízení, máte přístup ke svým datům pouze vy. Dokonce ani tým v bitwardenu nemůže číst vaše data a to ani kdybychom chtěli. Vaše data jsou totiž zakódována pomocí šifrovávání AES-256, náhodným hashem a PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Bezpečný a bezplatný správce hesel pro všechna vaše zařízení diff --git a/apps/browser/store/locales/da/copy.resx b/apps/browser/store/locales/da/copy.resx index 6159bb2d67c..858c56dea97 100644 --- a/apps/browser/store/locales/da/copy.resx +++ b/apps/browser/store/locales/da/copy.resx @@ -139,7 +139,7 @@ Bitwarden tilbyder Teams og Enterprise-planer for virksomheder, så du sikkert k Hvorfor vælge Bitwarden: Kryptering i verdensklasse -Adgangskoder er beskyttet med avanceret end-to-end-kryptering (AES-256 bit, saltet hashtag og PBKDF2 SHA-256), så dine data forbliver sikre og private. +Adgangskoder er beskyttet med avanceret end-to-end-kryptering (AES-256 bit, saltet hashing og PBKDF2 SHA-256), så dine data forbliver sikre og private. Indbygget adgangskodegenerator Generér stærke, unikke og tilfældige adgangskoder baseret på sikkerhedskrav til hvert websted, du besøger. @@ -148,7 +148,8 @@ Globale oversættelser Bitwarden findes på 40 sprog, og flere kommer til, takket være vores globale fællesskab. Applikationer på tværs af platforme -Beskyt og del følsomme data i din Bitwarden boks fra enhver browser, mobilenhed eller desktop OS og mere. +Beskyt og del følsomme data i din Bitwarden boks fra enhver browser, mobilenhed eller desktop OS og mere. + En sikker og gratis adgangskodemanager til alle dine enheder diff --git a/apps/browser/store/locales/el/copy.resx b/apps/browser/store/locales/el/copy.resx index de4f9e5ff67..e120c906a47 100644 --- a/apps/browser/store/locales/el/copy.resx +++ b/apps/browser/store/locales/el/copy.resx @@ -124,15 +124,32 @@ Ένας ασφαλής και δωρεάν διαχειριστής κωδικών για όλες τις συσκευές σας - Το Bitwarden είναι ο ευκολότερος και ασφαλέστερος τρόπος για να αποθηκεύσετε όλες τις συνδέσεις και τους κωδικούς πρόσβασης σας, διατηρώντας παράλληλα το συγχρονισμό μεταξύ όλων των συσκευών σας. Η επέκταση της εφαρμογής Bitwarden σας επιτρέπει να συνδεθείτε γρήγορα σε οποιαδήποτε ιστοσελίδα μέσω του Safari ή του Chrome και υποστηρίζεται από εκατοντάδες άλλες δημοφιλείς εφαρμογές. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Η κλοπή κωδικού πρόσβασης είναι ένα σοβαρό πρόβλημα. Οι ιστοσελίδες και οι εφαρμογές που χρησιμοποιείτε υποβάλλονται σε επίθεση κάθε μέρα. Παραβιάσεις ασφαλείας συμβαίνουν και οι κωδικοί ίσως κλαπούν. Όταν επαναχρησιμοποιείτε τους ίδιους κωδικούς πρόσβασης σε εφαρμογές και ιστοσελίδες, οι χάκερ μπορούν εύκολα να έχουν πρόσβαση στο ηλεκτρονικό σας ταχυδρομείο, στην τράπεζα σας και σε άλλους σημαντικούς λογαριασμούς. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Οι ειδικοί ασφαλείας συστήνουν να χρησιμοποιείτε διαφορετικό, τυχαία δημιουργημένο κωδικό πρόσβασης για κάθε λογαριασμό που δημιουργείτε. Αλλά πώς διαχειρίζεστε όλους αυτούς τους κωδικούς πρόσβασης; Το Bitwarden σας διευκολύνει να δημιουργείτε, να αποθηκεύετε και να έχετε πρόσβαση στους κωδικούς πρόσβασης σας. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Το Bitwarden αποθηκεύει όλες τις συνδέσεις σας σε κρυπτογραφημένη μορφή που συγχρονίζεται σε όλες τις συσκευές σας. Δεδομένου ότι είναι πλήρως κρυπτογραφημένο, μόνο εσείς έχετε πρόσβαση στα δεδομένα σας. Ούτε η ομάδα του Bitwarden μπορεί να διαβάσει τα δεδομένα σας, ακόμα κι αν θέλουμε. Τα δεδομένα σας είναι σφραγισμένα με κρυπτογράφηση AES-256 bit, salted hashing και PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Το Bitwarden είναι 100% λογισμικό ανοικτού κώδικα. Ο πηγαίος κώδικας για το Bitwarden φιλοξενείται στο GitHub και ο καθένας είναι ελεύθερος να επανεξετάσει, να ελέγξει και να συνεισφέρει στον κώδικα βάσης του Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Ένας ασφαλής και δωρεάν διαχειριστής κωδικών για όλες τις συσκευές σας diff --git a/apps/browser/store/locales/et/copy.resx b/apps/browser/store/locales/et/copy.resx index 88a5b077708..2014ec88a80 100644 --- a/apps/browser/store/locales/et/copy.resx +++ b/apps/browser/store/locales/et/copy.resx @@ -124,15 +124,32 @@ Tasuta ja turvaline paroolihaldur kõikidele sinu seadmetele - Bitwarden muudab kontoandmete ja teiste isiklike andmete kasutamise erinevate seadmete vahel lihtsaks ja turvaliseks. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Paroolivargustest on saamas järjest tõsisem probleem. Veebilehed ja rakendused, mida igapäevaselt kasutad, on pidevalt rünnakute all. Muuhulgas toimuvad alalõpmata andmelekked, millega koos saadakse ligipääs ka Sinu paroolidele. Kasutades erinevatel veebilehtedel ühesugust parooli, on häkkeritel lihtne ligi pääseda nii sinu e-postile, pangakontole või teistele tähtsatele kontodele. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Turvaeksperdid soovitavad kasutada kõikides kasutajakontodes erinevaid, juhuslikult koostatud paroole. Kuidas aga kõiki neid paroole hallata? Bitwarden muudab paroolide loomise, talletamise ja nendele ligipääsu lihtsaks ja turvaliseks. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden talletab kõik Sinu andmed krüpteeritud hoidlas, mis sünkroniseeritakse kõikide Sinu poolt kasutatavate seadmete vahel. Kuna hoidla sisu krüpteeritakse enne selle enne seadmest lahkumist, omad andmetele ligipääsu ainult sina. Ka bitwardeni meeskond ei saa Sinu andmeid vaadata, isegi kui neil selleks tahtmine oleks. Sinu andmed kaitsevad AES-256 bitine krüpteering, salted hashing ja PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwarden on 100% avatud koodiga tarkvara. Bitwarden lähtekood on saadaval GitHubis ja kõik saavad sellega tasuta tutvuda, seda kontrollida ja Bitwardeni koodibaasi panustada. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Tasuta ja turvaline paroolihaldur kõikidele Sinu seadmetele diff --git a/apps/browser/store/locales/fa/copy.resx b/apps/browser/store/locales/fa/copy.resx index 116e66369cb..60386bf1841 100644 --- a/apps/browser/store/locales/fa/copy.resx +++ b/apps/browser/store/locales/fa/copy.resx @@ -124,18 +124,32 @@ یک مدیریت کننده کلمه عبور رایگان برای تمامی دستگاههایتان - Bitwarden ساده ترین و امن ترین راه گردآوری تمام داده های ورودی و پسوردها است در حالی که به راحتی آنها را بین تمامی دستگاه ها همگام میکند. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -سرقت پسورد یک مشکل جدی است. وبسایت ها و اپلیکیشن هایی که شما از آنها استفاده میکنید هر روز تحت حملات قرار دارند. نقص های امنیتی رخ میدهند و پسوردها به سرقت میروند. زمانی که شما مجدداً از همان پسورد برای تمام وبسایت ها و اپلیکیشن ها استفاده میکنید هکرها می‌توانند به راحتی به ایمیل، حساب بانکی، و سایر حسابهای کاربریتان دسترسی داشته باشند. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -متخصصان امنیتی توصیه میکنند که برای هر حساب کاربری که ایجاد میکنید از پسوردهای متفاوت و تصادفی تولید شده استفاده کنید. اما چطور تمامی این پسورها را مدیریت میکنید؟ بیت واردن ساختن، نگهداری، ودسترسی به پسوردهایتان را آسان میکند. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. -Bitwarden تمامی داده های ورودی شما را در یک گاو صندوق رمزنگاری شده نگهداری میکند که قابل همگام سازی توسط تمامی دستگاه های شماست. از آنجا که این داده ها هر زمان قبل از ترک دستگاهتان کاملا رمزنگاری میشود، فقط شما به اطلاعاتتان دسترسی دارید. حتی اگر تیم ما در بیت واردن هم بخواهند نمیتوانند اطلاعات شما را مشاهده کنند. داده های شما توسط رمزگذاری AES-256 بیتی، هَش خرد شده، و PBKDF2SHA-256 رمزنگاری شده است. +Why Choose Bitwarden: -Bitwarden ۱۰۰٪ یک برنامه متن باز است. کد منبع بیت واردن در GitHub میزبانی میشود و هر کس آزاد است برای بررسی، تفتیش و کمک به کد دسترسی داشته باشد. +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + یک مدیریت کننده کلمه عبور رایگان برای تمامی دستگاههایتان diff --git a/apps/browser/store/locales/fi/copy.resx b/apps/browser/store/locales/fi/copy.resx index 5a85be3b48a..7511ed5915e 100644 --- a/apps/browser/store/locales/fi/copy.resx +++ b/apps/browser/store/locales/fi/copy.resx @@ -134,7 +134,7 @@ Luo usein käyttämillesi sivustoille automaattisesti vahvoja, yksilöllisiä ja Bitwarden Send -ominaisuudella lähetät tietoa nopeasti salattuna — tiedostoja ja tekstiä — suoraan kenelle tahansa. -Yrityksille Bitwarden tarjoaa Teams- ja Enterprise-tilaukset, jotka mahdollistavat turvallisen salasanojen jaon kollegoiden kesken. +Yrityksille Bitwarden tarjoaa Teams- ja Enterprise-tilaukset, jotka mahdollistavat turvallisen salasanojen jakamisen kollegoiden kesken. Miksi Bitwarden?: diff --git a/apps/browser/store/locales/he/copy.resx b/apps/browser/store/locales/he/copy.resx index 3ceccc9b9ce..cd980970fca 100644 --- a/apps/browser/store/locales/he/copy.resx +++ b/apps/browser/store/locales/he/copy.resx @@ -124,15 +124,32 @@ מנהל ססמאות חינמי ומאובטח עבור כל המכשירים שלך - תוכנת Bitwarden היא הדרך הקלה והבטוחה לשמירת הסיסמאות שלך ועוזרת לסנכרן את הסיסמאות בין כל המכשירים שברשותך. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -גניבת סיסמאות היא בעיה רצינית. אתרים ואפליקציות מותקפים באופן יום יומי. פירצות אבטחה קורות מדי פעם ומאגרי סיסמאות נחשפים במלואם. כשאתה משתמש באותה סיסמה עבור כמה אתרים או אפליקציות, האקרים יכולים לנצל את אותה הסיסמה עבור אותם האתרים והאפליקציות ויכולים להשיג גישה למייל, לבנק, ולחשבונות חשובים אחרים. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -מומחי אבטחה ממליצים להשתמש בסיסמאות שונות ורנדומליות עבור כל חשבון שאתה יוצר. אבל איך אפשר לנהל את כל הסיסמאות הללו? תוכנת Bitwarden עוזרת לך ליצור, לשמור, ולגשת לכל הסיסמאות שלך. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -תוכנת Bitwarden מאחסנת את כל הפרטים בכספת מוצפנת שמסתנכרנת בין כל המכשירים שלך. מאחר שהמידע מוצפן עוד לפני שהוא יוצא מהמכשיר שלך, רק לך יש גישה למידע. גם הצוות שלנו בBitwarden לא יכול לקרוא את המידע, אפילו אם ירצה. המידע שלך מוגן עם הצפנת AES-256 ביט, salted hashing, וPBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -תוכנת Bitwarden היא 100% תוכנת קוד פתוח. קוד המקור של Bitwarden מאוחסן בGitHub וכל מי שרוצה יכול לתת ביקורת, להוסיף הערות, וכמובן לתרום מזמנו לפיתוח הקוד של Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + מנהל סיסמאות חינמי ומאובטח עבור כל המכשירים שלך diff --git a/apps/browser/store/locales/hi/copy.resx b/apps/browser/store/locales/hi/copy.resx index 9edb8288abb..8db837a3c3a 100644 --- a/apps/browser/store/locales/hi/copy.resx +++ b/apps/browser/store/locales/hi/copy.resx @@ -124,13 +124,32 @@ आपके सभी उपकरणों के लिए एक सुरक्षित और नि: शुल्क कूटशब्द प्रबंधक - bitwarden is the easiest and safest way to store all of your logins and passwords while conveniently keeping them synced between all of your devices. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Password theft is a serious problem. The websites and apps that you use are under attack every day. Security breaches occur and your passwords are stolen. When you reuse the same passwords across apps and websites hackers can easily access your email, bank, and other important accounts. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Security experts recommend that you use a different, randomly generated password for every account that you create. But how do you manage all those passwords? bitwarden makes it easy for you to create, store, and access your passwords. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -bitwarden stores all of your logins in an encrypted vault that syncs across all of your devices. Since it's fully encrypted before it ever leaves your device, only you have access to your data. Not even the team at bitwarden can read your data, even if we wanted to. Your data is sealed with AES-256 bit encryption, salted hashing, and PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + आपके सभी उपकरणों के लिए एक सुरक्षित और नि: शुल्क पासवर्ड प्रबंधक diff --git a/apps/browser/store/locales/id/copy.resx b/apps/browser/store/locales/id/copy.resx index bf601db1dc1..b52252a342e 100644 --- a/apps/browser/store/locales/id/copy.resx +++ b/apps/browser/store/locales/id/copy.resx @@ -124,15 +124,32 @@ Pengelola sandi yang aman dan gratis untuk semua perangkat Anda - Bitwarden adalah cara termudah dan teraman untuk menyimpan semua info masuk dan sandi Anda sambil tetap menjaga mereka disinkronkan di antara semua perangkat Anda. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Pencurian sandi adalah masalah serius. Situs web dan aplikasi yang Anda gunakan diserang setiap hari. Pelanggaran keamanan terjadi dan sandi Anda dicuri. Ketika Anda menggunakan sandi yang sama di aplikasi dan situs web peretas dapat dengan mudah mengakses email, bank, dan akun penting Anda yang lain. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Pakar keamanan merekomendasikan agar Anda menggunakan sandi yang berbeda dan dibuat secara acak untuk setiap akun yang Anda buat. Tapi bagaimana mengelola semua sandi tersebut? Bitwarden membuatnya menjadi mudah untuk Anda membuat, menyimpan dan mengakses sandi Anda. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden menyimpan semua info masuk Anda di brankas terenkripsi yang disinkronkan di semua perangkat Anda. Karena sepenuhnya dienkripsi sebelum meninggalkan perangkat Anda, hanya Anda yang memiliki akses ke data Anda. Bahkan tim di Bitwarden tidak dapat membaca data Anda, bahkan jika kami mau. Data Anda disegel dengan ekripsi AES-256 bit, hash yang di-salt, dan PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwarden adalah 100% perangkat lunak sumber terbuka. Kode sumber untuk Bitwarden berada di GitHub dan setiap orang bebas untuk meninjau, mengaudit, dan berkontribusi ke basis kode Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Pengelola sandi yang aman dan gratis untuk semua perangkat Anda diff --git a/apps/browser/store/locales/ja/copy.resx b/apps/browser/store/locales/ja/copy.resx index 660708153da..33db9384ae3 100644 --- a/apps/browser/store/locales/ja/copy.resx +++ b/apps/browser/store/locales/ja/copy.resx @@ -124,15 +124,32 @@ あらゆる端末で使える、安全な無料パスワードマネージャー - Bitwarden は、あらゆる端末間で同期しつつログイン情報やパスワードを保管しておける、最も簡単で安全なサービスです。 + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -パスワードの盗難は深刻な問題になっています。ウェブサイトやアプリは毎日攻撃を受けており、もしセキュリティに問題があればパスワードが盗難されてしまいます。 同じパスワードを他のアプリでも再利用していると、攻撃者はメールや銀行口座など大切なアカウントに簡単に侵入できてしまいます。 +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -セキュリティの専門家は、アカウント毎に別のランダムに生成したパスワードを使うことを推奨していますが、ランダムなパスワードをすべて覚えていられますか? Bitwarden を使えば、わざわざパスワードを覚えなくても簡単にパスワードの生成、保管や利用ができます。 +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden は端末間で同期できる、暗号化された保管庫にログイン情報を保管します。端末から送信される前に暗号化されるので、あなただけがそのデータにアクセスできるのです。Bitwarden の開発者チームですら、あなたに頼まれたとしてもデータを読み取ることはできません。データは AES-256 bit 暗号化、ソルト化ハッシュ、PBKDF2 SHA-256 で保護されます。 +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwarden は100%オープンソースソフトウェアです。Bitwarden のソースコードは GitHub にホストされており、誰でもBitwardenのコードを自由にレビュー、監査、貢献できます。 +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + あらゆる端末で使える、安全な無料パスワードマネージャー diff --git a/apps/browser/store/locales/lt/copy.resx b/apps/browser/store/locales/lt/copy.resx index d7929c0b514..d2aa4024c07 100644 --- a/apps/browser/store/locales/lt/copy.resx +++ b/apps/browser/store/locales/lt/copy.resx @@ -124,15 +124,32 @@ Saugi ir nemokama slaptažodžių tvarkyklė visiems įrenginiams - „Bitwarden“ yra paprasčiausias ir saugiausias būdas išsaugoti visus prisijungimus ir slaptažodžius, tuo pačiu patogu juos pasiekti iš visų jūsų įrenginių. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Slaptažodžių vagystė yra rimta problema. Jūsų naudojamos svetainės ir programos yra atakuojamos kiekvieną dieną. Įvykus saugumo pažeidimų jūsų slaptažodžiai yra pavogiami. Kai pakartotinai naudojate tuos pačius slaptažodžius programose ir svetainėse, įsilaužėliai gali lengvai pasiekti jūsų el. pašto, banko ir kitas svarbias paskiras. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Saugumo ekspertai rekomenduoja kiekvienai jūsų sukurtai paskyrai naudoti kitą, atsitiktinai sugeneruotą slaptažodį. Bet kaip valdyti visus tuos slaptažodžius? „Bitwarden“ leidžia jums lengvai kurti, saugoti ir pasiekti slaptažodžius. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -„Bitwarden“ visus jūsų prisijungimus saugo šifruotoje saugykloje, kuri pasiekiama visuose jūsų įrenginiuose. Kadangi duomenys visiškai užšifruoti dar neišėjus iš jūsų įrenginio, prieigą prie savo duomenų turite tik jūs. Net „Bitwarden“ komanda negali perskaityti jūsų duomenų, net jei mes to ir norėtume. Jūsų duomenys užklijuojami naudojant AES-256 bitų šifravimą, druskinta maišos funkcija ir PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -„Bitwarden“ yra 100% atvirojo kodo programinė įranga. „Bitwarden“ kodas yra „GitHub“ ir visi gali peržiūrėti, tikrinti ir prisidėti prie „Bitwarden“ kodo bazės. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Saugi ir nemokama slaptažodžių tvarkyklė visiems įrenginiams diff --git a/apps/browser/store/locales/lv/copy.resx b/apps/browser/store/locales/lv/copy.resx index 252b6f0344a..203ef914839 100644 --- a/apps/browser/store/locales/lv/copy.resx +++ b/apps/browser/store/locales/lv/copy.resx @@ -124,15 +124,31 @@ Drošs bezmaksas paroļu pārvaldnieks visām Tavām ierīcēm - Bitwarden ir vieglākais un drošākais veids, kā glabāt visus pierakstīšanās vienumus un paroles, vienlaicīgi ērti uzturot tās sinhronizētas visās ierīcēs. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Paroļu zagšana ir nopietna nebūšana. Tīmekļa vietnēm un lietotnēm uzbrūk katru dienu. Datu drošības pārkāpumos tiek nozagtas paroles. Kad viena un tā pati parole tiek izmantota lietotnēs un tīmekļa vietnēs, urķi var viegli piekļūt e-pasta, banku un citiem būtiskiem kontiem. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Drošības lietpratēji iesaka katram izveidotajam kontam izmantot dažādas, nejauši veidotas paroles. Kā tās visas pārvaldīt? Bitwarden atvieglo paroļu izveidošanu, glabāšanu un piekļūšanu tām. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden uzglabā visus pierakstīšanās vienumus šifrētā glabātavā, kas tiek sinhronizēta visās izmantotajās ierīcēs. Tā kā tā dati tiek pilnībā šifrēti, pirms tie tiek izsūtīti no izmantotās ierīces, piekļuve tiem ir tikai glabātavas īpašniekam. Pat Bitwarden izstrādātāji nevar lasīt datus, pat ja to gribētu. Informācija tiek aizsargāta ar AES-256 bitu šifrēšanu, "sālīto" jaukšanu un PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwarden ir pilnībā atvērtā pirmkoda programmatūra. Bitwarden atvērtais pirmkods ir izvietots GitHub, un ikkatram ir iespēja pārskatīt, pārbaudīt un sniegt ieguldījumu Bitwarden pirmkodā. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. diff --git a/apps/browser/store/locales/nb/copy.resx b/apps/browser/store/locales/nb/copy.resx index 67d9a804504..74a8558db65 100644 --- a/apps/browser/store/locales/nb/copy.resx +++ b/apps/browser/store/locales/nb/copy.resx @@ -124,15 +124,32 @@ En sikker og fri passordbehandler for alle dine PCer og mobiler - Bitwarden er den enkleste og tryggeste måten å lagre alle dine innlogginger og passord på, samtidig som de blir synkronisert mellom alle dine PCer og mobiler. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Passordtyveri er et seriøst problem. Nettstedene og appene som du bruker er under angrep hver eneste dag. Sikkerhetsbrudd forekommer, og dine passord blir stjålet. Når du bruker de samme passordene over flere apper og nettsteder, kan hackere lett få tilgang til din e-post, bankkonto, og andre viktige kontoer. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Sikkerhetseksperter anbefaler at du bruker forskjellig og tilfeldig genererte passord for hver eneste konto du lager. Men hvordan håndterer du alle de passordene? Bitwarden gjør det lett for deg å lage, lagre, og få tilgang til dine passord. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden lagrer alle dine innlogginger i et kryptert hvelv som synkroniseres mellom alle dine PCer og mobiler. Ettersom hvelvet er fullstendig kryptert før det noensinne forlater enheten din, har bare du tilgang til dine dataer. Selv ikke de som jobber hos Bitwarden kan lese dine dataer, om vi så ville det. Dine dataer er forseglet med AES 256-bitkryptering, saltet hashing, og PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwardens programvare har 100% åpen kildekode. Kildekoden til Bitwarden betjenes på GitHub, og alle har all rett til å undersøke, gjennomgå og bidra til Bitwarden sin kodebase. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + En sikker og fri passordbehandler for alle dine PCer og mobiler diff --git a/apps/browser/store/locales/pt_BR/copy.resx b/apps/browser/store/locales/pt_BR/copy.resx index 536ad080eca..90a2959e807 100644 --- a/apps/browser/store/locales/pt_BR/copy.resx +++ b/apps/browser/store/locales/pt_BR/copy.resx @@ -124,15 +124,32 @@ Um gerenciador de senhas gratuito e seguro para todos os seus dispositivos - O Bitwarden é a maneira mais fácil e segura de armazenar todos os seus usuários e senhas mantendo-os convenientemente sincronizados entre todos os seus dispositivos. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -O furto de senhas é um problema sério. Os sites e aplicativos que os utiliza estão sob ataque todos os dias. Brechas de segurança ocorrem e as suas senhas são furtadas. Quando você reutiliza as mesmas senhas entre aplicativos e sites, os hackers podem facilmente acessar o seu e-mail, banco, e outras contas importantes. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Os especialistas de segurança recomendam que utilize uma senha diferente e aleatoriamente gerada para todas as contas que você cria. Mas como gerenciar todas essas senhas? O Bitwarden torna-lhe fácil criar, armazenar, e acessar as suas senhas. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -O Bitwarden armazena todas as suas credenciais num cofre encriptado que sincroniza entre todos os seus dispositivos. Como são completamente encriptados antes de se quer sair do seu dispositivo, apenas você tem acesso aos seus dados. Nem se quer a equipe do Bitwarden pode ler os seus dados, mesmo se quiséssemos. Os seus dados são selados com encriptação AES-256 bits, salted hashing, e PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwarden é um software 100% de código aberto. O código-fonte do Bitwarden está hospedado no GitHub e todos são livres para revisar, auditar e contribuir com a base de códigos do Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Um gerenciador de senhas gratuito e seguro para todos os seus dispositivos diff --git a/apps/browser/store/locales/pt_PT/copy.resx b/apps/browser/store/locales/pt_PT/copy.resx index 9f0230000c1..9fd0780a540 100644 --- a/apps/browser/store/locales/pt_PT/copy.resx +++ b/apps/browser/store/locales/pt_PT/copy.resx @@ -124,15 +124,32 @@ Um gestor de palavras-passe seguro e gratuito para todos os seus dispositivos - O Bitwarden é a maneira mais fácil e segura de armazenar todas as suas credenciais e palavras-passe mantendo-as convenientemente sincronizadas entre todos os seus dispositivos. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -O furto de palavras-passe é um problema sério. Os websites e aplicações que utiliza estão sob ataque todos os dias. Quebras de segurança ocorrem e as suas palavras-passe são furtadas. Quando reutiliza as mesmas palavras-passe entre aplicações e websites, os hackers podem facilmente aceder ao seu email, banco, e outras contas importantes. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Os especialistas de segurança recomendam que utilize uma palavra-passe diferente e aleatoriamente gerada para todas as contas que cria. Mas como é que gere todas essas palavras-passe? O Bitwarden torna-lhe fácil criar, armazenar, e aceder às suas palavras-passe. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -O Bitwarden armazena todas as suas credenciais num cofre encriptado que sincroniza entre todos os seus dispositivos. Como são completamente encriptados antes de se quer sair do seu dispositivo, apenas você tem acesso aos seus dados. Nem se quer a equipa do Bitwarden pode ler os seus dados, mesmo se quiséssemos. Os seus dados são selados com encriptação AES-256 bits, salted hashing, e PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -O Bitwarden é 100% software de código aberto. O código fonte para o Bitwarden está hospedado no GitHub e todos podem revisar, auditar, e contribuir para a base de código do Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Um gestor de palavras-passe seguro e gratuito para todos os seus dispositivos diff --git a/apps/browser/store/locales/sr/copy.resx b/apps/browser/store/locales/sr/copy.resx index d67314a07c1..15634809472 100644 --- a/apps/browser/store/locales/sr/copy.resx +++ b/apps/browser/store/locales/sr/copy.resx @@ -124,15 +124,32 @@ Сигурни и бесплатни менаџер лозинке за сва Ваша уређаја - Bitwarden је најједноставнији и најсигурнији начин за складиштење свих ваших података за пријављивање и лозинки, док их истовремено усклађујете на свим својим уређајима. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. -Крађа лозинке је озбиљан проблем. Веб локације и апликације које користите свакодневно су на удару. Дошло је до нарушавања безбедности и крађе лозинки. Када поново користите исте лозинке у апликацијама и на веб локацијама, хакери могу лако да приступе вашој е-пошти, банци и другим важним рачунима. +NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. -Стручњаци за безбедност препоручују употребу различите, насумично генерисане лозинке за сваки налог који креирате. Али како управљате свим тим лозинкама? Bitwarden вам олакшава стварање, чување и приступ вашим лозинкама. +Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. -Bitwarden чува све ваше пријаве у шифрованом сефу који се синхронизује на свим вашим уређајима. Пошто је потпуно шифровано пре него што напусти уређај, само ви имате приступ подацима. Чак ни тим у Bitwarden не може да прочита ваше податке, чак и да то желимо. Ваши подаци су запечаћени са AES-256 битном енкрипцијом, усољеним хеширањем и PBKDF2 SHA-256. +Generate strong, unique, and random passwords based on security requirements for every website you frequent. -Bitwardenје софтвер са 100% отвореног кода. Изворни код Bitwarden-а се налази на GitHub и сви могу слободно да прегледају, провере и дају свој допринос за Bitwarden. +Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + +Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + +Why Choose Bitwarden: + +World-Class Encryption +Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + +Built-in Password Generator +Generate strong, unique, and random passwords based on security requirements for every website you frequent. + +Global Translations +Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + +Cross-Platform Applications +Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. + Сигурни и бесплатни менаџер лозинке за сва Ваша уређаја diff --git a/apps/browser/store/locales/tr/copy.resx b/apps/browser/store/locales/tr/copy.resx index 2763c3ec91b..1fc3e2a34b3 100644 --- a/apps/browser/store/locales/tr/copy.resx +++ b/apps/browser/store/locales/tr/copy.resx @@ -139,7 +139,7 @@ Bitwarden, parolaları iş arkadaşlarınızla güvenli bir şekilde paylaşabil Neden Bitwarden? Üst düzey şifreleme -Parolalarınız gelişmiş uçtan uca şifreleme (AES-256 bit, salted hashtag ve PBKDF2 SHA-256) ile korunuyor, böylece verileriniz güvende ve gizli kalıyor. +Parolalarınız gelişmiş uçtan uca şifreleme (AES-256 bit, salted hashing ve PBKDF2 SHA-256) ile korunuyor, böylece verileriniz güvende ve gizli kalıyor. Dahili parola oluşturucu Sık kullandığınız web siteleri için güvenlik gereksinimlerinize uygun, güçlü, benzersiz ve rastgele parolalar oluşturabilirsiniz. @@ -148,7 +148,8 @@ Sık kullandığınız web siteleri için güvenlik gereksinimlerinize uygun, g Bitwarden 40 dilde kullanılabiliyor ve gönüllü topluluğumuz sayesinde çeviri sayısı giderek artıyor. Her platformla uyumlu uygulamalar -Bitwarden kasanızdaki hassas verilere her tarayıcıdan, mobil cihazdan veya masaüstü işletim sisteminden ulaşabilir ve onları paylaşabilirsiniz. +Bitwarden kasanızdaki hassas verilere her tarayıcıdan, mobil cihazdan veya masaüstü işletim sisteminden ulaşabilir ve onları paylaşabilirsiniz. + Tüm cihazarınız için güvenli ve ücretsiz bir parola yöneticisi diff --git a/apps/cli/package.json b/apps/cli/package.json index b833fe5b072..a360c1bef58 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -13,7 +13,7 @@ "homepage": "https://bitwarden.com", "repository": { "type": "git", - "url": "https://github.com/bitwarden/cli" + "url": "https://github.com/bitwarden/clients" }, "license": "GPL-3.0-only", "scripts": { diff --git a/apps/cli/src/bw.ts b/apps/cli/src/bw.ts index 734a030943d..489f92fac9d 100644 --- a/apps/cli/src/bw.ts +++ b/apps/cli/src/bw.ts @@ -30,8 +30,8 @@ import { ImportService } from "@bitwarden/common/services/import.service"; import { KeyConnectorService } from "@bitwarden/common/services/keyConnector.service"; import { MemoryStorageService } from "@bitwarden/common/services/memoryStorage.service"; import { NoopMessagingService } from "@bitwarden/common/services/noopMessaging.service"; -import { OrganizationService } from "@bitwarden/common/services/organization.service"; import { OrganizationApiService } from "@bitwarden/common/services/organization/organization-api.service"; +import { OrganizationService } from "@bitwarden/common/services/organization/organization.service"; import { PasswordGenerationService } from "@bitwarden/common/services/passwordGeneration.service"; import { PolicyService } from "@bitwarden/common/services/policy/policy.service"; import { ProviderService } from "@bitwarden/common/services/provider.service"; @@ -41,6 +41,7 @@ import { SettingsService } from "@bitwarden/common/services/settings.service"; import { StateService } from "@bitwarden/common/services/state.service"; import { StateMigrationService } from "@bitwarden/common/services/stateMigration.service"; import { SyncService } from "@bitwarden/common/services/sync/sync.service"; +import { SyncNotifierService } from "@bitwarden/common/services/sync/syncNotifier.service"; import { TokenService } from "@bitwarden/common/services/token.service"; import { TotpService } from "@bitwarden/common/services/totp.service"; import { TwoFactorService } from "@bitwarden/common/services/twoFactor.service"; @@ -113,6 +114,7 @@ export class Main { folderApiService: FolderApiService; userVerificationApiService: UserVerificationApiService; organizationApiService: OrganizationApiServiceAbstraction; + syncNotifierService: SyncNotifierService; constructor() { let p = null; @@ -191,7 +193,9 @@ export class Main { customUserAgent ); - this.organizationApiService = new OrganizationApiService(this.apiService); + this.syncNotifierService = new SyncNotifierService(); + + this.organizationApiService = new OrganizationApiService(this.apiService, this.syncService); this.containerService = new ContainerService(this.cryptoService, this.encryptService); @@ -231,7 +235,7 @@ export class Main { this.providerService = new ProviderService(this.stateService); - this.organizationService = new OrganizationService(this.stateService); + this.organizationService = new OrganizationService(this.stateService, this.syncNotifierService); this.policyService = new PolicyService(this.stateService, this.organizationService); @@ -311,9 +315,9 @@ export class Main { this.logService, this.keyConnectorService, this.stateService, - this.organizationService, this.providerService, this.folderApiService, + this.syncNotifierService, async (expired: boolean) => await this.logout() ); diff --git a/apps/cli/src/commands/convertToKeyConnector.command.ts b/apps/cli/src/commands/convertToKeyConnector.command.ts index 6339fa9b9aa..00fb2f72910 100644 --- a/apps/cli/src/commands/convertToKeyConnector.command.ts +++ b/apps/cli/src/commands/convertToKeyConnector.command.ts @@ -74,7 +74,6 @@ export class ConvertToKeyConnectorCommand { } else if (answer.convert === "leave") { await this.organizationApiService.leave(organization.id); await this.keyConnectorService.removeConvertAccountRequired(); - await this.syncService.fullSync(true); return Response.success(); } else { await this.logout(); diff --git a/apps/cli/src/commands/get.command.ts b/apps/cli/src/commands/get.command.ts index 7cfcd9fb6e3..510cb10da3f 100644 --- a/apps/cli/src/commands/get.command.ts +++ b/apps/cli/src/commands/get.command.ts @@ -4,7 +4,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { TotpService } from "@bitwarden/common/abstractions/totp.service"; diff --git a/apps/cli/src/commands/import.command.ts b/apps/cli/src/commands/import.command.ts index f3b04a5f564..6fb17fa2cd9 100644 --- a/apps/cli/src/commands/import.command.ts +++ b/apps/cli/src/commands/import.command.ts @@ -2,7 +2,7 @@ import * as program from "commander"; import * as inquirer from "inquirer"; import { ImportService } from "@bitwarden/common/abstractions/import.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { ImportType } from "@bitwarden/common/enums/importOptions"; import { Importer } from "@bitwarden/common/importers/importer"; import { Response } from "@bitwarden/node/cli/models/response"; diff --git a/apps/cli/src/commands/list.command.ts b/apps/cli/src/commands/list.command.ts index 4e2d7cb02e0..dd779ec0576 100644 --- a/apps/cli/src/commands/list.command.ts +++ b/apps/cli/src/commands/list.command.ts @@ -2,7 +2,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { SearchService } from "@bitwarden/common/abstractions/search.service"; import { Utils } from "@bitwarden/common/misc/utils"; import { CollectionData } from "@bitwarden/common/models/data/collectionData"; diff --git a/apps/cli/src/send.program.ts b/apps/cli/src/send.program.ts index 69e5eeaedf3..f92e2a305e1 100644 --- a/apps/cli/src/send.program.ts +++ b/apps/cli/src/send.program.ts @@ -139,7 +139,7 @@ export class SendProgram extends Program { return new program.Command("template") .arguments("") .description("Get json templates for send objects", { - object: "Valid objects are: send, send.text, send.file", + object: "Valid objects are: send.text, send.file", }) .action(async (object) => { const cmd = new GetCommand( @@ -176,12 +176,12 @@ export class SendProgram extends Program { writeLn(""); writeLn(" Examples:"); writeLn(""); - writeLn(" bw get send searchText"); - writeLn(" bw get send id"); - writeLn(" bw get send searchText --text"); - writeLn(" bw get send searchText --file"); - writeLn(" bw get send searchText --file --output ../Photos/photo.jpg"); - writeLn(" bw get send searchText --file --raw"); + writeLn(" bw send get searchText"); + writeLn(" bw send get id"); + writeLn(" bw send get searchText --text"); + writeLn(" bw send get searchText --file"); + writeLn(" bw send get searchText --file --output ../Photos/photo.jpg"); + writeLn(" bw send get searchText --file --raw"); writeLn("", true); }) .action(async (id: string, options: program.OptionValues) => { diff --git a/apps/cli/stores/chocolatey/bitwarden-cli.nuspec b/apps/cli/stores/chocolatey/bitwarden-cli.nuspec index 30de1c6f439..a61a7d12b49 100644 --- a/apps/cli/stores/chocolatey/bitwarden-cli.nuspec +++ b/apps/cli/stores/chocolatey/bitwarden-cli.nuspec @@ -4,18 +4,18 @@ bitwarden-cli 0.0.0 - https://github.com/bitwarden/cli/tree/master/stores/chocolatey + https://github.com/bitwarden/clients/tree/master/apps/cli/stores/chocolatey kspearrin Bitwarden CLI Bitwarden Inc. https://bitwarden.com/ - https://cdn.rawgit.com/bitwarden/desktop/51dd1341/resources/icon.png + https://raw.githubusercontent.com/bitwarden/brand/master/icons/256x256.png Copyright © 2015-2022 Bitwarden Inc. - https://github.com/bitwarden/cli/ + https://github.com/bitwarden/clients/ https://help.bitwarden.com/article/cli/ - https://github.com/bitwarden/cli/issues - https://github.com/bitwarden/cli/releases - https://github.com/bitwarden/cli/blob/master/LICENSE.txt + https://github.com/bitwarden/clients/issues + https://github.com/bitwarden/clients/releases + https://github.com/bitwarden/clients/blob/master/LICENSE.txt false bitwarden password manager cli A secure and free password manager for all of your devices. @@ -24,15 +24,31 @@ ----------------- - Bitwarden is the easiest and safest way to store all of your logins and passwords while conveniently keeping them synced between all of your devices. - - Password theft is a serious problem. The websites and apps that you use are under attack every day. Security breaches occur and your passwords are stolen. When you reuse the same passwords across apps and websites hackers can easily access your email, bank, and other important accounts. - - Security experts recommend that you use a different, randomly generated password for every account that you create. But how do you manage all those passwords? Bitwarden makes it easy for you to create, store, and access your passwords. - - Bitwarden stores all of your logins in an encrypted vault that syncs across all of your devices. Since it's fully encrypted before it ever leaves your device, only you have access to your data. Not even the team at Bitwarden can read your data, even if we wanted to. Your data is sealed with AES-256 bit encryption, salted hashing, and PBKDF2 SHA-256. - - Bitwarden is 100% open source software. The source code for Bitwarden is hosted on GitHub and everyone is free to review, audit, and contribute to the Bitwarden codebase. + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. + + NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. + + Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. + + Generate strong, unique, and random passwords based on security requirements for every website you frequent. + + Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + + Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + + Why Choose Bitwarden: + + World-Class Encryption + Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + + Built-in Password Generator + Generate strong, unique, and random passwords based on security requirements for every website you frequent. + + Global Translations + Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + + Cross-Platform Applications + Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. diff --git a/apps/cli/stores/snap/snapcraft.yaml b/apps/cli/stores/snap/snapcraft.yaml index b358a586872..19e6897faa3 100644 --- a/apps/cli/stores/snap/snapcraft.yaml +++ b/apps/cli/stores/snap/snapcraft.yaml @@ -1,13 +1,40 @@ name: bw version: __version__ -summary: Bitwarden CLI -description: A secure and free password manager for all of your devices. +summary: Bitwarden CLI - A secure and free password manager for all of your devices. +description: | + Bitwarden, Inc. is the parent company of 8bit Solutions LLC. + + NAMED BEST PASSWORD MANAGER BY THE VERGE, U.S. NEWS & WORLD REPORT, CNET, AND MORE. + + Manage, store, secure, and share unlimited passwords across unlimited devices from anywhere. Bitwarden delivers open source password management solutions to everyone, whether at home, at work, or on the go. + + Generate strong, unique, and random passwords based on security requirements for every website you frequent. + + Bitwarden Send quickly transmits encrypted information --- files and plaintext -- directly to anyone. + + Bitwarden offers Teams and Enterprise plans for companies so you can securely share passwords with colleagues. + + Why Choose Bitwarden: + + World-Class Encryption + Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashing, and PBKDF2 SHA-256) so your data stays secure and private. + + Built-in Password Generator + Generate strong, unique, and random passwords based on security requirements for every website you frequent. + + Global Translations + Bitwarden translations exist in 40 languages and are growing, thanks to our global community. + + Cross-Platform Applications + Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more. confinement: strict base: core18 apps: bw: command: bw - plugs: [network, home, network-bind] + environment: + XDG_CONFIG_HOME: $SNAP_USER_DATA + plugs: [network, network-bind] parts: bw: plugin: dump diff --git a/apps/desktop/config/development.json b/apps/desktop/config/development.json index 3c93018e65f..b587e9ecfb9 100644 --- a/apps/desktop/config/development.json +++ b/apps/desktop/config/development.json @@ -1,4 +1,6 @@ { "devFlags": {}, - "flags": {} + "flags": { + "showDDGSetting": true + } } diff --git a/apps/desktop/config/production.json b/apps/desktop/config/production.json index b04d1531a2f..56f19341304 100644 --- a/apps/desktop/config/production.json +++ b/apps/desktop/config/production.json @@ -1,3 +1,5 @@ { - "flags": {} + "flags": { + "showDDGSetting": true + } } diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index aec92d256aa..a3a20cd647e 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -153,7 +153,7 @@ dependencies = [ "security-framework-sys", "tokio", "widestring", - "windows 0.32.0", + "windows", ] [[package]] @@ -329,18 +329,22 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "libsecret" version = "0.1.4" @@ -426,28 +430,29 @@ dependencies = [ [[package]] name = "napi" -version = "2.1.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ec66e60f000c78dd7c6215b6fa260e0591e09805024332bc5b3f55acc12244" +checksum = "743fece4c26c5132f8559080145fde9ba88700c0f1aa30a1ab3e057ab105814d" dependencies = [ + "bitflags", "ctor", - "lazy_static", "napi-sys", + "once_cell", + "thread_local", "tokio", - "windows 0.30.0", ] [[package]] name = "napi-build" -version = "1.2.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd4419172727423cf30351406c54f6cc1b354a2cfb4f1dba3e6cd07f6d5522b" +checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e" [[package]] name = "napi-derive" -version = "2.1.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ac5287a5e94a8728fc82d16c5127acc5eb5b8ad6404ef5f82d6a4ce8d5bdd2" +checksum = "39f3d8b02ef355898ea98f69082d9a183c8701c836942c2daf3e92364e88a0fa" dependencies = [ "convert_case", "napi-derive-backend", @@ -458,9 +463,9 @@ dependencies = [ [[package]] name = "napi-derive-backend" -version = "1.0.25" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427f4f04525635cdf22005d1be62d6d671bcb5550d694a1efb480a315422b4af" +checksum = "6c35640513eb442fcbd1653a1c112fb6b2cc12b54d82f9c141f5859c721cab36" dependencies = [ "convert_case", "once_cell", @@ -472,9 +477,12 @@ dependencies = [ [[package]] name = "napi-sys" -version = "2.1.0" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a385494dac3c52cbcacb393bb3b42669e7db8ab240c7ad5115f549eb061f2cc" +checksum = "529671ebfae679f2ce9630b62dd53c72c56b3eb8b2c852e7e2fa91704ff93d67" +dependencies = [ + "libloading", +] [[package]] name = "ntapi" @@ -513,9 +521,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" dependencies = [ "cfg-if", "libc", @@ -745,6 +753,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + [[package]] name = "tokio" version = "1.17.0" @@ -846,19 +863,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" -dependencies = [ - "windows_aarch64_msvc 0.30.0", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", -] - [[package]] name = "windows" version = "0.32.0" @@ -874,23 +878,17 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.32.0" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc 0.32.0", - "windows_i686_gnu 0.32.0", - "windows_i686_msvc 0.32.0", - "windows_x86_64_gnu 0.32.0", - "windows_x86_64_msvc 0.32.0", + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", ] -[[package]] -name = "windows_aarch64_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" - [[package]] name = "windows_aarch64_msvc" version = "0.32.0" @@ -898,10 +896,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" [[package]] -name = "windows_i686_gnu" -version = "0.30.0" +name = "windows_aarch64_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_i686_gnu" @@ -910,10 +908,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" [[package]] -name = "windows_i686_msvc" -version = "0.30.0" +name = "windows_i686_gnu" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_msvc" @@ -922,10 +920,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" [[package]] -name = "windows_x86_64_gnu" -version = "0.30.0" +name = "windows_i686_msvc" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_x86_64_gnu" @@ -934,13 +932,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" [[package]] -name = "windows_x86_64_msvc" -version = "0.30.0" +name = "windows_x86_64_gnu" +version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_msvc" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index 0c990fe622d..b7d95bf96d5 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -12,13 +12,13 @@ crate-type = ["cdylib"] [dependencies] anyhow = "1.0" -napi = {version = "2", features = ["async"]} -napi-derive = "2" +napi = {version = "2.9.1", features = ["async"]} +napi-derive = "2.9.1" scopeguard = "1.1.0" tokio = {version = "1.17.0", features = ["full"]} [build-dependencies] -napi-build = "1" +napi-build = "2.0.1" [target.'cfg(windows)'.dependencies] widestring = "0.5.1" @@ -30,6 +30,8 @@ windows = {version = "0.32.0", features = [ "Win32_Foundation", "Win32_Security_Credentials", "Win32_System_WinRT", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_WindowsAndMessaging", ]} [target.'cfg(windows)'.dev-dependencies] diff --git a/apps/desktop/desktop_native/src/biometric/windows.rs b/apps/desktop/desktop_native/src/biometric/windows.rs index d956da064d0..f49730cc559 100644 --- a/apps/desktop/desktop_native/src/biometric/windows.rs +++ b/apps/desktop/desktop_native/src/biometric/windows.rs @@ -1,19 +1,33 @@ use anyhow::Result; use windows::{ - core::factory, Foundation::IAsyncOperation, Security::Credentials::UI::*, - Win32::Foundation::HWND, Win32::System::WinRT::IUserConsentVerifierInterop, + core::{factory, HSTRING}, + Foundation::IAsyncOperation, + Security::Credentials::UI::*, + Win32::{ + Foundation::HWND, + System::WinRT::IUserConsentVerifierInterop, + UI::{ + Input::KeyboardAndMouse::{ + self, keybd_event, GetAsyncKeyState, SetFocus, KEYEVENTF_EXTENDEDKEY, + KEYEVENTF_KEYUP, VK_MENU, + }, + WindowsAndMessaging::{self, SetForegroundWindow}, + }, + }, }; pub fn prompt(hwnd: Vec, message: String) -> Result { - let interop = factory::()?; - - let h = isize::from_le_bytes(hwnd.try_into().unwrap()); + let h = isize::from_le_bytes(hwnd.clone().try_into().unwrap()); let window = HWND(h); - let operation: IAsyncOperation = - unsafe { interop.RequestVerificationForWindowAsync(window, message)? }; + // The Windows Hello prompt is displayed inside the application window. For best result we + // should set the window to the foreground and focus it. + set_focus(window); - let result: UserConsentVerificationResult = operation.get()?; + let interop = factory::()?; + let operation: IAsyncOperation = + unsafe { interop.RequestVerificationForWindowAsync(window, &HSTRING::from(message))? }; + let result = operation.get()?; match result { UserConsentVerificationResult::Verified => Ok(true), @@ -31,6 +45,31 @@ pub fn available() -> Result { } } +fn set_focus(window: HWND) { + let mut pressed = false; + + unsafe { + // Simulate holding down Alt key to bypass windows limitations + // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getasynckeystate#return-value + // The most significant bit indicates if the key is currently being pressed. This means the + // value will be negative if the key is pressed. + if GetAsyncKeyState(VK_MENU.0 as i32) >= 0 { + pressed = true; + keybd_event(VK_MENU.0 as u8, 0, KEYEVENTF_EXTENDEDKEY, 0); + } + SetForegroundWindow(window); + SetFocus(window); + if pressed { + keybd_event( + VK_MENU.0 as u8, + 0, + KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, + 0, + ); + } + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/apps/desktop/jest.config.js b/apps/desktop/jest.config.js new file mode 100644 index 00000000000..4f954afa9e2 --- /dev/null +++ b/apps/desktop/jest.config.js @@ -0,0 +1,14 @@ +const { pathsToModuleNameMapper } = require("ts-jest"); + +const { compilerOptions } = require("./tsconfig"); + +const sharedConfig = require("../../libs/shared/jest.config.base"); + +module.exports = { + ...sharedConfig, + preset: "jest-preset-angular", + setupFilesAfterEnv: ["/test.setup.ts"], + moduleNameMapper: pathsToModuleNameMapper(compilerOptions?.paths || {}, { + prefix: "/", + }), +}; diff --git a/apps/desktop/native-messaging-test-runner/.eslintrc.json b/apps/desktop/native-messaging-test-runner/.eslintrc.json new file mode 100644 index 00000000000..d5ba8f9d9ca --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "rules": { + "no-console": "off" + } +} diff --git a/apps/desktop/native-messaging-test-runner/package-lock.json b/apps/desktop/native-messaging-test-runner/package-lock.json new file mode 100644 index 00000000000..34b1bb54068 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/package-lock.json @@ -0,0 +1,681 @@ +{ + "name": "native-messaging-test-runner", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "native-messaging-test-runner", + "version": "1.0.0", + "license": "GPL-3.0", + "dependencies": { + "@bitwarden/common": "file:../../../libs/common", + "@bitwarden/node": "file:../../../libs/node", + "module-alias": "^2.2.2", + "node-ipc": "9.2.1", + "ts-node": "^10.9.1", + "uuid": "^8.3.2", + "yargs": "^17.5.1" + }, + "devDependencies": { + "@tsconfig/node16": "^1.0.3", + "@types/node": "^18.6.5", + "@types/node-ipc": "9.2.0", + "typescript": "^4.7.4" + } + }, + "../../../libs/common": { + "name": "@bitwarden/common", + "version": "0.0.0", + "license": "GPL-3.0" + }, + "../../../libs/node": { + "name": "@bitwarden/node", + "version": "0.0.0", + "license": "GPL-3.0", + "dependencies": { + "@bitwarden/common": "file:../common" + } + }, + "node_modules/@bitwarden/common": { + "resolved": "../../../libs/common", + "link": true + }, + "node_modules/@bitwarden/node": { + "resolved": "../../../libs/node", + "link": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.6.5", + "license": "MIT" + }, + "node_modules/@types/node-ipc": { + "version": "9.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.8.0", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "license": "MIT" + }, + "node_modules/diff": { + "version": "4.0.2", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/js-queue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz", + "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==", + "dependencies": { + "easy-stack": "^1.0.1" + }, + "engines": { + "node": ">=1.0.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "license": "ISC" + }, + "node_modules/module-alias": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", + "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" + }, + "node_modules/node-ipc": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz", + "integrity": "sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ==", + "dependencies": { + "event-pubsub": "4.3.0", + "js-message": "1.0.7", + "js-queue": "2.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "@bitwarden/common": { + "version": "file:../../../libs/common" + }, + "@bitwarden/node": { + "version": "file:../../../libs/node", + "requires": { + "@bitwarden/common": "file:../common" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0" + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@tsconfig/node10": { + "version": "1.0.9" + }, + "@tsconfig/node12": { + "version": "1.0.11" + }, + "@tsconfig/node14": { + "version": "1.0.3" + }, + "@tsconfig/node16": { + "version": "1.0.3" + }, + "@types/node": { + "version": "18.6.5" + }, + "@types/node-ipc": { + "version": "9.2.0", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "acorn": { + "version": "8.8.0" + }, + "acorn-walk": { + "version": "8.2.0" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "arg": { + "version": "4.1.3" + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "create-require": { + "version": "1.1.1" + }, + "diff": { + "version": "4.0.2" + }, + "easy-stack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz", + "integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "event-pubsub": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz", + "integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "js-message": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==", + "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", + "integrity": "sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA==" + }, + "js-queue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz", + "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==", + "resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz", + "integrity": "sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA==", + "requires": { + "easy-stack": "^1.0.1" + } + }, + "make-error": { + "version": "1.3.6" + }, + "module-alias": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/module-alias/-/module-alias-2.2.2.tgz", + "integrity": "sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q==" + }, + "node-ipc": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz", + "integrity": "sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ==", + "requires": { + "event-pubsub": "4.3.0", + "js-message": "1.0.7", + "js-queue": "2.0.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "ts-node": { + "version": "10.9.1", + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "typescript": { + "version": "4.7.4" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "yn": { + "version": "3.1.1" + } + } +} diff --git a/apps/desktop/native-messaging-test-runner/package.json b/apps/desktop/native-messaging-test-runner/package.json new file mode 100644 index 00000000000..85d4a1ab6a6 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/package.json @@ -0,0 +1,35 @@ +{ + "name": "native-messaging-test-runner", + "version": "1.0.0", + "description": "Test runner for Desktop native messaging", + "main": "dist/bw-handshake.ts", + "scripts": { + "handshake": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-handshake.js", + "status": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-status.js", + "retrieve": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-retrieval.js", + "create": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-create.js", + "update": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-update.js", + "generate": "tsc && node dist/apps/desktop/native-messaging-test-runner/src/commands/bw-generate-password.js" + }, + "author": "Bitwarden Inc. (https://bitwarden.com)", + "license": "GPL-3.0", + "dependencies": { + "@bitwarden/common": "file:../../../libs/common", + "@bitwarden/node": "file:../../../libs/node", + "module-alias": "^2.2.2", + "node-ipc": "9.2.1", + "ts-node": "^10.9.1", + "uuid": "^8.3.2", + "yargs": "^17.5.1" + }, + "devDependencies": { + "@tsconfig/node16": "^1.0.3", + "@types/node": "^18.6.5", + "@types/node-ipc": "9.2.0", + "typescript": "^4.7.4" + }, + "_moduleAliases": { + "@bitwarden/common": "dist/libs/common/src", + "@bitwarden/node/services/nodeCryptoFunction.service": "dist/libs/node/src/services/nodeCryptoFunction.service" + } +} diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-create.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-create.ts new file mode 100644 index 00000000000..a017b4c72cb --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-create.ts @@ -0,0 +1,66 @@ +import "module-alias/register"; + +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { CredentialCreatePayload } from "../../../src/models/nativeMessaging/encryptedMessagePayloads/credentialCreatePayload"; +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +const argv: any = yargs(hideBin(process.argv)).option("name", { + alias: "n", + demand: true, + describe: "Name that the created login will be given", + type: "string", +}).argv; + +const { name } = argv; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + // Handshake + LogUtils.logInfo("Sending Handshake"); + const handshakeResponse = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + + if (!handshakeResponse.status) { + LogUtils.logError(" Handshake failed. Error was: " + handshakeResponse.error); + nativeMessageService.disconnect(); + return; + } + + // Get active account userId + const status = await nativeMessageService.checkStatus(handshakeResponse.sharedKey); + + const activeUser = status.payload.filter((a) => a.active === true && a.status === "unlocked")[0]; + if (activeUser === undefined) { + LogUtils.logError("No active or unlocked user"); + } + LogUtils.logInfo("Active userId: " + activeUser.id); + + LogUtils.logSuccess("Handshake success response"); + const response = await nativeMessageService.credentialCreation(handshakeResponse.sharedKey, { + name: name, + userName: "SuperAwesomeUser", + password: "dolhpin", + uri: "google.com", + userId: activeUser.id, + } as CredentialCreatePayload); + + if (response.payload.status === "failure") { + LogUtils.logError("Failure response returned "); + } else if (response.payload.status === "success") { + LogUtils.logSuccess("Success response returned "); + } else if (response.payload.error === "locked") { + LogUtils.logError("Error: vault is locked"); + } else { + LogUtils.logWarning("Other response: ", response); + } + + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-retrieval.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-retrieval.ts new file mode 100644 index 00000000000..17244623b55 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-retrieval.ts @@ -0,0 +1,46 @@ +import "module-alias/register"; + +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +const argv: any = yargs(hideBin(process.argv)).option("uri", { + alias: "u", + demand: true, + describe: "The uri to retrieve logins for", + type: "string", +}).argv; + +const { uri } = argv; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + // Handshake + LogUtils.logInfo("Sending Handshake"); + const handshakeResponse = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + + if (!handshakeResponse.status) { + LogUtils.logError(" Handshake failed. Error was: " + handshakeResponse.error); + nativeMessageService.disconnect(); + return; + } + + LogUtils.logSuccess("Handshake success response"); + const response = await nativeMessageService.credentialRetrieval(handshakeResponse.sharedKey, uri); + + if (response.payload.error != null) { + LogUtils.logError("Error response returned: ", response.payload.error); + } else { + LogUtils.logSuccess("Credentials returned ", response); + } + + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-update.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-update.ts new file mode 100644 index 00000000000..ecfbd3f5bb8 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-credential-update.ts @@ -0,0 +1,89 @@ +import "module-alias/register"; + +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { CredentialUpdatePayload } from "../../../src/models/nativeMessaging/encryptedMessagePayloads/credentialUpdatePayload"; +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +// Command line arguments +const argv: any = yargs(hideBin(process.argv)) + .option("name", { + alias: "n", + demand: true, + describe: "Name that the updated login will be given", + type: "string", + }) + .option("username", { + alias: "u", + demand: true, + describe: "Username that the login will be given", + type: "string", + }) + .option("password", { + alias: "p", + demand: true, + describe: "Password that the login will be given", + type: "string", + }) + .option("uri", { + demand: true, + describe: "Uri that the login will be given", + type: "string", + }) + .option("credentialId", { + demand: true, + describe: "GUID of the credential to update", + type: "string", + }).argv; + +const { name, username, password, uri, credentialId } = argv; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + // Handshake + LogUtils.logInfo("Sending Handshake"); + const handshakeResponse = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + + if (!handshakeResponse.status) { + LogUtils.logError(" Handshake failed. Error was: " + handshakeResponse.error); + nativeMessageService.disconnect(); + return; + } + LogUtils.logSuccess("Handshake success response"); + + // Get active account userId + const status = await nativeMessageService.checkStatus(handshakeResponse.sharedKey); + + const activeUser = status.payload.filter((a) => a.active === true && a.status === "unlocked")[0]; + if (activeUser === undefined) { + LogUtils.logError("No active or unlocked user"); + } + LogUtils.logInfo("Active userId: " + activeUser.id); + + const response = await nativeMessageService.credentialUpdate(handshakeResponse.sharedKey, { + name: name, + password: password, + userName: username, + uri: uri, + userId: activeUser.id, + credentialId: credentialId, + } as CredentialUpdatePayload); + + if (response.payload.status === "failure") { + LogUtils.logError("Failure response returned "); + } else if (response.payload.status === "success") { + LogUtils.logSuccess("Success response returned "); + } else { + LogUtils.logWarning("Other response: ", response); + } + + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-generate-password.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-generate-password.ts new file mode 100644 index 00000000000..34bb41abb95 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-generate-password.ts @@ -0,0 +1,46 @@ +import "module-alias/register"; + +import yargs from "yargs"; +import { hideBin } from "yargs/helpers"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +const argv: any = yargs(hideBin(process.argv)).option("userId", { + alias: "u", + demand: true, + describe: "UserId to generate password for", + type: "string", +}).argv; + +const { userId } = argv; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + // Handshake + LogUtils.logInfo("Sending Handshake"); + const handshakeResponse = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + + if (!handshakeResponse.status) { + LogUtils.logError(" Handshake failed. Error was: " + handshakeResponse.error); + nativeMessageService.disconnect(); + return; + } + + LogUtils.logSuccess("Handshake success response"); + const response = await nativeMessageService.generatePassword(handshakeResponse.sharedKey, userId); + + if (response.payload.error != null) { + LogUtils.logError("Error response returned: ", response.payload.error); + } else { + LogUtils.logSuccess("Response: ", response); + } + + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-handshake.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-handshake.ts new file mode 100644 index 00000000000..f3098062c46 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-handshake.ts @@ -0,0 +1,25 @@ +import "module-alias/register"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + + const response = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + LogUtils.logSuccess("Received response to handshake request"); + if (response.status) { + LogUtils.logSuccess("Handshake success response"); + } else if (response.error === "canceled") { + LogUtils.logWarning("Handshake canceled by user"); + } else { + LogUtils.logError("Handshake failure response"); + } + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/commands/bw-status.ts b/apps/desktop/native-messaging-test-runner/src/commands/bw-status.ts new file mode 100644 index 00000000000..7782e203cb8 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/commands/bw-status.ts @@ -0,0 +1,29 @@ +import "module-alias/register"; + +import { NativeMessagingVersion } from "@bitwarden/common/enums/nativeMessagingVersion"; + +import { LogUtils } from "../logUtils"; +import NativeMessageService from "../nativeMessageService"; +import * as config from "../variables"; + +(async () => { + const nativeMessageService = new NativeMessageService(NativeMessagingVersion.One); + + LogUtils.logInfo("Sending Handshake"); + const handshakeResponse = await nativeMessageService.sendHandshake( + config.testRsaPublicKey, + config.applicationName + ); + LogUtils.logSuccess("Received response to handshake request"); + + if (!handshakeResponse.status) { + LogUtils.logError(" Handshake failed. Error was: " + handshakeResponse.error); + nativeMessageService.disconnect(); + return; + } + LogUtils.logSuccess("Handshake success response"); + const status = await nativeMessageService.checkStatus(handshakeResponse.sharedKey); + + LogUtils.logSuccess("Status output is: ", status); + nativeMessageService.disconnect(); +})(); diff --git a/apps/desktop/native-messaging-test-runner/src/deferred.ts b/apps/desktop/native-messaging-test-runner/src/deferred.ts new file mode 100644 index 00000000000..b6478bcf268 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/deferred.ts @@ -0,0 +1,26 @@ +// Wrapper for a promise that we can await the promise in one case +// while allowing an unrelated event to fulfill it elsewhere. +export default class Deferred { + private promise: Promise; + private resolver: (T?) => void; + private rejecter: (Error?) => void; + + constructor() { + this.promise = new Promise((resolve, reject) => { + this.resolver = resolve; + this.rejecter = reject; + }); + } + + resolve(value?: T) { + this.resolver(value); + } + + reject(error?: Error) { + this.rejecter(error); + } + + getPromise(): Promise { + return this.promise; + } +} diff --git a/apps/desktop/native-messaging-test-runner/src/ipcService.ts b/apps/desktop/native-messaging-test-runner/src/ipcService.ts new file mode 100644 index 00000000000..eadc69a3513 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/ipcService.ts @@ -0,0 +1,166 @@ +import { homedir } from "os"; + +import * as NodeIPC from "node-ipc"; + +import { MessageCommon } from "../../src/models/nativeMessaging/messageCommon"; +import { UnencryptedMessageResponse } from "../../src/models/nativeMessaging/unencryptedMessageResponse"; + +import Deferred from "./deferred"; +import { race } from "./race"; + +NodeIPC.config.id = "native-messaging-test-runner"; +NodeIPC.config.maxRetries = 0; +NodeIPC.config.silent = true; + +const DESKTOP_APP_PATH = `${homedir}/tmp/app.bitwarden`; +const DEFAULT_MESSAGE_TIMEOUT = 10 * 1000; // 10 seconds + +export type MessageHandler = (MessageCommon) => void; + +export enum IPCConnectionState { + Disconnected = "disconnected", + Connecting = "connecting", + Connected = "connected", +} + +export type IPCOptions = { + overrideTimeout?: number; +}; + +export default class IPCService { + // The current connection state of the socket. + private connectionState: IPCConnectionState = IPCConnectionState.Disconnected; + + // Messages that have been sent, but have not yet received responses + private pendingMessages = new Map>(); + + // A set of deferred promises that are awaiting socket connection + private awaitingConnection = new Set>(); + + constructor(private socketName: string, private messageHandler: MessageHandler) {} + + async connect(): Promise { + console.log("[IPCService] connecting..."); + if (this.connectionState === IPCConnectionState.Connected) { + // Socket is already connected. Don't throw, just allow the callsite to proceed + return; + } + + const deferredConnections = new Deferred(); + + this.awaitingConnection.add(deferredConnections); + + // If the current connection state is disconnected, we should start trying to connect. + // The only other possible connection state at this point is "connecting" and if this + // is the case, we just want to add a deferred promise to the awaitingConnection collection + // and not try to initiate the connection again. + if (this.connectionState === IPCConnectionState.Disconnected) { + this._connect(); + } + + return deferredConnections.getPromise(); + } + + private _connect() { + this.connectionState = IPCConnectionState.Connecting; + + NodeIPC.connectTo(this.socketName, DESKTOP_APP_PATH, () => { + // Process incoming message + this.getSocket().on("message", (message: any) => { + this.processMessage(message); + }); + + this.getSocket().on("error", (error: Error) => { + // Only makes sense as long as config.maxRetries stays set to 0. Otherwise this will be + // invoked multiple times each time a connection error happens + console.log("[IPCService] errored"); + console.log( + "\x1b[33m Please make sure the desktop app is running locally and 'Allow DuckDuckGo browser integration' setting is enabled \x1b[0m" + ); + this.awaitingConnection.forEach((deferred) => { + console.log(`rejecting: ${deferred}`); + deferred.reject(error); + }); + this.awaitingConnection.clear(); + }); + + this.getSocket().on("connect", () => { + console.log("[IPCService] connected"); + this.connectionState = IPCConnectionState.Connected; + + this.awaitingConnection.forEach((deferred) => { + deferred.resolve(null); + }); + this.awaitingConnection.clear(); + }); + + this.getSocket().on("disconnect", () => { + console.log("[IPCService] disconnected"); + this.connectionState = IPCConnectionState.Disconnected; + }); + }); + } + + disconnect() { + console.log("[IPCService] disconnecting..."); + if (this.connectionState !== IPCConnectionState.Disconnected) { + NodeIPC.disconnect(this.socketName); + } + } + + async sendMessage( + message: MessageCommon, + options: IPCOptions = {} + ): Promise { + console.log("[IPCService] sendMessage"); + if (this.pendingMessages.has(message.messageId)) { + throw new Error(`A message with the id: ${message.messageId} has already been sent.`); + } + + // Creates a new deferred promise that allows us to convert a message received over the IPC socket + // into a response for a message that we previously sent. This mechanism relies on the fact that we + // create a unique message id and attach it with each message. Response messages are expected to + // include the message id of the message they are responding to. + const deferred = new Deferred(); + + this.pendingMessages.set(message.messageId, deferred); + + this.getSocket().emit("message", message); + + try { + // Since we can not guarentee that a response message will ever be sent, we put a timeout + // on messages + return race({ + promise: deferred.getPromise(), + timeout: options?.overrideTimeout ?? DEFAULT_MESSAGE_TIMEOUT, + error: new Error(`Message: ${message.messageId} timed out`), + }); + } catch (error) { + // If there is a timeout, remove the message from the pending messages set + // before triggering error handling elsewhere. + this.pendingMessages.delete(message.messageId); + throw error; + } + } + + private getSocket() { + return NodeIPC.of[this.socketName]; + } + + private processMessage(message: any) { + // If the message is a response to a previous message, resolve the deferred promise that + // is awaiting that response. Otherwise, assume this was a new message that wasn't sent as a + // response and invoke the message handler. + if (message.messageId && this.pendingMessages.has(message.messageId)) { + const deferred = this.pendingMessages.get(message.messageId); + + // In the future, this could be improved to add ability to reject, but most messages coming in are + // encrypted at this point so we're unable to determine if they contain error info. + deferred.resolve(message); + + this.pendingMessages.delete(message.messageId); + } else { + this.messageHandler(message); + } + } +} diff --git a/apps/desktop/native-messaging-test-runner/src/logUtils.ts b/apps/desktop/native-messaging-test-runner/src/logUtils.ts new file mode 100644 index 00000000000..0e7c39742e3 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/logUtils.ts @@ -0,0 +1,29 @@ +/* eslint-disable no-console */ + +// Class for logging messages with colors for ease of reading important info +// Reference: https://stackoverflow.com/a/41407246 +export class LogUtils { + static logSuccess(message: string, payload?: any): void { + this.logFormat(message, "32", payload); + } + + static logWarning(message: string, payload?: any): void { + this.logFormat(message, "33", payload); + } + + static logError(message: string, payload?: any): void { + this.logFormat(message, "31", payload); + } + + static logInfo(message: string, payload?: any): void { + this.logFormat(message, "36", payload); + } + + private static logFormat(message: string, color: string, payload?: any) { + if (payload) { + console.log(`\x1b[${color}m ${message} \x1b[0m`, payload); + } else { + console.log(`\x1b[${color}m ${message} \x1b[0m`); + } + } +} diff --git a/apps/desktop/native-messaging-test-runner/src/nativeMessageService.ts b/apps/desktop/native-messaging-test-runner/src/nativeMessageService.ts new file mode 100644 index 00000000000..ada09064e3c --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/nativeMessageService.ts @@ -0,0 +1,235 @@ +import "module-alias/register"; + +import { v4 as uuidv4 } from "uuid"; + +import { Utils } from "@bitwarden/common/misc/utils"; +import { EncString } from "@bitwarden/common/models/domain/encString"; +import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey"; +import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service"; +import { EncryptService } from "@bitwarden/common/services/encrypt.service"; +import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service"; + +import { DecryptedCommandData } from "../../src/models/nativeMessaging/decryptedCommandData"; +import { EncryptedMessage } from "../../src/models/nativeMessaging/encryptedMessage"; +import { CredentialCreatePayload } from "../../src/models/nativeMessaging/encryptedMessagePayloads/credentialCreatePayload"; +import { CredentialUpdatePayload } from "../../src/models/nativeMessaging/encryptedMessagePayloads/credentialUpdatePayload"; +import { EncryptedMessageResponse } from "../../src/models/nativeMessaging/encryptedMessageResponse"; +import { MessageCommon } from "../../src/models/nativeMessaging/messageCommon"; +import { UnencryptedMessage } from "../../src/models/nativeMessaging/unencryptedMessage"; +import { UnencryptedMessageResponse } from "../../src/models/nativeMessaging/unencryptedMessageResponse"; + +import IPCService, { IPCOptions } from "./ipcService"; +import * as config from "./variables"; + +type HandshakeResponse = { + status: boolean; + sharedKey: string; + error?: "canceled" | "cannot-decrypt"; +}; + +const CONFIRMATION_MESSAGE_TIMEOUT = 100 * 1000; // 100 seconds + +export default class NativeMessageService { + private ipcService: IPCService; + private nodeCryptoFunctionService: NodeCryptoFunctionService; + private encryptService: EncryptService; + + constructor(private apiVersion: number) { + console.log("Starting native messaging service"); + this.ipcService = new IPCService(`bitwarden`, (rawMessage) => { + console.log(`Received unexpected: `, rawMessage); + }); + + this.nodeCryptoFunctionService = new NodeCryptoFunctionService(); + this.encryptService = new EncryptService( + this.nodeCryptoFunctionService, + new ConsoleLogService(false), + false + ); + } + + // Commands + + async sendHandshake(publicKey: string, applicationName: string): Promise { + const rawResponse = await this.sendUnencryptedMessage( + { + command: "bw-handshake", + payload: { + publicKey, + applicationName: applicationName, + }, + }, + { + overrideTimeout: CONFIRMATION_MESSAGE_TIMEOUT, + } + ); + return rawResponse.payload as HandshakeResponse; + } + + async checkStatus(key: string): Promise { + const encryptedCommand = await this.encryptCommandData( + { + command: "bw-status", + }, + key + ); + + const response = await this.sendEncryptedMessage({ + encryptedCommand, + }); + + return this.decryptResponsePayload(response.encryptedPayload, key); + } + + async credentialRetrieval(key: string, uri: string): Promise { + const encryptedCommand = await this.encryptCommandData( + { + command: "bw-credential-retrieval", + payload: { + uri: uri, + }, + }, + key + ); + const response = await this.sendEncryptedMessage({ + encryptedCommand, + }); + + return this.decryptResponsePayload(response.encryptedPayload, key); + } + + async credentialCreation( + key: string, + credentialData: CredentialCreatePayload + ): Promise { + const encryptedCommand = await this.encryptCommandData( + { + command: "bw-credential-create", + payload: credentialData, + }, + key + ); + const response = await this.sendEncryptedMessage({ + encryptedCommand, + }); + + return this.decryptResponsePayload(response.encryptedPayload, key); + } + + async credentialUpdate( + key: string, + credentialData: CredentialUpdatePayload + ): Promise { + const encryptedCommand = await this.encryptCommandData( + { + command: "bw-credential-update", + payload: credentialData, + }, + key + ); + const response = await this.sendEncryptedMessage({ + encryptedCommand, + }); + + return this.decryptResponsePayload(response.encryptedPayload, key); + } + + async generatePassword(key: string, userId: string): Promise { + const encryptedCommand = await this.encryptCommandData( + { + command: "bw-generate-password", + payload: { + userId: userId, + }, + }, + key + ); + const response = await this.sendEncryptedMessage({ + encryptedCommand, + }); + + return this.decryptResponsePayload(response.encryptedPayload, key); + } + + // Private message sending + + private async sendEncryptedMessage( + message: Omit, + options: IPCOptions = {} + ): Promise { + const result = await this.sendMessage(message, options); + return result as EncryptedMessageResponse; + } + + private async sendUnencryptedMessage( + message: Omit, + options: IPCOptions = {} + ): Promise { + const result = await this.sendMessage(message, options); + return result as UnencryptedMessageResponse; + } + + private async sendMessage( + message: + | Omit + | Omit, + options: IPCOptions + ): Promise { + // Attempt to connect before sending any messages. If the connection has already + // been made, this is a NOOP within the IPCService. + await this.ipcService.connect(); + + const commonFields: MessageCommon = { + // Create a messageId that can be used as a lookup when we get a response + messageId: uuidv4(), + version: this.apiVersion, + }; + const fullMessage: UnencryptedMessage | EncryptedMessage = { + ...message, + ...commonFields, + }; + + console.log(`[NativeMessageService] sendMessage with id: ${fullMessage.messageId}`); + + const response = await this.ipcService.sendMessage(fullMessage, options); + + console.log(`[NativeMessageService] received response for message: ${fullMessage.messageId}`); + + return response; + } + + disconnect() { + this.ipcService.disconnect(); + } + + // Data Encryption + private async encryptCommandData( + commandData: DecryptedCommandData, + key: string + ): Promise { + const commandDataString = JSON.stringify(commandData); + + const sharedKey = await this.getSharedKeyForKey(key); + + return this.encryptService.encrypt(commandDataString, sharedKey); + } + + private async decryptResponsePayload( + payload: EncString, + key: string + ): Promise { + const sharedKey = await this.getSharedKeyForKey(key); + const decrypted = await this.encryptService.decryptToUtf8(payload, sharedKey); + + return JSON.parse(decrypted); + } + + private async getSharedKeyForKey(key: string): Promise { + const dataBuffer = Utils.fromB64ToArray(key).buffer; + const privKey = Utils.fromB64ToArray(config.testRsaPrivateKey).buffer; + + return new SymmetricCryptoKey( + await this.nodeCryptoFunctionService.rsaDecrypt(dataBuffer, privKey, "sha1") + ); + } +} diff --git a/apps/desktop/native-messaging-test-runner/src/race.ts b/apps/desktop/native-messaging-test-runner/src/race.ts new file mode 100644 index 00000000000..7aba3aa41f9 --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/race.ts @@ -0,0 +1,25 @@ +export const race = ({ + promise, + timeout, + error, +}: { + promise: Promise; + timeout: number; + error?: Error; +}) => { + let timer = null; + + // Similar to Promise.all, but instead of waiting for all, it resolves once one promise finishes. + // Using this so we can reject if the timeout threshold is hit + return Promise.race([ + new Promise((_, reject) => { + timer = setTimeout(reject, timeout, error); + return timer; + }), + + promise.then((value) => { + clearTimeout(timer); + return value; + }), + ]); +}; diff --git a/apps/desktop/native-messaging-test-runner/src/variables.ts b/apps/desktop/native-messaging-test-runner/src/variables.ts new file mode 100644 index 00000000000..973da2c224b --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/src/variables.ts @@ -0,0 +1,27 @@ +export const applicationName = "Native Messaging Test Runner"; +export const encryptionAlogrithm = "sha1"; +export const testRsaPublicKey = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP" + + "4xlU2ab/v0crqIfXfIoWF/XXdHGIdrZeilnRXPPJT1B9dTsasttEZNnua/0Rek/cjNDHtzT52irfoZYS7X6HNIfOi54Q+egP" + + "RQ1H7iNHVZz3K8Db9GCSKPeC8MbW6gVCzb15esCe1gGzg6wkMuWYDFYPoh/oBqcIqrGah7firqB1nDedzEjw32heP2DAffVN" + + "084iTDjiWrJNUxBJ2pDD5Z9dT3MzQ2s09ew1yMWK2z37rT3YerC7OgEDmo3WYo3xL3qYJznu3EO2nmrYjiRa40wKSjxsTlUc" + + "xDF+F0uMW8oR9EMUHgepdepfAtLsSAQIDAQAB"; +export const testRsaPrivateKey = + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCXRVrCX+2hfOQS8Hz" + + "YUS2oc/jGVTZpv+/Ryuoh9d8ihYX9dd0cYh2tl6KWdFc88lPUH11Oxqy20Rk2e5r/RF6T9yM0Me3NPnaKt+hlhLtfoc0h86L" + + "nhD56A9FDUfuI0dVnPcrwNv0YJIo94LwxtbqBULNvXl6wJ7WAbODrCQy5ZgMVg+iH+gGpwiqsZqHt+KuoHWcN53MSPDfaF4/" + + "YMB99U3TziJMOOJask1TEEnakMPln11PczNDazT17DXIxYrbPfutPdh6sLs6AQOajdZijfEvepgnOe7cQ7aeatiOJFrjTApK" + + "PGxOVRzEMX4XS4xbyhH0QxQeB6l16l8C0uxIBAgMBAAECggEASaWfeVDA3cVzOPFSpvJm20OTE+R6uGOU+7vh36TX/POq92q" + + "Buwbd0h0oMD32FxsXywd2IxtBDUSiFM9699qufTVuM0Q3tZw6lHDTOVG08+tPdr8qSbMtw7PGFxN79fHLBxejjO4IrM9lapj" + + "WpxEF+11x7r+wM+0xRZQ8sNFYG46aPfIaty4BGbL0I2DQ2y8I57iBCAy69eht59NLMm27fRWGJIWCuBIjlpfzET1j2HLXUIh" + + "5bTBNzqaN039WH49HczGE3mQKVEJZc/efk3HaVd0a1Sjzyn0QY+N1jtZN3jTRbuDWA1AknkX1LX/0tUhuS3/7C3ejHxjw4Dk" + + "1ZLo5/QKBgQDIWvqFn0+IKRSu6Ua2hDsufIHHUNLelbfLUMmFthxabcUn4zlvIscJO00Tq/ezopSRRvbGiqnxjv/mYxucvOU" + + "BeZtlus0Q9RTACBtw9TGoNTmQbEunJ2FOSlqbQxkBBAjgGEppRPt30iGj/VjAhCATq2MYOa/X4dVR51BqQAFIEwKBgQDBSIf" + + "TFKC/hDk6FKZlgwvupWYJyU9RkyfstPErZFmzoKhPkQ3YORo2oeAYmVUbS9I2iIYpYpYQJHX8jMuCbCz4ONxTCuSIXYQYUcU" + + "q4PglCKp31xBAE6TN8SvhfME9/MvuDssnQinAHuF0GDAhF646T3LLS1not6Vszv7brwSoGwKBgQC88v/8cGfi80ssQZeMnVv" + + "q1UTXIeQcQnoY5lGHJl3K8mbS3TnXE6c9j417Fdz+rj8KWzBzwWXQB5pSPflWcdZO886Xu/mVGmy9RWgLuVFhXwCwsVEPjNX" + + "5ramRb0/vY0yzenUCninBsIxFSbIfrPtLUYCc4hpxr+sr2Mg/y6jpvQKBgBezMRRs3xkcuXepuI2R+BCXL1/b02IJTUf1F+1" + + "eLLGd7YV0H+J3fgNc7gGWK51hOrF9JBZHBGeOUPlaukmPwiPdtQZpu4QNE3l37VlIpKTF30E6mb+BqR+nht3rUjarnMXgAoE" + + "Z18y6/KIjpSMpqC92Nnk/EBM9EYe6Cf4eA9ApAoGAeqEUg46UTlJySkBKURGpIs3v1kkf5I0X8DnOhwb+HPxNaiEdmO7ckm8" + + "+tPVgppLcG0+tMdLjigFQiDUQk2y3WjyxP5ZvXu7U96jaJRI8PFMoE06WeVYcdIzrID2HvqH+w0UQJFrLJ/0Mn4stFAEzXKZ" + + "BokBGnjFnTnKcs7nv/O8="; diff --git a/apps/desktop/native-messaging-test-runner/tsconfig.json b/apps/desktop/native-messaging-test-runner/tsconfig.json new file mode 100644 index 00000000000..a34554a264f --- /dev/null +++ b/apps/desktop/native-messaging-test-runner/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "outDir": "dist", + "target": "es6", + "module": "CommonJS", + "moduleResolution": "node", + "sourceMap": false, + "declaration": false, + "paths": { + "@src/*": ["src/*"], + "@bitwarden/node/*": ["../../../libs/node/src/*"], + "@bitwarden/common/*": ["../../../libs/common/src/*"] + } + }, + "exclude": ["node_modules"] +} diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 58b31e7dbfd..61a3e05b58c 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -18,10 +18,11 @@ "scripts": { "postinstall": "electron-rebuild", "start": "cross-env ELECTRON_IS_DEV=0 ELECTRON_NO_UPDATER=1 electron ./build", + "build-native": "cargo build --manifest-path=./desktop_native/Cargo.toml", "build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"", "build:dev": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main:dev\" \"npm run build:renderer:dev\"", "build:main": "cross-env NODE_ENV=production webpack --config webpack.main.js", - "build:main:dev": "cross-env NODE_ENV=development webpack --config webpack.main.js", + "build:main:dev": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.main.js", "build:renderer": "cross-env NODE_ENV=production webpack --config webpack.renderer.js", "build:renderer:dev": "cross-env NODE_ENV=development webpack --config webpack.renderer.js", "build:renderer:watch": "cross-env NODE_ENV=development webpack --config webpack.renderer.js --watch", @@ -48,6 +49,9 @@ "publish:mac:mas": "npm run dist:mac:mas && npm run upload:mas", "publish:win": "npm run build && npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p always -c.win.certificateSubjectName=\"8bit Solutions LLC\"", "publish:win:dev": "npm run build && npm run clean:dist && electron-builder --win --x64 --arm64 --ia32 -p always", - "upload:mas": "xcrun altool --upload-app --type osx --file \"$(find ./dist/mas-universal/Bitwarden*.pkg)\" --username $APPLE_ID_USERNAME --password $APPLE_ID_PASSWORD" + "upload:mas": "xcrun altool --upload-app --type osx --file \"$(find ./dist/mas-universal/Bitwarden*.pkg)\" --username $APPLE_ID_USERNAME --password $APPLE_ID_PASSWORD", + "test": "jest", + "test:watch": "jest --watch", + "test:watch:all": "jest --watchAll" } } diff --git a/apps/desktop/src/app/accounts/login.component.html b/apps/desktop/src/app/accounts/login.component.html index 314b0550621..c11ed881b00 100644 --- a/apps/desktop/src/app/accounts/login.component.html +++ b/apps/desktop/src/app/accounts/login.component.html @@ -16,6 +16,7 @@ #form (ngSubmit)="submit()" [appApiAction]="formPromise" + [formGroup]="formGroup" attr.aria-hidden="{{ showingModal }}" >
@@ -25,14 +26,7 @@
- +
@@ -40,10 +34,8 @@
diff --git a/apps/desktop/src/app/accounts/login.component.ts b/apps/desktop/src/app/accounts/login.component.ts index 959c8a45650..33eefbd57ec 100644 --- a/apps/desktop/src/app/accounts/login.component.ts +++ b/apps/desktop/src/app/accounts/login.component.ts @@ -1,4 +1,5 @@ import { Component, NgZone, OnDestroy, ViewChild, ViewContainerRef } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; import { Router } from "@angular/router"; import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/components/login.component"; @@ -7,6 +8,7 @@ import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service"; import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; @@ -47,7 +49,9 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy { private broadcasterService: BroadcasterService, ngZone: NgZone, private messagingService: MessagingService, - logService: LogService + logService: LogService, + formBuilder: FormBuilder, + formValidationErrorService: FormValidationErrorsService ) { super( authService, @@ -59,7 +63,9 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy { passwordGenerationService, cryptoFunctionService, logService, - ngZone + ngZone, + formBuilder, + formValidationErrorService ); super.onSuccessfulLogin = () => { return syncService.fullSync(true); diff --git a/apps/desktop/src/app/accounts/settings.component.html b/apps/desktop/src/app/accounts/settings.component.html index 420ee20a39e..a1ecc0732f9 100644 --- a/apps/desktop/src/app/accounts/settings.component.html +++ b/apps/desktop/src/app/accounts/settings.component.html @@ -309,6 +309,23 @@
{{ "enableBrowserIntegrationDesc" | i18n }}
+
+
+ +
+ {{ + "enableDuckDuckGoBrowserIntegrationDesc" | i18n + }} +
-
-
- diff --git a/apps/web/src/app/accounts/login/login-with-device.component.html b/apps/web/src/app/accounts/login/login-with-device.component.html new file mode 100644 index 00000000000..3e5f48d597c --- /dev/null +++ b/apps/web/src/app/accounts/login/login-with-device.component.html @@ -0,0 +1,44 @@ +
+
+ +

+ {{ "loginOrCreateNewAccount" | i18n }} +

+ +
+

{{ "logInInitiated" | i18n }}

+ +
+

{{ "notificationSentDevice" | i18n }}

+ +

+ {{ "fingerprintMatchInfo" | i18n }} +

+
+ +
+

{{ "fingerprintPhraseHeader" | i18n }}

+

+ {{ passwordlessRequest?.fingerprintPhrase }} +

+
+ + + +
+ +
+ {{ "loginWithDeviceEnabledInfo" | i18n }} + {{ "viewAllLoginOptions" | i18n }} +
+
+
+
diff --git a/apps/web/src/app/accounts/login/login-with-device.component.ts b/apps/web/src/app/accounts/login/login-with-device.component.ts new file mode 100644 index 00000000000..4c6f6268dfd --- /dev/null +++ b/apps/web/src/app/accounts/login/login-with-device.component.ts @@ -0,0 +1,175 @@ +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Router } from "@angular/router"; +import { Subject, takeUntil } from "rxjs"; + +import { CaptchaProtectedComponent } from "@bitwarden/angular/components/captchaProtected.component"; +import { AnonymousHubService } from "@bitwarden/common/abstractions/anonymousHub.service"; +import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { AppIdService } from "@bitwarden/common/abstractions/appId.service"; +import { AuthService } from "@bitwarden/common/abstractions/auth.service"; +import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; +import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; +import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; +import { LogService } from "@bitwarden/common/abstractions/log.service"; +import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; +import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { StateService } from "@bitwarden/common/abstractions/state.service"; +import { AuthRequestType } from "@bitwarden/common/enums/authRequestType"; +import { Utils } from "@bitwarden/common/misc/utils"; +import { PasswordlessLogInCredentials } from "@bitwarden/common/models/domain/logInCredentials"; +import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetricCryptoKey"; +import { PasswordlessCreateAuthRequest } from "@bitwarden/common/models/request/passwordlessCreateAuthRequest"; +import { AuthRequestResponse } from "@bitwarden/common/models/response/authRequestResponse"; + +@Component({ + selector: "app-login-with-device", + templateUrl: "login-with-device.component.html", +}) +export class LoginWithDeviceComponent + extends CaptchaProtectedComponent + implements OnInit, OnDestroy +{ + private destroy$ = new Subject(); + email: string; + showResendNotification = false; + passwordlessRequest: PasswordlessCreateAuthRequest; + onSuccessfulLoginTwoFactorNavigate: () => Promise; + onSuccessfulLogin: () => Promise; + onSuccessfulLoginNavigate: () => Promise; + + protected twoFactorRoute = "2fa"; + protected successRoute = "vault"; + private authRequestKeyPair: [publicKey: ArrayBuffer, privateKey: ArrayBuffer]; + + constructor( + private router: Router, + private cryptoService: CryptoService, + private cryptoFunctionService: CryptoFunctionService, + private appIdService: AppIdService, + private passwordGenerationService: PasswordGenerationService, + private apiService: ApiService, + private authService: AuthService, + private logService: LogService, + private stateService: StateService, + environmentService: EnvironmentService, + i18nService: I18nService, + platformUtilsService: PlatformUtilsService, + private anonymousHubService: AnonymousHubService + ) { + super(environmentService, i18nService, platformUtilsService); + + const navigation = this.router.getCurrentNavigation(); + if (navigation) { + this.email = navigation.extras?.state?.email; + } + + //gets signalR push notification + this.authService + .getPushNotifcationObs$() + .pipe(takeUntil(this.destroy$)) + .subscribe((id) => { + this.confirmResponse(id); + }); + } + + async ngOnInit() { + if (!this.email) { + this.router.navigate(["/login"]); + return; + } + + this.startPasswordlessLogin(); + } + + async startPasswordlessLogin() { + this.showResendNotification = false; + + try { + await this.buildAuthRequest(); + const reqResponse = await this.apiService.postAuthRequest(this.passwordlessRequest); + + if (reqResponse.id) { + this.anonymousHubService.createHubConnection(reqResponse.id); + } + } catch (e) { + this.logService.error(e); + } + + setTimeout(() => { + this.showResendNotification = true; + }, 12000); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + this.anonymousHubService.stopHubConnection(); + } + + private async confirmResponse(requestId: string) { + try { + const response = await this.apiService.getAuthResponse( + requestId, + this.passwordlessRequest.accessCode + ); + + if (!response.requestApproved) { + return; + } + + const credentials = await this.buildLoginCredntials(requestId, response); + await this.authService.logIn(credentials); + if (this.onSuccessfulLogin != null) { + this.onSuccessfulLogin(); + } + if (this.onSuccessfulLoginNavigate != null) { + this.onSuccessfulLoginNavigate(); + } else { + this.router.navigate([this.successRoute]); + } + } catch (error) { + this.logService.error(error); + } + } + + private async buildAuthRequest() { + this.authRequestKeyPair = await this.cryptoFunctionService.rsaGenerateKeyPair(2048); + const fingerprint = await ( + await this.cryptoService.getFingerprint(this.email, this.authRequestKeyPair[0]) + ).join("-"); + const deviceIdentifier = await this.appIdService.getAppId(); + const publicKey = Utils.fromBufferToB64(this.authRequestKeyPair[0]); + const accessCode = await this.passwordGenerationService.generatePassword({ length: 25 }); + + this.passwordlessRequest = new PasswordlessCreateAuthRequest( + this.email, + deviceIdentifier, + publicKey, + AuthRequestType.AuthenticateAndUnlock, + accessCode, + fingerprint + ); + } + + private async buildLoginCredntials( + requestId: string, + response: AuthRequestResponse + ): Promise { + const decKey = await this.cryptoService.rsaDecrypt(response.key, this.authRequestKeyPair[1]); + const decMasterPasswordHash = await this.cryptoService.rsaDecrypt( + response.masterPasswordHash, + this.authRequestKeyPair[1] + ); + const key = new SymmetricCryptoKey(decKey); + const localHashedPassword = Utils.fromBufferToUtf8(decMasterPasswordHash); + + return new PasswordlessLogInCredentials( + this.email, + this.passwordlessRequest.accessCode, + requestId, + key, + localHashedPassword + ); + } +} diff --git a/apps/web/src/app/accounts/login/login.component.html b/apps/web/src/app/accounts/login/login.component.html new file mode 100644 index 00000000000..7df9777f39c --- /dev/null +++ b/apps/web/src/app/accounts/login/login.component.html @@ -0,0 +1,121 @@ +
+
+
+ +

+ {{ "loginOrCreateNewAccount" | i18n }} +

+
+ + {{ "resetPasswordAutoEnrollInviteWarning" | i18n }} + + +
+ + {{ "emailAddress" | i18n }} + + +
+ +
+ + {{ "masterPass" | i18n }} + + + + {{ "getMasterPasswordHint" | i18n }} + + +
+ +
+
+ +
+ + {{ "rememberEmail" | i18n }} + +
+ +
+ +
+ +
+ +
+ + + + + {{ "createAccount" | i18n }} + +
+ +
+ +
+ + +
+
+
+
diff --git a/apps/web/src/app/accounts/login.component.ts b/apps/web/src/app/accounts/login/login.component.ts similarity index 80% rename from apps/web/src/app/accounts/login.component.ts rename to apps/web/src/app/accounts/login/login.component.ts index 6a13ff32337..2568d5a3e74 100644 --- a/apps/web/src/app/accounts/login.component.ts +++ b/apps/web/src/app/accounts/login/login.component.ts @@ -1,4 +1,5 @@ import { Component, NgZone } from "@angular/core"; +import { FormBuilder } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { first } from "rxjs/operators"; @@ -7,6 +8,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { AuthService } from "@bitwarden/common/abstractions/auth.service"; import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service"; import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service"; +import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; @@ -20,7 +22,8 @@ import { Policy } from "@bitwarden/common/models/domain/policy"; import { ListResponse } from "@bitwarden/common/models/response/listResponse"; import { PolicyResponse } from "@bitwarden/common/models/response/policyResponse"; -import { RouterService, StateService } from "../core"; +import { flagEnabled } from "../../../utils/flags"; +import { RouterService, StateService } from "../../core"; @Component({ selector: "app-login", @@ -31,6 +34,7 @@ export class LoginComponent extends BaseLoginComponent { showResetPasswordAutoEnrollWarning = false; enforcedPasswordPolicyOptions: MasterPasswordPolicyOptions; policies: ListResponse; + showPasswordless = false; constructor( authService: AuthService, @@ -48,7 +52,9 @@ export class LoginComponent extends BaseLoginComponent { ngZone: NgZone, protected stateService: StateService, private messagingService: MessagingService, - private routerService: RouterService + private routerService: RouterService, + formBuilder: FormBuilder, + formValidationErrorService: FormValidationErrorsService ) { super( authService, @@ -60,19 +66,22 @@ export class LoginComponent extends BaseLoginComponent { passwordGenerationService, cryptoFunctionService, logService, - ngZone + ngZone, + formBuilder, + formValidationErrorService ); this.onSuccessfulLogin = async () => { this.messagingService.send("setFullWidth"); }; this.onSuccessfulLoginNavigate = this.goAfterLogIn; + this.showPasswordless = flagEnabled("showPasswordless"); } async ngOnInit() { // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe this.route.queryParams.pipe(first()).subscribe(async (qParams) => { if (qParams.email != null && qParams.email.indexOf("@") > -1) { - this.email = qParams.email; + this.formGroup.get("email")?.setValue(qParams.email); } if (qParams.premium != null) { this.routerService.setPreviousUrl("/settings/premium"); @@ -91,7 +100,8 @@ export class LoginComponent extends BaseLoginComponent { this.routerService.setPreviousUrl(route.toString()); } await super.ngOnInit(); - this.rememberEmail = await this.stateService.getRememberEmail(); + const rememberEmail = await this.stateService.getRememberEmail(); + this.formGroup.get("rememberEmail")?.setValue(rememberEmail); }); const invite = await this.stateService.getOrganizationInvitation(); @@ -125,10 +135,12 @@ export class LoginComponent extends BaseLoginComponent { } async goAfterLogIn() { + const masterPassword = this.formGroup.get("masterPassword")?.value; + // Check master password against policy if (this.enforcedPasswordPolicyOptions != null) { const strengthResult = this.passwordGenerationService.passwordStrength( - this.masterPassword, + masterPassword, this.getPasswordStrengthUserInput() ); const masterPasswordScore = strengthResult == null ? null : strengthResult.score; @@ -137,7 +149,7 @@ export class LoginComponent extends BaseLoginComponent { if ( !this.policyService.evaluateMasterPassword( masterPasswordScore, - this.masterPassword, + masterPassword, this.enforcedPasswordPolicyOptions ) ) { @@ -158,19 +170,34 @@ export class LoginComponent extends BaseLoginComponent { } async submit() { - await this.stateService.setRememberEmail(this.rememberEmail); - if (!this.rememberEmail) { + const rememberEmail = this.formGroup.get("rememberEmail")?.value; + + await this.stateService.setRememberEmail(rememberEmail); + if (!rememberEmail) { await this.stateService.setRememberedEmail(null); } - await super.submit(); + await super.submit(false); + } + + async startPasswordlessLogin() { + this.formGroup.get("masterPassword")?.clearValidators(); + this.formGroup.get("masterPassword")?.updateValueAndValidity(); + + if (!this.formGroup.valid) { + return; + } + + const email = this.formGroup.get("email").value; + this.router.navigate(["/login-with-device"], { state: { email: email } }); } private getPasswordStrengthUserInput() { + const email = this.formGroup.get("email")?.value; let userInput: string[] = []; - const atPosition = this.email.indexOf("@"); + const atPosition = email.indexOf("@"); if (atPosition > -1) { userInput = userInput.concat( - this.email + email .substr(0, atPosition) .trim() .toLowerCase() diff --git a/apps/web/src/app/accounts/login/login.module.ts b/apps/web/src/app/accounts/login/login.module.ts new file mode 100644 index 00000000000..9ab8dfb3a1b --- /dev/null +++ b/apps/web/src/app/accounts/login/login.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from "@angular/core"; + +import { SharedModule } from "../../shared"; + +import { LoginWithDeviceComponent } from "./login-with-device.component"; +import { LoginComponent } from "./login.component"; + +@NgModule({ + imports: [SharedModule], + declarations: [LoginComponent, LoginWithDeviceComponent], + exports: [LoginComponent, LoginWithDeviceComponent], +}) +export class LoginModule {} diff --git a/apps/web/src/app/accounts/register-form/register-form.component.html b/apps/web/src/app/accounts/register-form/register-form.component.html index 56364086ff9..d9456d5a6e9 100644 --- a/apps/web/src/app/accounts/register-form/register-form.component.html +++ b/apps/web/src/app/accounts/register-form/register-form.component.html @@ -114,7 +114,9 @@
- {{ "createAccount" | i18n }} + - {{ "logIn" | i18n }} +
diff --git a/apps/web/src/app/accounts/trial-initiation/billing.component.html b/apps/web/src/app/accounts/trial-initiation/billing.component.html index 4486d0672dd..0eb203f72ca 100644 --- a/apps/web/src/app/accounts/trial-initiation/billing.component.html +++ b/apps/web/src/app/accounts/trial-initiation/billing.component.html @@ -40,7 +40,9 @@
- {{ "startTrial" | i18n }} +
diff --git a/apps/web/src/app/accounts/trial-initiation/billing.component.ts b/apps/web/src/app/accounts/trial-initiation/billing.component.ts index 7bf672d09a2..aff798b5b86 100644 --- a/apps/web/src/app/accounts/trial-initiation/billing.component.ts +++ b/apps/web/src/app/accounts/trial-initiation/billing.component.ts @@ -7,8 +7,8 @@ import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; diff --git a/apps/web/src/app/accounts/two-factor-options.component.html b/apps/web/src/app/accounts/two-factor-options.component.html index 690d0a1d995..5c5eccb8831 100644 --- a/apps/web/src/app/accounts/two-factor-options.component.html +++ b/apps/web/src/app/accounts/two-factor-options.component.html @@ -2,7 +2,7 @@
diff --git a/apps/web/src/app/organizations/settings/settings.component.ts b/apps/web/src/app/organizations/settings/settings.component.ts index 318608524b3..9988e65dd7c 100644 --- a/apps/web/src/app/organizations/settings/settings.component.ts +++ b/apps/web/src/app/organizations/settings/settings.component.ts @@ -1,30 +1,34 @@ -import { Component } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; +import { Subject, switchMap, takeUntil } from "rxjs"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; -import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; +import { Organization } from "@bitwarden/common/models/domain/organization"; @Component({ selector: "app-org-settings", templateUrl: "settings.component.html", }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class SettingsComponent { - access2fa = false; - showBilling: boolean; +export class SettingsComponent implements OnInit, OnDestroy { + organization: Organization; - constructor( - private route: ActivatedRoute, - private organizationService: OrganizationService, - private platformUtilsService: PlatformUtilsService - ) {} + private destroy$ = new Subject(); + + constructor(private route: ActivatedRoute, private organizationService: OrganizationService) {} ngOnInit() { - // eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe - this.route.parent.params.subscribe(async (params) => { - const organization = await this.organizationService.get(params.organizationId); - this.showBilling = !this.platformUtilsService.isSelfHost() && organization.canManageBilling; - this.access2fa = organization.use2fa; - }); + this.route.params + .pipe( + switchMap(async (params) => await this.organizationService.get(params.organizationId)), + takeUntil(this.destroy$) + ) + .subscribe((organization) => { + this.organization = organization; + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); } } diff --git a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.html b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.html index caa2260f526..055cdddb38a 100644 --- a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.html +++ b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.html @@ -34,7 +34,9 @@ > - +
diff --git a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts index 673ffa586d6..853907452d2 100644 --- a/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts +++ b/apps/web/src/app/organizations/sponsorships/families-for-enterprise-setup.component.ts @@ -1,12 +1,13 @@ -import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; -import { first } from "rxjs/operators"; +import { Observable, Subject } from "rxjs"; +import { first, map, takeUntil } from "rxjs/operators"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { ValidationService } from "@bitwarden/angular/services/validation.service"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { SyncService } from "@bitwarden/common/abstractions/sync/sync.service.abstraction"; import { PlanSponsorshipType } from "@bitwarden/common/enums/planSponsorshipType"; @@ -15,15 +16,14 @@ import { ProductType } from "@bitwarden/common/enums/productType"; import { Organization } from "@bitwarden/common/models/domain/organization"; import { OrganizationSponsorshipRedeemRequest } from "@bitwarden/common/models/request/organization/organizationSponsorshipRedeemRequest"; +import { DeleteOrganizationComponent } from "../../organizations/settings"; import { OrganizationPlansComponent } from "../../settings/organization-plans.component"; -import { DeleteOrganizationComponent } from "../settings/delete-organization.component"; @Component({ selector: "families-for-enterprise-setup", templateUrl: "families-for-enterprise-setup.component.html", }) -// eslint-disable-next-line rxjs-angular/prefer-takeuntil -export class FamiliesForEnterpriseSetupComponent implements OnInit { +export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy { @ViewChild(OrganizationPlansComponent, { static: false }) set organizationPlansComponent(value: OrganizationPlansComponent) { if (!value) { @@ -46,11 +46,14 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit { token: string; existingFamilyOrganizations: Organization[]; + existingFamilyOrganizations$: Observable; showNewOrganization = false; _organizationPlansComponent: OrganizationPlansComponent; _selectedFamilyOrganizationId = ""; + private _destroy = new Subject(); + constructor( private router: Router, private platformUtilsService: PlatformUtilsService, @@ -84,17 +87,24 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit { await this.syncService.fullSync(true); this.badToken = !(await this.apiService.postPreValidateSponsorshipToken(this.token)); this.loading = false; + }); - this.existingFamilyOrganizations = (await this.organizationService.getAll()).filter( - (o) => o.planProductType === ProductType.Families - ); + this.existingFamilyOrganizations$ = this.organizationService.organizations$.pipe( + map((orgs) => orgs.filter((o) => o.planProductType === ProductType.Families)) + ); - if (this.existingFamilyOrganizations.length === 0) { + this.existingFamilyOrganizations$.pipe(takeUntil(this._destroy)).subscribe((orgs) => { + if (orgs.length === 0) { this.selectedFamilyOrganizationId = "createNew"; } }); } + ngOnDestroy(): void { + this._destroy.next(); + this._destroy.complete(); + } + async submit() { this.formPromise = this.doSubmit(this._selectedFamilyOrganizationId); await this.formPromise; diff --git a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts index 00c2ce2e3f4..adb7ba60246 100644 --- a/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/exposed-passwords-report.component.ts @@ -5,7 +5,7 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { AuditService } from "@bitwarden/common/abstractions/audit.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; diff --git a/apps/web/src/app/organizations/tools/import-export/org-import.component.ts b/apps/web/src/app/organizations/tools/import-export/org-import.component.ts index 27d1c6cd39e..69506b226a3 100644 --- a/apps/web/src/app/organizations/tools/import-export/org-import.component.ts +++ b/apps/web/src/app/organizations/tools/import-export/org-import.component.ts @@ -5,7 +5,7 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { ImportService } from "@bitwarden/common/abstractions/import.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; diff --git a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts index 80fe51d32d3..49ae82ab5f3 100644 --- a/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts +++ b/apps/web/src/app/organizations/tools/inactive-two-factor-report.component.ts @@ -5,7 +5,7 @@ import { ModalService } from "@bitwarden/angular/services/modal.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherView } from "@bitwarden/common/models/view/cipherView"; diff --git a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts index 98a62cd83ab..74e5ac91bb1 100644 --- a/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/reused-passwords-report.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { Cipher } from "@bitwarden/common/models/domain/cipher"; diff --git a/apps/web/src/app/organizations/tools/tools.component.ts b/apps/web/src/app/organizations/tools/tools.component.ts index 249e5cd2ca8..e50320d7c80 100644 --- a/apps/web/src/app/organizations/tools/tools.component.ts +++ b/apps/web/src/app/organizations/tools/tools.component.ts @@ -2,7 +2,7 @@ import { Component } from "@angular/core"; import { ActivatedRoute } from "@angular/router"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/models/domain/organization"; @Component({ diff --git a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts index b1e99c50fc5..dbb5e08be54 100644 --- a/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts +++ b/apps/web/src/app/organizations/tools/unsecured-websites-report.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CipherView } from "@bitwarden/common/models/view/cipherView"; diff --git a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts index 9b5d95b6372..3b8cc1490a0 100644 --- a/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts +++ b/apps/web/src/app/organizations/tools/weak-passwords-report.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { ModalService } from "@bitwarden/angular/services/modal.service"; import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; diff --git a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html index f72602ac911..4d24e66764e 100644 --- a/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html +++ b/apps/web/src/app/organizations/users/enroll-master-password-reset.component.html @@ -13,9 +13,9 @@ ngNativeValidate >
- +

{{ "reportError" | i18n }}...

diff --git a/apps/web/src/app/reports/pages/exposed-passwords-report.component.html b/apps/web/src/app/reports/pages/exposed-passwords-report.component.html index 2c5547efc7c..0fce002310b 100644 --- a/apps/web/src/app/reports/pages/exposed-passwords-report.component.html +++ b/apps/web/src/app/reports/pages/exposed-passwords-report.component.html @@ -2,9 +2,9 @@

{{ "exposedPasswordsReport" | i18n }}

{{ "exposedPasswordsReportDesc" | i18n }}

- +
{{ "noExposedPasswords" | i18n }} diff --git a/apps/web/src/app/send/add-edit.component.html b/apps/web/src/app/send/add-edit.component.html index 8d6c066bab9..dcc60a3c7af 100644 --- a/apps/web/src/app/send/add-edit.component.html +++ b/apps/web/src/app/send/add-edit.component.html @@ -9,7 +9,7 @@ autocomplete="off" >
- + diff --git a/apps/web/src/app/settings/change-password.component.html b/apps/web/src/app/settings/change-password.component.html index 6f36236a7ae..e74881db025 100644 --- a/apps/web/src/app/settings/change-password.component.html +++ b/apps/web/src/app/settings/change-password.component.html @@ -100,7 +100,7 @@ - + diff --git a/apps/web/src/app/settings/change-password.component.ts b/apps/web/src/app/settings/change-password.component.ts index 7636c6970b5..45672940f15 100644 --- a/apps/web/src/app/settings/change-password.component.ts +++ b/apps/web/src/app/settings/change-password.component.ts @@ -10,8 +10,8 @@ import { FolderService } from "@bitwarden/common/abstractions/folder/folder.serv import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; import { OrganizationApiServiceAbstraction } from "@bitwarden/common/abstractions/organization/organization-api.service.abstraction"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordGenerationService } from "@bitwarden/common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; @@ -139,7 +139,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { this.platformUtilsService.showToast( "error", this.i18nService.t("errorOccurred"), - this.i18nService.t("masterPassRequired") + this.i18nService.t("masterPasswordRequired") ); return false; } diff --git a/apps/web/src/app/settings/deauthorize-sessions.component.html b/apps/web/src/app/settings/deauthorize-sessions.component.html index ac7dc7ba02e..56e2cda578d 100644 --- a/apps/web/src/app/settings/deauthorize-sessions.component.html +++ b/apps/web/src/app/settings/deauthorize-sessions.component.html @@ -8,7 +8,7 @@ ngNativeValidate > diff --git a/apps/web/src/app/vault/share.component.ts b/apps/web/src/app/vault/share.component.ts index 018e4a6f569..6d22c0fe50d 100644 --- a/apps/web/src/app/vault/share.component.ts +++ b/apps/web/src/app/vault/share.component.ts @@ -5,7 +5,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { LogService } from "@bitwarden/common/abstractions/log.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { CollectionView } from "@bitwarden/common/models/view/collectionView"; diff --git a/apps/web/src/app/vault/vault-filter/organization-filter/organization-filter.component.html b/apps/web/src/app/vault/vault-filter/organization-filter/organization-filter.component.html index 18d7e730d3d..2977f63ed71 100644 --- a/apps/web/src/app/vault/vault-filter/organization-filter/organization-filter.component.html +++ b/apps/web/src/app/vault/vault-filter/organization-filter/organization-filter.component.html @@ -4,7 +4,11 @@
  • - @@ -42,6 +46,7 @@ class="filter-button" (click)="clearFilter()" [ngClass]="{ active: !hasActiveFilter }" + appA11yTitle="{{ 'vault' | i18n }}: {{ organizationGrouping.name | i18n }}" >  {{ organizationGrouping.name | i18n }} @@ -53,7 +58,12 @@ [ngClass]="{ active: organization.id === activeFilter.selectedOrganizationId }" > - @@ -79,7 +89,11 @@
    - @@ -107,6 +121,7 @@ class="filter-button" (click)="clearFilter()" [ngClass]="{ active: !hasActiveFilter }" + appA11yTitle="{{ 'vault' | i18n }}: {{ organizationGrouping.name | i18n }}" >  {{ organizationGrouping.name | i18n }} @@ -114,7 +129,12 @@
    • - @@ -130,6 +150,7 @@ class="filter-button" [ngClass]="{ 'disabled-organization': !organization.enabled }" (click)="applyOrganizationFilter(organization)" + appA11yTitle="{{ 'vault' | i18n }}: {{ organization.name }}" > {{ organization.name }} diff --git a/apps/web/src/app/vault/vault-filter/organization-filter/organization-options.component.ts b/apps/web/src/app/vault/vault-filter/organization-filter/organization-options.component.ts index efffd7d54a2..fb1009fa515 100644 --- a/apps/web/src/app/vault/vault-filter/organization-filter/organization-options.component.ts +++ b/apps/web/src/app/vault/vault-filter/organization-filter/organization-options.component.ts @@ -102,9 +102,7 @@ export class OrganizationOptionsComponent { } try { - this.actionPromise = this.organizationApiService.leave(org.id).then(() => { - return this.syncService.fullSync(true); - }); + this.actionPromise = this.organizationApiService.leave(org.id); await this.actionPromise; this.platformUtilsService.showToast("success", null, this.i18nService.t("leftOrganization")); await this.load(); diff --git a/apps/web/src/app/vault/vault-filter/shared/vault-filter.service.ts b/apps/web/src/app/vault/vault-filter/shared/vault-filter.service.ts index b6c2f7cfa70..d8bb48ce663 100644 --- a/apps/web/src/app/vault/vault-filter/shared/vault-filter.service.ts +++ b/apps/web/src/app/vault/vault-filter/shared/vault-filter.service.ts @@ -8,7 +8,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CollectionService } from "@bitwarden/common/abstractions/collection.service"; import { FolderService } from "@bitwarden/common/abstractions/folder/folder.service.abstraction"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/abstractions/policy/policy.service.abstraction"; import { StateService } from "@bitwarden/common/abstractions/state.service"; import { CollectionData } from "@bitwarden/common/models/data/collectionData"; diff --git a/apps/web/src/app/vault/vault.component.ts b/apps/web/src/app/vault/vault.component.ts index c9d6b590390..892a4fac8dc 100644 --- a/apps/web/src/app/vault/vault.component.ts +++ b/apps/web/src/app/vault/vault.component.ts @@ -17,7 +17,7 @@ import { CipherService } from "@bitwarden/common/abstractions/cipher.service"; import { CryptoService } from "@bitwarden/common/abstractions/crypto.service"; import { I18nService } from "@bitwarden/common/abstractions/i18n.service"; import { MessagingService } from "@bitwarden/common/abstractions/messaging.service"; -import { OrganizationService } from "@bitwarden/common/abstractions/organization.service"; +import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction"; import { PasswordRepromptService } from "@bitwarden/common/abstractions/passwordReprompt.service"; import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; import { StateService } from "@bitwarden/common/abstractions/state.service"; diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index 3ab3434cfb3..6a52acd58d7 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Toestemmings" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 2b3457e9bde..473e312b25e 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index 1bd2459880a..86ebc3a5878 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "İcazələr" }, + "managerPermissions": { + "message": "Menecer icazələri" + }, + "adminPermissions": { + "message": "Admin icazələri" + }, "accessEventLogs": { "message": "Tədbir jurnalına müraciət" }, diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 252e101dace..20a80249cc7 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -10,7 +10,7 @@ } }, "whatTypeOfItem": { - "message": "Выберыце тып элемента" + "message": "Які гэта элемент запісу?" }, "name": { "message": "Назва" @@ -65,7 +65,7 @@ "message": "Код бяспекі (CVV)" }, "identityName": { - "message": "Імя" + "message": "Імя пасведчання" }, "company": { "message": "Кампанія" @@ -137,10 +137,10 @@ "message": "Доктар" }, "expirationMonth": { - "message": "Месяц заканчэння" + "message": "Месяц завяршэння" }, "expirationYear": { - "message": "Год заканчэння" + "message": "Год завяршэння" }, "authenticatorKeyTotp": { "message": "Ключ аўтэнтыфікацыі (TOTP)" @@ -227,13 +227,13 @@ "description": "Toggling an expand/collapse state." }, "generatePassword": { - "message": "Згенерыраваць пароль" + "message": "Генерыраваць пароль" }, "checkPassword": { "message": "Праверце, ці не скампраметаваны пароль." }, "passwordExposed": { - "message": "Гэты пароль быў скампраметаваны $VALUE$ раз(-ы/-оў). Вы павінны змяніць яго.", + "message": "Гэты пароль быў скампраметаваны наступную колькасць разоў: $VALUE$. Вы павінны змяніць яго.", "placeholders": { "value": { "content": "$1", @@ -294,7 +294,7 @@ "message": "Тыпы" }, "typeLogin": { - "message": "Імя карыстальніка" + "message": "Лагін" }, "typeCard": { "message": "Картка" @@ -315,7 +315,7 @@ "message": "Пасведчанні" }, "typeSecureNotePlural": { - "message": "Бяспечныя нататкі" + "message": "Абароненыя нататкі" }, "folders": { "message": "Папкі" @@ -369,10 +369,10 @@ "message": "Дадаць элемент" }, "editItem": { - "message": "Рэдагаванне элемента" + "message": "Рэдагаваць элемент" }, "viewItem": { - "message": "Прагляд элемента" + "message": "Прагледзець элемент" }, "ex": { "message": "напр.", @@ -388,7 +388,7 @@ "message": "Перамясціць у арганізацыю" }, "valueCopied": { - "message": "$VALUE$ скапіяваны(-а)", + "message": "$VALUE$ скапіяваны", "description": "Value has been copied to the clipboard.", "placeholders": { "value": { @@ -398,27 +398,27 @@ } }, "copyValue": { - "message": "Капіяваць значэнне", + "message": "Скапіяваць значэнне", "description": "Copy value to clipboard" }, "copyPassword": { - "message": "Капіяваць пароль", + "message": "Скапіяваць пароль", "description": "Copy password to clipboard" }, "copyUsername": { - "message": "Капіяваць імя карыстальніка", + "message": "Скапіяваць імя карыстальніка", "description": "Copy username to clipboard" }, "copyNumber": { - "message": "Капіяваць нумар", + "message": "Скапіяваць нумар", "description": "Copy credit card number" }, "copySecurityCode": { - "message": "Капіяваць код бяспекі", + "message": "Скапіяваць код бяспекі", "description": "Copy credit card security code (CVV)" }, "copyUri": { - "message": "Капіяваць URI", + "message": "Скапіяваць URI", "description": "Copy URI to clipboard" }, "me": { @@ -549,7 +549,7 @@ "message": "Вы выйшлі" }, "loginExpired": { - "message": "Скончыўся тэрмін дзеяння вашага сеансу." + "message": "Тэрмін дзеяння вашага сеансу завяршыўся." }, "logOutConfirmation": { "message": "Вы ўпэўнены, што хочаце выйсці?" @@ -600,7 +600,7 @@ "message": "Асноўныя паролі немагчыма будзе аднавіць, калі вы іх забудзеце!" }, "masterPassHintDesc": { - "message": "Падказка да асноўнага пароля можа дапамагчы вам яго ўспомніць, калі вы яго забылі." + "message": "Падказка да асноўнага пароля можа дапамагчы вам успомніць яго, калі вы яго забылі." }, "reTypeMasterPass": { "message": "Увядзіце асноўны пароль паўторна" @@ -621,7 +621,7 @@ "message": "Увядзіце адрас электроннай пошты ўліковага запісу для атрымання падказкі да асноўнага пароля." }, "getMasterPasswordHint": { - "message": "Атрымаць падказку для асноўнага пароля" + "message": "Атрымаць падказку да асноўнага пароля" }, "emailRequired": { "message": "Патрабуецца адрас электроннай пошты." @@ -648,7 +648,7 @@ "message": "Уліковы запіс паспяхова створаны." }, "masterPassSent": { - "message": "Мы адправілі вам на электронную пошту падказку для асноўнага пароля." + "message": "Мы адправілі вам на электронную пошту падказку да асноўнага пароля." }, "unexpectedError": { "message": "Адбылася нечаканая памылка." @@ -663,7 +663,7 @@ "message": "Разблакіраваць" }, "loggedInAsEmailOn": { - "message": "Вы ўвайшлі як $HOSTNAME$ у $EMAIL$.", + "message": "Вы ўвайшлі як $EMAIL$ у $HOSTNAME$.", "placeholders": { "email": { "content": "$1", @@ -718,7 +718,7 @@ "message": "Увядзіце 6 лічбаў праверачнага кода з вашай праграмы аўтэнтыфікацыі." }, "enterVerificationCodeEmail": { - "message": "Увядзіце 6 лічбаў кода праверкі, які быў адпраўлены на $EMAIL$.", + "message": "Увядзіце 6 лічбаў праверачнага кода, які быў адпраўлены на $EMAIL$.", "placeholders": { "email": { "content": "$1", @@ -782,11 +782,11 @@ "message": "Выкарыстоўвайце YubiKey для доступу да вашага ўліковага запісу. Працуе з прыладамі YubiKey серый 4, 5 і NEO." }, "duoDesc": { - "message": "Пацвярдзіце з дапамогай Duo Security, выкарыстоўваючы праграму Duo Mobile, SMS, тэлефонны выклік або ключ бяспекі.", + "message": "Праверка з дапамогай Duo Security, выкарыстоўваючы праграму Duo Mobile, SMS, тэлефонны выклік або ключ бяспекі U2F.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "duoOrganizationDesc": { - "message": "Пацвярдзіце з дапамогай Duo Security для вашай арганізацыі, выкарыстоўваючы праграму Duo Mobile, SMS, тэлефонны выклік або ключ бяспекі.", + "message": "Праверка з дапамогай Duo Security для вашай арганізацыі, выкарыстоўваючы праграму Duo Mobile, SMS, тэлефонны выклік або ключ бяспекі U2F.", "description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated." }, "u2fDesc": { @@ -829,7 +829,7 @@ "message": "Рэдагуйце калекцыі, з якімі гэты элемент знаходзіцца ў агульным доступе. Толькі карыстальнікі арганізацыі з доступам да гэтых калекцый змогуць бачыць гэты элемент." }, "deleteSelectedItemsDesc": { - "message": "Вы выбралі наступную колькасць запісаў для выдалення: $COUNT$. Вы ўпэўнены, што хочаце выдаліць гэтыя элементы?", + "message": "Вы выбралі наступную колькасць элементаў для выдалення: $COUNT$ шт. Вы ўпэўнены, што хочаце выдаліць іх?", "placeholders": { "count": { "content": "$1", @@ -838,7 +838,7 @@ } }, "moveSelectedItemsDesc": { - "message": "Выберыце папку ў якую вы хочаце перамясціць выбраныя элементы (колькасць: $COUNT$).", + "message": "Выберыце папку ў якую вы хочаце перамясціць выбраныя элементы (колькасць: $COUNT$ шт.).", "placeholders": { "count": { "content": "$1", @@ -847,7 +847,7 @@ } }, "moveSelectedItemsCountDesc": { - "message": "Вы выбралі наступную колькасць элементаў: $COUNT$. Наступная колькасць колькасць будзе перамешчана: $MOVEABLE_COUNT$. Застануцца без перамяшчэння: $NONMOVEABLE_COUNT$.", + "message": "Вы выбралі наступную колькасць элементаў: $COUNT$ шт. З іх будуць перамешчаны ў арганізацыю: $MOVEABLE_COUNT$ шт. Не перамешчанымі застануцца: $NONMOVEABLE_COUNT$ шт.", "placeholders": { "count": { "content": "$1", @@ -867,7 +867,7 @@ "message": "Праверачны код (TOTP)" }, "copyVerificationCode": { - "message": "Капіяваць праверачны код" + "message": "Скапіяваць праверачны код" }, "warning": { "message": "Папярэджанне" @@ -876,10 +876,10 @@ "message": "Пацвердзіць экспартаванне сховішча" }, "exportWarningDesc": { - "message": "Файл, які экспартуецца ўтрымлівае даныя вашага сховішча ў незашыфраваным фармаце. Яго не варта захоўваць або адпраўляць па неабароненых каналах (напрыклад, па электроннай пошце). Выдаліце яго адразу пасля выкарыстання." + "message": "Пры экспартаванні файл утрымлівае даныя вашага сховішча ў незашыфраваным фармаце. Яго не варта захоўваць або адпраўляць па неабароненых каналах (напрыклад, па электроннай пошце). Выдаліце яго адразу пасля выкарыстання." }, "encExportKeyWarningDesc": { - "message": "Пры экспарце даныя шыфруюцца з дапамогай ключа шыфравання ўліковага запісу. Калі вы калі-небудзь зменіце ключ шыфравання ўліковага запісу, вам неабходна будзе экспартаваць даныя паўторна, паколькі вы не зможаце расшыфраваць гэты файл экспартавання." + "message": "Пры экспартаванні даныя шыфруюцца з дапамогай ключа шыфравання ўліковага запісу. Калі вы калі-небудзь зменіце ключ шыфравання ўліковага запісу, вам неабходна будзе экспартаваць даныя паўторна, паколькі вы не зможаце расшыфраваць гэты файл экспартавання." }, "encExportAccountWarningDesc": { "message": "Ключы шыфравання з'яўляюцца ўнікальнымі для кожнага ўліковага запісу Bitwarden, таму нельга імпартаваць зашыфраванае сховішча ў іншы ўліковы запіс." @@ -930,7 +930,7 @@ "message": "“Пароль файла” і “Пацвярджэнне пароля файла“ не супадаюць." }, "confirmVaultImport": { - "message": "Пацвердзіць імпартаванне сімвала" + "message": "Пацвердзіць імпартаванне сховішча" }, "confirmVaultImportDesc": { "message": "Гэты файл абаронены паролем. Калі ласка, увядзіце пароль для імпартавання даных." @@ -955,7 +955,7 @@ "message": "Пазбягаць неадназначных сімвалаў" }, "regeneratePassword": { - "message": "Згенерыраваць новы пароль" + "message": "Паўторна генерыраваць пароль" }, "length": { "message": "Даўжыня" @@ -1013,7 +1013,7 @@ "message": "Код" }, "changeEmailDesc": { - "message": "Мы адправілі праверачны код на $EMAIL$. Праверце сваю пошту на наяўнасць гэтага кода і ўвядзіце яго ніжэй, каб завяршыць змяненне адраса электроннай пошты.", + "message": "На ваш паштовы адрас $EMAIL$ адпраўлены ліст з праверачным кодам. Праверце сваю пошту на наяўнасць гэтага кода і ўвядзіце яго ніжэй, каб завяршыць змяненне адраса электроннай пошты.", "placeholders": { "email": { "content": "$1", @@ -1028,10 +1028,10 @@ "message": "Электронная пошта зменена" }, "logBackIn": { - "message": "Калі ласка, увайдзіце зноў." + "message": "Калі ласка, увайдзіце паўторна." }, "logBackInOthersToo": { - "message": "Калі ласка, увайдзіце паўторна. Калі вы выкарыстоўваеце іншыя праграмы Bitwarden, выйдзіце з іх, а потым увайдзіце зноў." + "message": "Калі ласка, увайдзіце паўторна. Калі вы выкарыстоўваеце іншыя праграмы Bitwarden, выйдзіце з іх, а потым увайдзіце яшчэ раз." }, "changeMasterPassword": { "message": "Змяніць асноўны пароль" @@ -1058,7 +1058,7 @@ "message": "Ітэрацыя KDF" }, "kdfIterationsDesc": { - "message": "Высокае значэнне ітэрацыі KDF дапаможа абараніць галоўны пароль ад атакі поўным пераборам. Мы рэкамендуем значэнне $VALUE$ або вышэй.", + "message": "Высокае значэнне ітэрацыі KDF дапаможа абараніць асноўны пароль ад атакі поўным пераборам. Мы рэкамендуем значэнне $VALUE$ або вышэй.", "placeholders": { "value": { "content": "$1", @@ -1067,7 +1067,7 @@ } }, "kdfIterationsWarning": { - "message": "Занадта вялікае значэнне ітэрацый KDF можа істотна запаволіць уваход (і разблакіроўку) на прыладах з састарэлымі працэсарамі. Мы рэкамендуем паслядоўна павялічваць значэнне з крокам $INCREMENT$ і правяраць вынік на ўсіх вашых прыладах.", + "message": "Занадта вялікае значэнне ітэрацый KDF можа істотна запаволіць уваход (і разблакіроўку) на прыладах, якія маюць састарэлы працэсар. Мы рэкамендуем паслядоўна павялічваць значэнне з крокам $INCREMENT$ і правяраць вынік на ўсіх вашых прыладах.", "placeholders": { "increment": { "content": "$1", @@ -1091,13 +1091,13 @@ "message": "Скасаваць аўтарызацыю сеанса" }, "deauthorizeSessionsDesc": { - "message": "Непакоіцеся пра тое, што ўваход у ваш уліковы запіс выкананы іншай прыладзе? Перайдзіце ніжэй, каб закрыць сеансы на ўсіх камп'ютарах або іншых прыладах, якія вы раней выкарыстоўвалі. Гэты крок бяспекі рэкамендаваны, калі вы раней выкарыстоўвалі агульнадаступны камп'ютар або выпадкова захавалі пароль на прыладзе, якая не належыць вам. Гэта дзеянне таксама ачысціць усе папярэднія сеансы двухэтапнага ўваходу." + "message": "Непакоіцеся, што ўваход у ваш уліковы запіс можа быць выкананы на іншай прыладзе? Перайдзіце ніжэй, каб скасаваць аўтарызацыю на ўсіх камп'ютарах або іншых прыладах, якія вы раней выкарыстоўвалі. Гэты крок бяспекі рэкамендаваны, калі вы раней выкарыстоўвалі агульнадаступны камп'ютар або выпадкова захавалі пароль на прыладзе, якая не належыць вам. Гэта дзеянне таксама ачысціць усе папярэднія сеансы двухэтапнага ўваходу." }, "deauthorizeSessionsWarning": { "message": "Працягваючы, вы таксама выйдзіце з бягучага сеанса і вам неабходна будзе ўвайсці паўторна. Вы таксама атрымаеце паўторны запыт двухэтапнага ўваходу, калі гэта функцыя ў вас уключана. Сеансы на іншых прыладах могуць заставацца актыўнымі на працягу адной гадзіны." }, "sessionsDeauthorized": { - "message": "Усе сеансы адкліканы" + "message": "Аўтарызацыя ўсіх сеансаў скасавана" }, "purgeVault": { "message": "Ачысціць сховішча" @@ -1148,7 +1148,7 @@ "message": "Памылка імпартавання" }, "importErrorDesc": { - "message": "Адбылася праблема з данымі, якія вы спрабуеце імпартаваць. Калі ласка, выпраўце памылкі, якія пералічаны ў вашым зыходным файле і паспрабуйце яшчэ раз." + "message": "Адбылася праблема з данымі, якія вы спрабуеце імпартаваць. Калі ласка, выпраўце памылкі, якія пералічаны ніжэй у вашым зыходным файле і паспрабуйце яшчэ раз." }, "importSuccess": { "message": "Даныя былі паспяхова імпартаваны ў ваша сховішча." @@ -1197,7 +1197,7 @@ "message": "Параметры" }, "preferencesDesc": { - "message": "Дастасуйце працу з вэб-сховішчам." + "message": "Дапасуйце працу з вэб-сховішчам." }, "preferencesUpdated": { "message": "Параметры абноўлены" @@ -1212,7 +1212,7 @@ "message": "Паказваць значкі вэб-сайтаў" }, "faviconDesc": { - "message": "Паказваць распазнавальны відарыс побач з кожным з кожным лагінам." + "message": "Паказваць распазнавальны відарыс побач з кожным лагінам." }, "enableGravatars": { "message": "Паказваць Gravatars", @@ -1235,7 +1235,7 @@ "message": "Правілы дамена" }, "domainRulesDesc": { - "message": "Калі ў вас ёсць аднолькавы лагін на некалькіх розных даменах вэб-сайта, то вы можаце пазначыць вэб-сайт як \"эквівалентны\". \"Глабальныя\" - гэта дамены, які створаны для вас Bitwarden." + "message": "Калі ў вас ёсць аднолькавы лагін на некалькіх розных даменах вэб-сайта, вы можаце пазначыць вэб-сайт як \"эквівалентны\". \"Глабальныя\" - гэта дамены, якія стварыў для вас Bitwarden." }, "globalEqDomains": { "message": "Глабальныя эквівалентныя дамены" @@ -1280,7 +1280,7 @@ "message": "Патрабаваць двухэтапны ўваход для карыстальнікаў вашай арганізацыі, які сканфігураваны на ўзроўні арганізацыі." }, "twoStepLoginRecoveryWarning": { - "message": "Уключэнне двухэтапнага ўваходу можа цалкам заблакіраваць доступ да ўліковага запісу Bitwarden. Код аднаўлення дае магчымасць атрымаць доступ да вашага ўліковага запісу ў выпадку, калі вы не можаце скарыстацца звычайным спосабам пастаўшчыка двухэтапнага ўваходу (напрыклад, вы згубілі сваю прыладу). Падтрымка Bitwarden не зможа вам дапамагчы, калі вы згубіце доступ да свайго ўліковага запіс. Мы рэкамендуем вам запісаць або раздрукаваць код аднаўлення і захоўваць яго ў надзейным месцы." + "message": "Уключэнне двухэтапнага ўваходу можа цалкам заблакіраваць доступ да ўліковага запісу Bitwarden. Код аднаўлення дае магчымасць атрымаць доступ да вашага ўліковага запісу ў выпадку, калі вы не можаце скарыстацца звычайным спосабам пастаўшчыка двухэтапнага ўваходу (напрыклад, вы згубілі сваю прыладу). Падтрымка Bitwarden не зможа вам дапамагчы, калі вы згубіце доступ да свайго ўліковага запісу. Мы рэкамендуем вам запісаць або раздрукаваць код аднаўлення і захоўваць яго ў надзейным месцы." }, "viewRecoveryCode": { "message": "Паглядзець код аднаўлення" @@ -1299,26 +1299,26 @@ "message": "Аднавіць доступ" }, "premium": { - "message": "Прэміяльны статус", + "message": "Прэміум", "description": "Premium Membership" }, "premiumMembership": { - "message": "Прэміяльны статус" + "message": "Прэміяльны ўдзельнік" }, "premiumRequired": { - "message": "Патрабуецца прэміяльны статус" + "message": "Патрабуецца прэміум" }, "premiumRequiredDesc": { "message": "Для выкарыстання гэтай функцыі патрабуецца прэміяльны статус." }, "youHavePremiumAccess": { - "message": "У вас прэміяльын статус" + "message": "У вас прэміяльны доступ" }, "alreadyPremiumFromOrg": { "message": "У вас ужо ёсць доступ да прэміяльных функцый, таму што вы з'яўляецеся ўдзельнікам арганізацыі, якая іх мае." }, "manage": { - "message": "Кіраваць" + "message": "Кіраванне" }, "disable": { "message": "Адключыць" @@ -1330,7 +1330,7 @@ "message": "Гэты пастаўшчык двухэтапнага ўваходу ўключаны для вашага ўліковага запісу." }, "twoStepLoginAuthDesc": { - "message": "Увядзіце галоўны пароль для змянення наладаў двухэтапнага ўваходу." + "message": "Увядзіце асноўны пароль для змянення наладаў двухэтапнага ўваходу." }, "twoStepAuthenticatorDesc": { "message": "Прытрымлівайцеся гэтых крокаў, каб прызначыць двухэтапны ўваход з дапамогай праграмы аўтэнтыфікацыі:" @@ -1354,7 +1354,7 @@ "message": "Гэтыя праграмы з'яўляюцца рэкамендаванымі. Звярніце ўвагу, што іншыя праграмы таксама будуць працаваць." }, "twoStepAuthenticatorScanCode": { - "message": "Скануйце гэты QR-код з дапамогай праграмы аўтэнтыфікацыі" + "message": "Адскануйце гэты QR-код з дапамогай праграмы аўтэнтыфікацыі" }, "key": { "message": "Ключ" @@ -1369,7 +1369,7 @@ "message": "Вы ўпэўнены, што хочаце адключыць гэтага пастаўшчыка двухэтапнага ўваходу?" }, "twoStepDisabled": { - "message": "Пастаўшчык двухэтапнага ўваходу выключаны." + "message": "Пастаўшчык двухэтапнага ўваходу адключаны." }, "twoFactorYubikeyAdd": { "message": "Дадаць новы YubiKey у ваш уліковы запіс" @@ -1387,13 +1387,13 @@ "message": "Захаваць форму." }, "twoFactorYubikeyWarning": { - "message": "З-за абмежаванняў платформы, YubiKey нельга выкарыстоўваць ва ўсіх праграмах Bitwarden. Калі YubiKey немагчыма выкарыстоўваць, вы павінны актываваць пастаўшчыка двухэтапнага ўваходу для атрымання доступу да свайго ўліковага запісу. Платформы, якія падтрымліваюцца:" + "message": "У сувязі з абмежаваннямі платформы, YubiKey нельга выкарыстоўваць ва ўсіх праграмах Bitwarden. Калі YubiKey немагчыма выкарыстоўваць, вы павінны актываваць пастаўшчыка двухэтапнага ўваходу для атрымання доступу да свайго ўліковага запісу. Платформы, якія падтрымліваюцца:" }, "twoFactorYubikeySupportUsb": { "message": "Вэб-сховішча, праграма для камп'ютара, інтэрфейс каманднага радка (CLI) і ўсе пашырэнні браўзера на прыладах з партом USB, якія сумяшчальныя з YubiKey." }, "twoFactorYubikeySupportMobile": { - "message": "Мабільныя праграмы на прыладах з NFC або портам USB, якія сумяшчальныя з YubiKey." + "message": "Мабільныя праграмы на прыладах з NFC або партом USB, якія сумяшчальны з YubiKey." }, "yubikeyX": { "message": "YubiKey $INDEX$", @@ -1489,13 +1489,13 @@ "message": "Захаваць форму." }, "twoFactorU2fWarning": { - "message": "З-за абмежаванняў платформы, FIDO U2F можна выкарыстоўваць не ва ўсіх праграмах Bitwarden. Калі FIDO U2F не атрымліваецца выкарыстоўваць, то вы павінны ўключыць другога пастаўшчыка двухэтапнага ўваходу, каб атрымаць доступ да вашага ўліковага запісу. Платформы, якія падтрымліваюцца:" + "message": "У сувязі з абмежаваннямі платформы, FIDO U2F можна выкарыстоўваць не ва ўсіх праграмах Bitwarden. Калі FIDO U2F не атрымліваецца выкарыстоўваць, то вы павінны ўключыць другога пастаўшчыка двухэтапнага ўваходу, каб атрымаць доступ да вашага ўліковага запісу. Платформы, якія падтрымліваюцца:" }, "twoFactorU2fSupportWeb": { "message": "Вэб-сховішча і пашырэнні браўзера на камп'ютары/ноўтбуку з браўзерам, які падтрымлівае U2F (Chrome, Opera, Vivaldi або Firefox з уключаным FIDO U2F)." }, "twoFactorU2fWaiting": { - "message": "Чаканне націску кнопкі на ключы бяспекі" + "message": "Чаканне націску кнопкі на вашым ключы бяспекі" }, "twoFactorU2fClickSave": { "message": "Націсніце кнопку \"Захаваць\" ніжэй, каб уключыць гэты ключ бяспекі для двухэтапнага ўваходу." @@ -1504,7 +1504,7 @@ "message": "Праблема чытання ключа бяспекі. Паспрабуйце яшчэ раз." }, "twoFactorWebAuthnWarning": { - "message": "З-за абмежавання платформы, WebAuthn немагчыма выкарыстоўваць ва ўсіх праграмах Bitwarden. Вам неабходна актываваць іншага пастаўшчыка двухэтапнага ўваходу, каб вы маглі атрымаць доступ да свайго ўліковага запісу, калі немагчыма скарыстацца WebAuthn. Платформы, які падтрымліваюцца:" + "message": "У сувязі з абмежаваннямі платформы, WebAuthn немагчыма выкарыстоўваць ва ўсіх праграмах Bitwarden. Вам неабходна актываваць іншага пастаўшчыка двухэтапнага ўваходу, каб вы маглі атрымаць доступ да свайго ўліковага запісу, калі немагчыма скарыстацца WebAuthn. Платформы, які падтрымліваюцца:" }, "twoFactorWebAuthnSupportWeb": { "message": "Вэб-сховішча і пашырэнні браўзера на камп'ютары/ноўтбуку з браўзерам, які падтрымлівае WebAuthn (Chrome, Opera, Vivaldi або Firefox з уключаным FIDO U2F)." @@ -1523,7 +1523,7 @@ "message": "Справаздачы" }, "reportsDesc": { - "message": "Выявіце і выпраўце недахопы ў бяспецы вашых уліковых запісах, націснуўшы на справаздачы ніжэй.", + "message": "Выявіце і выпраўце недахопы ў бяспецы вашых уліковых запісаў, націснуўшы на справаздачы ніжэй.", "description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault." }, "unsecuredWebsitesReport": { @@ -1536,7 +1536,7 @@ "message": "Знойдзены неабароненыя вэб-сайты" }, "unsecuredWebsitesFoundDesc": { - "message": "Мы знайшлі наступную колькасць з неабароненымі URI у вашым сховішчы: $COUNT$. Вам неабходна змяніць іх схему URI на https://, калі вэб-сайт дазваляе гэта зрабіць.", + "message": "У сховішчы ёсць элементы ($COUNT$ шт.) з неабароненымі URI. Вам неабходна змяніць іх схему URI на https://, калі вэб-сайт дазваляе гэта зрабіць.", "placeholders": { "count": { "content": "$1", @@ -1557,7 +1557,7 @@ "message": "Знойдзены лагіны без 2ФА" }, "inactive2faFoundDesc": { - "message": "У сховішчы выяўлены вэб-сайты ($COUNT$ шт.), якія могуць быць не наладжаны для двухэтапнай аўтэнтыфікацыі (згодна з 2fa.directory). Для дадатковай абароны гэтых уліковых запісаў уключыце двухэтапную аўтэнтыфікацыю.", + "message": "У сховішчы ёсць вэб-сайты ($COUNT$ шт.), якія могуць быць не наладжаны для двухэтапнай аўтэнтыфікацыі (згодна з 2fa.directory). Для дадатковай абароны гэтых уліковых запісаў уключыце двухэтапную аўтэнтыфікацыю.", "placeholders": { "count": { "content": "$1", @@ -1605,16 +1605,16 @@ } }, "weakPasswordsReport": { - "message": "Слабыя паролі" + "message": "Ненадзейныя паролі" }, "weakPasswordsReportDesc": { - "message": "Слабыя паролі могуць быць лёгка падабраныя зламыснікамі. Змяніце гэтыя паролі на надзейныя з дапамогай генератара пароляў." + "message": "Ненадзейныя паролі могуць быць лёгка падабраныя зламыснікамі. Замяніце гэтыя паролі на надзейныя з дапамогай генератара пароляў." }, "weakPasswordsFound": { - "message": "Знойдзены слабыя паролі" + "message": "Знойдзены ненадзейныя паролі" }, "weakPasswordsFoundDesc": { - "message": "У сховішчы ёсць элементы ($COUNT$ шт.) з ненадзейнымі паролямі. Вам неабходна змяніць іх на больш складаныя.", + "message": "У сховішчы ёсць элементы ($COUNT$ шт.) з ненадзейнымі паролямі. Вам неабходна замяніць іх на больш надзейныя.", "placeholders": { "count": { "content": "$1", @@ -1635,7 +1635,7 @@ "message": "Знойдзены паўторныя паролі" }, "reusedPasswordsFoundDesc": { - "message": "У сховішчы знойдзены паўторныя паролі ($COUNT$ шт.). Змяніце іх на ўнікальныя.", + "message": "У сховішчы ёсць паўторныя паролі ($COUNT$ шт.). Вам неабходна згенерыраваць унікальныя паролі і замяніць іх.", "placeholders": { "count": { "content": "$1", @@ -1668,7 +1668,7 @@ "message": "Праверыць па базах уцечак" }, "breachUsernameNotFound": { - "message": "$USERNAME$ не знойдзены ў вядомых базах уцечак.", + "message": "$USERNAME$ не знойдзены ў вядомых уцечках даных.", "placeholders": { "username": { "content": "$1", @@ -1743,7 +1743,7 @@ "message": "Дададзеныя крэдыты з'явяцца на вашым рахунку пасля поўнай апрацоўкі плацяжу. Некаторыя спосабы аплаты адбываюцца з затрымкай і могуць заняць больш часу, чым астатнія." }, "makeSureEnoughCredit": { - "message": "Пераканайцеся, што на вашым рахунку дастаткова крэдытаў для ажыццяўлення гэтай пакупкі. Калі сродкаў на вашым рахунку не хапае, то для кампенсацыі нястачы будзе выкарыстаны ваш прадвызначаны метад аплаты. Вы можаце дадаць крэдыты на свой рахунак на старонцы аплаты." + "message": "Пераканайцеся, што на вашым рахунку дастаткова крэдытаў для ажыццяўлення гэтай пакупкі. Калі сродкаў на вашым рахунку не хапае, то для кампенсацыі нястачы будзе выкарыстаны ваш прадвызначаны спосаб аплаты. Вы можаце дадаць крэдыты на свой рахунак на старонцы аплаты." }, "creditAppliedDesc": { "message": "Крэдыт вашага рахунку можа выкарыстоўвацца для здзяйснення купляў. Любыя даступныя крэдыты будуць аўтаматычна ўжыты для рахункаў, якія згенерыраваны для гэтага ўліковага запісу." @@ -1753,7 +1753,7 @@ "description": "Another way of saying \"Get a premium membership\"" }, "premiumUpdated": { - "message": "Вы абнавіліся да прэміяльнага статусу." + "message": "Вы абнавіліся да прэміяльнай версіі." }, "premiumUpgradeUnlockFeatures": { "message": "Абнавіце свой уліковы запіс да платнай версіі і разблакіруйце некаторыя цудоўныя дадатковыя функцыі." @@ -1780,7 +1780,7 @@ "message": "Усе будучыя функцыі прэміяльнага статусу. Іх будзе больш!" }, "premiumPrice": { - "message": "Усяго толькі за $PRICE$ на год!", + "message": "Усяго за $PRICE$ у год!", "placeholders": { "price": { "content": "$1", @@ -1850,10 +1850,10 @@ "description": "Short abbreviation for 'month'" }, "paymentChargedAnnually": { - "message": "У вас адразу будзе спагнана плата згодна з абраным спосабам плацяжу, а інтэрвал такіх плацяжоў будзе ажыццяўляцца штогод. Вы можаце скасаваць іх у любы момант." + "message": "У вас адразу будзе спагнана плата згодна з выбраным спосабам аплаты, а інтэрвал такіх плацяжоў будзе ажыццяўляцца кожны год. Вы можаце скасаваць іх у любы момант." }, "paymentCharged": { - "message": "У вас адразу будзе спагнана плата згодна з абраным спосабам плацяжу, а інтэрвал такіх плацяжоў будзе ажыццяўляцца $INTERVAL$. Вы можаце скасаваць яго ў любы момант.", + "message": "У вас адразу будзе спагнана плата згодна з выбраным спосабам аплаты, а інтэрвал такіх плацяжоў будзе ажыццяўляцца кожны $INTERVAL$. Вы можаце скасаваць яго ў любы момант.", "placeholders": { "interval": { "content": "$1", @@ -1862,7 +1862,7 @@ } }, "paymentChargedWithTrial": { - "message": "У ваш тарыфны план уключаны выпрабавальны перыяд на 7 дзён. У вас не будзе спагнана плата згодна з абраным спосабам плацяжу пакуль выпрабавальны перыяд не скончыцца. Вы можаце скасаваць яго ў любы момант." + "message": "У ваш тарыфны план уключаны выпрабавальны перыяд на 7 дзён. У вас не будзе спагнана плата згодна з выбраным спосабам аплаты пакуль не завяршыцца выпрабавальны перыяд. Вы можаце скасаваць яго ў любы момант." }, "paymentInformation": { "message": "Плацежная інфармацыя" @@ -1871,7 +1871,7 @@ "message": "Плацежная інфармацыя" }, "billingTrialSubLabel": { - "message": "У вас не будзе спаганяцца плата абраным метадам плацяжу на працягу 7 дзён выпрабавальнага перыяду." + "message": "У вас не будзе спаганяцца плата згодна з выбраным спосабам аплаты на працягу 7 дзён выпрабавальнага перыяду." }, "creditCard": { "message": "Крэдытная картка" @@ -1928,7 +1928,7 @@ "message": "Ліцэнзія абноўлена" }, "manageSubscription": { - "message": "Кіраваць падпіскай" + "message": "Кіраванне падпіскай" }, "storage": { "message": "Сховішча" @@ -1956,7 +1956,7 @@ "message": "Спосаб аплаты" }, "noPaymentMethod": { - "message": "Файл не змяшчае метаду аплаты." + "message": "Файл не змяшчае спосабу аплаты." }, "addPaymentMethod": { "message": "Дадаць спосаб аплаты" @@ -1986,7 +1986,7 @@ "message": "Няма трансакцый." }, "chargeNoun": { - "message": "Спісанне", + "message": "Спагнанне", "description": "Noun. A charge from a payment method." }, "refundNoun": { @@ -2003,13 +2003,13 @@ } }, "gbStorageAdd": { - "message": "ГБ сховішча для дадавання" + "message": "ГБ сховішча для дабаўлення" }, "gbStorageRemove": { "message": "ГБ сховішча для выдалення" }, "storageAddNote": { - "message": "Дадаванне сховішча прывядзе да карэкціроўкі ў вашым выніковым рахунку і адразу будзе спагнана аплата згодна з азначаным метадам. Першы плацеж будзе прапарцыйны астачы бягучага плацежнага перыяду." + "message": "Дабаўленне сховішча прывядзе да карэкціроўкі ў вашым выніковым рахунку і адразу будзе спагнаны плацеж згодна з азначаным у файле спосабам аплаты. Першы плацеж будзе прапарцыйны астачы бягучага плацежнага перыяду." }, "storageRemoveNote": { "message": "Выдаленне сховішча прывядзе да карэкціроўкі вашага выніковага рахунку, які будзе прапарцыйна раздзелены ў выглядзе крэдытаў за наступны плацежны перыяд." @@ -2030,7 +2030,7 @@ "message": "Спосаб аплаты абноўлены." }, "purchasePremium": { - "message": "Купіць прэміяльны статус" + "message": "Купіць прэміум" }, "licenseFile": { "message": "Файл ліцэнзіі" @@ -2054,7 +2054,7 @@ "message": "Электронная пошта вашага ўліковага запісу павінна быць пацверджана." }, "newOrganizationDesc": { - "message": "Арганізацыі дазваляюць дзяліцца элементамі вашага сховішча з іншымі, а таксама кіраваць звязанымі карыстальнікамі для вызначанага аб'екта. Гэта можа быць сям'я, невялікая каманда або вялікая кампанія." + "message": "Арганізацыі дазваляюць абагуляць элементы вашага сховішча з іншымі, а таксама кіраваць звязанымі карыстальнікамі для вызначанага аб'екта. Гэта можа быць сям'я, невялікая каманда або вялікая кампанія." }, "generalInformation": { "message": "Агульная інфармацыя" @@ -2066,7 +2066,7 @@ "message": "Гэты ўліковы запіс належыць кампаніі." }, "billingEmail": { - "message": "Адрас пошты для разлікаў" + "message": "Адрас пошты для аплаты" }, "businessName": { "message": "Назва кампаніі" @@ -2084,10 +2084,10 @@ "message": "Дадатковыя месцы карыстальнікаў" }, "userSeatsDesc": { - "message": "# карыстальніцкіх ліцэнзій" + "message": "# карыстальніцкіх месцаў" }, "userSeatsAdditionalDesc": { - "message": "Ваш тарыфны план мае наступную колькасць карыстальніцкіх ліцэнзій: $BASE_SEATS$. Вы можаце дадаць дадатковую колькасць карыстальнікаў па кошце $SEAT_PRICE$ за карыстальніка ў месяц.", + "message": "Ваш тарыфны план мае наступную колькасць карыстальніцкіх месцаў: $BASE_SEATS$ шт. Вы можаце дадаць дадатковую колькасць карыстальнікаў па кошце $SEAT_PRICE$ за карыстальніка ў месяц.", "placeholders": { "base_seats": { "content": "$1", @@ -2100,7 +2100,7 @@ } }, "userSeatsHowManyDesc": { - "message": "Колькі ліцэнзій вам неабходна? Пры неабходнасці, вы заўсёды можаце дакупіць дадатковыя ліцэнзіі." + "message": "Колькі месцаў вам неабходна? Пры неабходнасці, вы заўсёды можаце дакупіць дадатковыя месцы." }, "planNameFree": { "message": "Бясплатна", @@ -2176,7 +2176,7 @@ } }, "addShareLimitedUsers": { - "message": "Дабаўленне і абагульненне з $COUNT$ карыстальнікамі", + "message": "Дабаўленне і абагуленне з $COUNT$ карыстальнікамі", "placeholders": { "count": { "content": "$1", @@ -2203,7 +2203,7 @@ "message": "Лакальны хостынг (неабавязкова)" }, "usersGetPremium": { - "message": "Карыстальнікі атрымліваюць доступ да прэміяльных функцый" + "message": "Карыстальнікі атрымаюць доступ да прэміяльных функцый" }, "controlAccessWithGroups": { "message": "Кантроль доступу карыстальнікаў з дапамогай груп" @@ -2257,7 +2257,7 @@ "message": "Штогадова" }, "annual": { - "message": "Штогадова" + "message": "Штогадовы" }, "basePrice": { "message": "Базавы кошт" @@ -2272,10 +2272,10 @@ "message": "Ваша арганізацыя была абноўлена." }, "leave": { - "message": "Пакінуць" + "message": "Выйсці" }, "leaveOrganizationConfirmation": { - "message": "Вы ўпэўнены, што хочаце пакінуць гэту арганізацыю?" + "message": "Вы ўпэўнены, што хочаце выйсці з гэтай арганізацыі?" }, "leftOrganization": { "message": "Вы пакінулі арганізацыю." @@ -2284,7 +2284,7 @@ "message": "Прадвызначаная калекцыя" }, "getHelp": { - "message": "Атрымаць дапамогу" + "message": "Атрымаць даведку" }, "getApps": { "message": "Атрымаць праграмы" @@ -2332,13 +2332,13 @@ "message": "Пасля таго, як удзельнік адкліканы, ён больш не зможа атрымаць доступ да даных арганізацыі. Для хуткага аднаўлення доступу ўдзельніка, перайдзіце ва ўкладку \"Адкліканыя\"." }, "removeUserConfirmationKeyConnector": { - "message": "Увага! Гэтаму карыстальніку патрабуецца Key Connector для таго, каб кіраваць шыфраваннем. Выдаленне гэтага карыстальніка з вашай арганізацыі канчаткова адключыць яго ўліковы запіс. Гэта дзеянне нельга будзе адрабіць. Вы сапраўды хочаце працягнуць?" + "message": "Папярэджанне! Гэтаму карыстальніку патрабуецца Key Connector для таго, каб кіраваць шыфраваннем. Выдаленне гэтага карыстальніка з вашай арганізацыі канчаткова адключыць яго ўліковы запіс. Гэта дзеянне нельга будзе адрабіць. Вы сапраўды хочаце працягнуць?" }, "externalId": { "message": "Знешні ідэнтыфікатар" }, "externalIdDesc": { - "message": "Знешні ідэнтыфікатара можа быць выкарыстаны ў якасці спасылкі для сувязі гэтага рэсурсу са знешняй сістэмай, такой як каталог карыстальніка." + "message": "Знешні ідэнтыфікатар можа быць выкарыстаны ў якасці спасылкі для сувязі гэтага рэсурсу са знешняй сістэмай, такой як каталог карыстальніка." }, "accessControl": { "message": "Кантроль доступу" @@ -2371,7 +2371,7 @@ "message": "Запрасіць карыстальніка" }, "inviteUserDesc": { - "message": "Запрасіце новага карыстальніка ў вашу арганізацыю ўвёўшы яго электронную пошту ўліковага запісу Bitwarden. Калі ў яго пакуль няма ўліковага запісу Bitwarden, яму будзе прапанавана стварыць яго." + "message": "Запрасіць новага карыстальніка ў вашу арганізацыю, увёўшы яго электронную пошту ўліковага запісу Bitwarden. Калі ён не мае ўліковага запісу, то ён атрымае запыт на яго стварэнне." }, "inviteMultipleEmailDesc": { "message": "Вы можаце запрасіць да $COUNT$ карыстальнікаў за раз, падзяляючы адрасы электроннай пошты ў спісе коскамі.", @@ -2467,7 +2467,7 @@ "message": "Вэб-сховішча" }, "loggedIn": { - "message": "Выкананы ўваход." + "message": "Вы ўвайшлі." }, "changedPassword": { "message": "Пароль уліковага запісу зменены." @@ -2506,7 +2506,7 @@ } }, "editedItemId": { - "message": "Адрэдагаваны элемент $ID$.", + "message": "Элемент $ID$ адрэдагаваны.", "placeholders": { "id": { "content": "$1", @@ -2614,7 +2614,7 @@ } }, "editedCollectionId": { - "message": "Адрэдагавана калекцыя $ID$.", + "message": "Калекцыя $ID$ адрэдагавана.", "placeholders": { "id": { "content": "$1", @@ -2632,7 +2632,7 @@ } }, "editedPolicyId": { - "message": "Адрэдагаваная палітыка $ID$.", + "message": "Палітыка $ID$ адрэдагавана.", "placeholders": { "id": { "content": "$1", @@ -2650,7 +2650,7 @@ } }, "editedGroupId": { - "message": "Адрэдагавана група $ID$.", + "message": "Група $ID$ адрэдагавана.", "placeholders": { "id": { "content": "$1", @@ -2731,7 +2731,7 @@ } }, "editedCollectionsForItem": { - "message": "Адрэдагаваныя калекцыі для элемента $ID$.", + "message": "Калекцыі для элемента $ID$ адрэдагаваны.", "placeholders": { "id": { "content": "$1", @@ -2758,7 +2758,7 @@ } }, "editedUserId": { - "message": "Адрэдагаваны карыстальнік $ID$.", + "message": "Карыстальнік $ID$ адрэдагаваны.", "placeholders": { "id": { "content": "$1", @@ -2767,7 +2767,7 @@ } }, "editedGroupsForUser": { - "message": "Адрэдагаваныя групы для карыстальніка $ID$.", + "message": "Групы для карыстальніка $ID$ адрэдагаваны.", "placeholders": { "id": { "content": "$1", @@ -2776,7 +2776,7 @@ } }, "unlinkedSsoUser": { - "message": "Нязвязныя SSO для карыстальніка $ID$.", + "message": "Адлучаныя SSO для карыстальніка $ID$.", "placeholders": { "id": { "content": "$1", @@ -2881,7 +2881,7 @@ "message": "Пацвердзіць карыстальнікаў" }, "usersNeedConfirmed": { - "message": "У вас ёсць карыстальнікі, які прынялі запрашэнне, але патрабуюць пацвярджэння. Гэтыя карыстальнікі не будуць мець доступу да арганізацыі, пакуль не будуць пацверджаны." + "message": "У вас ёсць карыстальнікі, якія прынялі запрашэнне, але патрабуюць пацвярджэння. Гэтыя карыстальнікі не будуць мець доступу да арганізацыі, пакуль не будуць пацверджаны." }, "startDate": { "message": "Дата пачатку" @@ -2893,13 +2893,13 @@ "message": "Праверыць пошту" }, "verifyEmailDesc": { - "message": "Параверце ваш адрас электроннай пошты для разблакіроўкі доступу да ўсіх функцый." + "message": "Праверце ваш адрас электроннай пошты для разблакіроўкі доступу да ўсіх функцый." }, "verifyEmailFirst": { "message": "Спачатку неабходна праверыць адрас электроннай пошты вашага ўліковага запісу." }, "checkInboxForVerification": { - "message": "У папцы ўваходныя павінен быць праверачны код." + "message": "У папцы з уваходнымі павінна быць праверачная спасылка." }, "emailVerified": { "message": "Ваша пошта была праверана." @@ -2929,7 +2929,7 @@ "message": "Запрашэнне прынята" }, "inviteAcceptedDesc": { - "message": "Вы можаце атрымаць доступ да гэтага арганізацыі адразу пасля таго, як будзе пацверджаны ваш удзел. Мы апавясцім вас, калі гэта адбудзецца." + "message": "Вы можаце атрымаць доступ да гэтай арганізацыі адразу пасля таго, як будзе пацверджаны ваш удзел. Мы апавясцім вас, калі гэта адбудзецца." }, "inviteAcceptFailed": { "message": "Немагчыма прыняць запрашэнне. Папрасіце адміністратара арганізацыі адправіць яго яшчэ раз." @@ -2974,7 +2974,7 @@ "message": "Выдаліць арганізацыю" }, "deletingOrganizationContentWarning": { - "message": "Увядзіце галоўны пароль для пацвярджэння выдалення $ORGANIZATION$ і ўсіх звязаных даных. Даныя сховішча $ORGANIZATION$ уключаюць:", + "message": "Увядзіце асноўны пароль для пацвярджэння выдалення $ORGANIZATION$ і ўсіх звязаных даных. Даныя сховішча $ORGANIZATION$ уключаюць:", "placeholders": { "organization": { "content": "$1", @@ -3014,7 +3014,7 @@ "description": "A billing plan/package. For example: families, teams, enterprise, etc." }, "changeBillingPlan": { - "message": "Палепшыць план", + "message": "Палепшыць тарыфны план", "description": "A billing plan/package. For example: families, teams, enterprise, etc." }, "changeBillingPlanUpgrade": { @@ -3041,10 +3041,10 @@ "message": "Праверыць банкаўскі рахунак" }, "verifyBankAccountDesc": { - "message": "Мы зрабілі два сімвалічныя ўклады на ваш банкаўскі рахунак (ён адлюструецца ў спісе на працягу 1-2 працоўных дзён). Увядзіце гэту суму для праверкі банкаўскага рахунку." + "message": "Мы зрабілі два сімвалічныя ўклады на ваш банкаўскі рахунак (ён адлюструецца ў спісе на працягу некалькіх наступных працоўных дзён). Увядзіце гэту суму для праверкі банкаўскага рахунку." }, "verifyBankAccountInitialDesc": { - "message": "Плацеж праз банкаўскі рахунак даступны толькі кліентам, якія пражываюць у ЗША. Вам неабходна будзе пацвердзіць свой банкаўскі рахунак. Мы зробім два сімвалічныя ўклады на працягу наступных 1-2 дзён. Увядзіце гэтыя сумы на старонцы аплаты арганізацыі для праверкі банкаўскага рахунку." + "message": "Плацеж праз банкаўскі рахунак даступны толькі кліентам, якія пражываюць у ЗША. Вам неабходна будзе пацвердзіць свой банкаўскі рахунак. Мы зробім два сімвалічныя ўклады на працягу наступных некалькіх дзён. Увядзіце гэтыя сумы на старонцы аплаты арганізацыі для праверкі банкаўскага рахунку." }, "verifyBankAccountFailureWarning": { "message": "Невыкананне праверкі банкаўскага рахунку прывядзе да збою аплаты і адключэння падпіскі." @@ -3091,7 +3091,7 @@ "message": "Прызначыць абмежаванне месцаў для вашай падпіскі. Пасля дасягнення гэтага абмежавання, вы не зможаце запрашаць новых карыстальнікаў." }, "maxSeatLimit": { - "message": "Максімальная колькасць ліцэнзій (неабавязкова)", + "message": "Максімальная колькасць месцаў (неабавязкова)", "description": "Upper limit of seats to allow through autoscaling" }, "maxSeatCost": { @@ -3106,10 +3106,10 @@ "description": "Seat = User Seat" }, "subscriptionDesc": { - "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць ліцэнзій у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў." + "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць месцаў у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў." }, "subscriptionUserSeats": { - "message": "Колькасць карыстальнікаў для вашай падпіскі: $COUNT$.", + "message": "Агульная колькасць карыстальнікаў для вашай падпіскі: $COUNT$ шт.", "placeholders": { "count": { "content": "$1", @@ -3133,10 +3133,10 @@ "message": "Для атрымання дадатковай дапамогі ў кіраванні вашай падпіскай, калі ласка, звярніцеся ў службу падтрымкі." }, "subscriptionUserSeatsUnlimitedAutoscale": { - "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць ліцэнзій у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў." + "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць месцаў у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў." }, "subscriptionUserSeatsLimitedAutoscale": { - "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць ліцэнзій у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў, пакуль не будзе дасягнута абмежаванне $MAX$ ліцэнзій.", + "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Калі колькасць карыстальнікаў перавысіць колькасць месцаў у вашай падпісцы, вы адразу атрымаеце прапарцыйную плату за дадатковых карыстальнікаў, пакуль не будзе дасягнута абмежаванне (максімальная колькасць месцаў: $MAX$).", "placeholders": { "max": { "content": "$1", @@ -3163,7 +3163,7 @@ } }, "subscriptionSponsoredFamiliesPlan": { - "message": "Колькасць карыстальнікаў для вашай падпіскі: $COUNT$. Ваш тарыфны план мае спонсарскую падтрымку і аплачваецца знешняй арганізацыяй.", + "message": "Колькасць карыстальнікаў для вашай падпіскі: $COUNT$ шт. Ваш тарыфны план мае спонсарскую падтрымку і аплачваецца знешняй арганізацыяй.", "placeholders": { "count": { "content": "$1", @@ -3172,7 +3172,7 @@ } }, "subscriptionMaxReached": { - "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Вы не зможаце запрасіць больш за $COUNT$ карыстальнікаў без павелічэння ліцэнзій вашай падпіскі.", + "message": "Карэкціроўка вашай падпіскі прывядзе да прапарцыйнага змянення ў вашым выніковым рахунку. Вы не зможаце запрасіць больш за $COUNT$ карыстальнікаў без павелічэння месцаў у вашай падпісцы.", "placeholders": { "count": { "content": "$1", @@ -3181,16 +3181,16 @@ } }, "seatsToAdd": { - "message": "Дадаецца месца" + "message": "Дадаецца месцаў" }, "seatsToRemove": { - "message": "Ліцэнзіі для выдалення" + "message": "Месцаў для выдалення" }, "seatsAddNote": { - "message": "Дадаванне карыстальніцкіх ліцэнзій прывядзе да карэкціроўкі ў вашым выніковым рахунку і адразу будзе спагнана аплата згодна з азначаным метадам. Першы плацеж будзе прапарцыйны астачы бягучага плацежнага перыяду." + "message": "Дабаўленне карыстальніцкіх месцаў прывядзе да карэкціроўкі ў вашым выніковым рахунку і адразу будзе спагнаны плацеж згодна з азначаным у файле спосабам аплаты. Першы плацеж будзе прапарцыйны астачы бягучага плацежнага перыяду." }, "seatsRemoveNote": { - "message": "Выдаленне карыстальніцкіх ліцэнзій прывядзе да змен у вашым выніковым рахунку, які будзе прапарцыйна раздзелены ў выглядзе крэдытаў за наступны плацежны перыяд." + "message": "Выдаленне карыстальніцкіх месцаў прывядзе да карэкціроўкі вашага выніковага рахунку, які будзе прапарцыйна раздзелены ў выглядзе крэдытаў за наступны плацежны перыяд." }, "adjustedSeats": { "message": "Скарэктавана месцаў карыстальніка: $AMOUNT$.", @@ -3214,7 +3214,7 @@ "message": "Зараз вы выкарыстоўваеце састарэлую схему шыфравання." }, "updateEncryptionKeyDesc": { - "message": "Мы перайшлі на больш складаныя ключы шыфравання, якія забяспечваюць лепшую бяспеку і доступ да самых новых функцый. Абнаўленне вашы ключоў шыфравання адбываецца хутка і лёгка. Проста ўвядзіце свой галоўны пароль знізу. Гэта абнаўленне ўрэшце стане абавязковым." + "message": "Мы перайшлі на больш складаныя ключы шыфравання, якія забяспечваюць лепшую бяспеку і доступ да самых новых функцый. Абнаўленне вашых ключоў шыфравання адбудзецца хутка і лёгка. Проста ўвядзіце свой асноўны пароль знізу. Гэта абнаўленне ўрэшце стане абавязковым." }, "updateEncryptionKeyWarning": { "message": "Пасля абнаўлення вашага ключа шыфравання вам неабходна выйсці з сістэмы, а потым выканаць паўторны ўваход ва ўсе праграмы Bitwarden, якія вы зараз выкарыстоўваеце (напрыклад, мабільныя праграмы або пашырэнні для браўзераў). Збой пры выхадзе і паўторным уваходзе (пры гэтым спампоўваецца ваш новы ключ шыфравання) можа стаць прычынай пашкоджання даных. Мы паспрабуем аўтаматычна ажыццявіць завяршэнне ўсіх вашых сеансаў, але гэта можа адбывацца з затрымкай." @@ -3247,10 +3247,10 @@ "message": "Вернута" }, "nothingSelected": { - "message": "Вы нічога не выбралі." + "message": "Вы пакуль нічога не выбралі." }, "acceptPolicies": { - "message": "Ставячы гэты сцяжок вы пагаджаецеся з наступным:" + "message": "Ставячы гэты сцяжок, вы пагаджаецеся з наступным:" }, "acceptPoliciesRequired": { "message": "Умовы выкарыстання і Палітыка прыватнасці не былі пацверджаны." @@ -3321,7 +3321,7 @@ "message": "Хто валодае гэтым элементам?" }, "strong": { - "message": "Моцны", + "message": "Надзейны", "description": "ex. A strong password. Scale: Very Weak -> Weak -> Good -> Strong" }, "good": { @@ -3329,15 +3329,15 @@ "description": "ex. A good password. Scale: Very Weak -> Weak -> Good -> Strong" }, "weak": { - "message": "Слабы", + "message": "Ненадзейны", "description": "ex. A weak password. Scale: Very Weak -> Weak -> Good -> Strong" }, "veryWeak": { - "message": "Вельмі слабы", + "message": "Вельмі ненадзейны", "description": "ex. A very weak password. Scale: Very Weak -> Weak -> Good -> Strong" }, "weakMasterPassword": { - "message": "Слабы асноўны пароль" + "message": "Ненадзейны асноўны пароль" }, "weakMasterPasswordDesc": { "message": "Асноўны пароль, які вы выбралі з'яўляецца ненадзейным. Для належнай абароны ўліковага запісу Bitwarden, вы павінны выкарыстоўваць надзейны асноўны пароль (або парольную фразу). Вы ўпэўнены, што хочаце выкарыстоўваць гэты асноўны пароль?" @@ -3365,7 +3365,7 @@ "message": "У вашым сховішчы ёсць старыя далучаныя файлы, якія неабходна выправіць перад тым, як змяніць ключ шыфравання ўліковага запісу." }, "yourAccountsFingerprint": { - "message": "Фраза адбітку вашага ўліковага запісу", + "message": "Фраза адбітку пальца вашага ўліковага запісу", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, "fingerprintEnsureIntegrityVerify": { @@ -3384,7 +3384,7 @@ "message": "Ключ API" }, "apiKeyDesc": { - "message": "Ваш ключ API можа быць выкарыстаны для аўтэнтыфікацыі публічнага API праграмы." + "message": "Ваш ключ API можа быць выкарыстаны для аўтэнтыфікацыі публічнага API праграмы Bitwarden." }, "apiKeyRotateDesc": { "message": "Змяненне ключа API анулюе папярэдні ключ. Вы можаце змяніць ваш ключ API, калі ёсць любыя сумневы адносна бяспекі бягучага ключа." @@ -3418,7 +3418,7 @@ "message": "Купля ў праграме" }, "cannotPerformInAppPurchase": { - "message": "Вы не можаце выканаць гэта дзеянне падчас выкарыстання аплаты ў праграме." + "message": "Вы не можаце выканаць гэта дзеянне падчас выкарыстання спосабу аплаты ў праграме." }, "manageSubscriptionFromStore": { "message": "Вы павінны кіраваць сваёй падпіскай з той крамы, у якой вы ажыццяўлялі куплю праграмы." @@ -3433,28 +3433,28 @@ "message": "Патрабуецца асноўны пароль" }, "masterPassPolicyDesc": { - "message": "Задайце мінімальныя патрабаванні для надзейнасці асноўнага пароля." + "message": "Прызначце мінімальныя патрабаванні да надзейнасці асноўнага пароля." }, "twoStepLoginPolicyTitle": { "message": "Патрабуецца двухэтапны ўваход" }, "twoStepLoginPolicyDesc": { - "message": "Патрабаваць удзельнікаў наладу двуэтапнага ўваходу." + "message": "Патрабаваць ад удзельнікаў наладу двуэтапнага ўваходу." }, "twoStepLoginPolicyWarning": { - "message": "Удзельнікі арганізацыі, якія не з'яўляюцца ўладальнікамі або адміністратарамі і якія не ўключылі двухэтапны ўваход у сваіх уліковых запісаць будуць выдалены з арганізацыі і атрымаюць адпаведнае апавяшчэнне па электроннай пошце." + "message": "Удзельнікі арганізацыі, якія не з'яўляюцца ўладальнікамі або адміністратарамі і якія не ўключылі двухэтапны ўваход у сваіх уліковых запісах будуць выдалены з арганізацыі і атрымаюць адпаведнае апавяшчэнне па электроннай пошце." }, "twoStepLoginPolicyUserWarning": { - "message": "Вы з'яўляецеся ўдзельнікам арганізацыі, якая патрабуе выкарыстанне двухэтапнага ўваходу для вашага ўліковага запісу. Калі вы адключыце ўсіх пастаўшчыкоў двухэтапнага ўваходу, то вы будзеце аўтаматычна выдалены з гэтай арганізацыі." + "message": "Вы з'яўляецеся ўдзельнікам арганізацыі, якая патрабуе выкарыстанне двухэтапнага ўваходу для вашага ўліковага запісу. Калі вы адключыце ўсіх пастаўшчыкоў двухэтапнага ўваходу, вы будзеце аўтаматычна выдалены з гэтай арганізацыі." }, "passwordGeneratorPolicyDesc": { "message": "Прызначыць патрабаванні для генератара пароляў." }, "passwordGeneratorPolicyInEffect": { - "message": "На налады генератара ўплываюць адна або некалькі палітык арганізацый." + "message": "Адна або больш палітык арганізацыі ўплывае на налады генератара." }, "masterPasswordPolicyInEffect": { - "message": "Згодна з адной або некалькімі палітыкамі арганізацыі асноўны пароль павінен адпавядаць наступным патрабаванням:" + "message": "Адна або больш палітык арганізацыі патрабуе, каб ваш асноўны пароль адпавядаў наступным патрабаванням:" }, "policyInEffectMinComplexity": { "message": "Мінімальны ўзровень складанасці $SCORE$", @@ -3475,13 +3475,13 @@ } }, "policyInEffectUppercase": { - "message": "Уключыць адну ці больш вялікіх літар" + "message": "Уключыць адну або некалькі вялікіх літар" }, "policyInEffectLowercase": { - "message": "Уключыць адну ці больш малых літар" + "message": "Уключыць адну або некалькі малых літар" }, "policyInEffectNumbers": { - "message": "Уключыць адну або больш лічбаў" + "message": "Уключыць адну або некалькі лічбаў" }, "policyInEffectSpecial": { "message": "Уключаць хаця б адзін з наступных спецыяльных сімвалаў $CHARS$", @@ -3493,7 +3493,7 @@ } }, "masterPasswordPolicyRequirementsNotMet": { - "message": "Ваш новы асноўны пароль не адпавядае патрабаванням палітыцы." + "message": "Ваш новы асноўны пароль не адпавядае патрабаванням палітыкі." }, "minimumNumberOfWords": { "message": "Мінімум лічбаў або слоў" @@ -3505,10 +3505,10 @@ "message": "Параметры карыстальніка" }, "vaultTimeoutAction": { - "message": "Дзеянне пасля заканчэння часу сховішча" + "message": "Дзеянне пасля заканчэння часу чакання сховішча" }, "vaultTimeoutActionLockDesc": { - "message": "Для таго, каб атрымаць доступ да заблакіраванага сховішча, вам неабходна ўвесці галоўны пароль або скарыстацца іншым метадам разблакіроўкі." + "message": "Для атрымання доступу да заблакіраванага сховішча, вам неабходна ўвесці асноўны пароль або скарыстацца іншым метадам разблакіроўкі." }, "vaultTimeoutActionLogOutDesc": { "message": "Для таго, каб аднавіць доступ да сховішча, патрабуецца паўторная аўтарызацыя." @@ -3525,7 +3525,7 @@ "message": "Пошук у сметніцы" }, "permanentlyDelete": { - "message": "Выдаліць канчаткова" + "message": "Выдаліць назаўсёды" }, "permanentlyDeleteSelected": { "message": "Назаўсёды выдаліць выбраныя" @@ -3534,7 +3534,7 @@ "message": "Назаўсёды выдаліць элементы" }, "permanentlyDeleteItemConfirmation": { - "message": "Вы ўпэўнены, што хочаце назаўсёды выдаліць гэтыя элементы?" + "message": "Вы ўпэўнены, што хочаце назаўсёды выдаліць гэты элемент?" }, "permanentlyDeletedItem": { "message": "Элемент выдалены назаўсёды" @@ -3543,7 +3543,7 @@ "message": "Элементы выдалены назаўсёды" }, "permanentlyDeleteSelectedItemsDesc": { - "message": "Вы выбралі наступную колькасць запісаў для выдалення: $COUNT$ шт. Вы ўпэўнены, што хочаце назаўсёды выдаліць гэтыя элементы?", + "message": "Вы выбралі наступную колькасць элементаў для выдалення: $COUNT$ шт. Вы ўпэўнены, што хочаце назаўсёды выдаліць іх?", "placeholders": { "count": { "content": "$1", @@ -3582,7 +3582,7 @@ "message": "Аднавіць элементы" }, "restoreSelectedItemsDesc": { - "message": "Вы выбралі наступную колькасць запісаў для аднаўлення: $COUNT$. Вы ўпэўнены, што хочаце аднавіць гэтыя элементы?", + "message": "Вы выбралі наступную колькасць элементаў для аднаўлення: $COUNT$. Вы ўпэўнены, што хочаце аднавіць іх?", "placeholders": { "count": { "content": "$1", @@ -3600,7 +3600,7 @@ } }, "vaultTimeoutLogOutConfirmation": { - "message": "Выхад з сістэмы скасуе ўсе магчымасці доступу да сховішча і запатрабуе аўтэнтыфікацыі праз інтэрнэт пасля завяршэння часу чакання. Вы ўпэўнены, што хочаце выкарыстоўваць гэты параметр?" + "message": "Выхад з сістэмы скасуе ўсе магчымасці доступу да сховішча і запатрабуе аўтэнтыфікацыю праз інтэрнэт пасля завяршэння часу чакання. Вы ўпэўнены, што хочаце выкарыстоўваць гэты параметр?" }, "vaultTimeoutLogOutConfirmationTitle": { "message": "Пацвярджэнне дзеяння часу чакання" @@ -3621,10 +3621,10 @@ "message": "Падатковая інфармацыя абноўлена." }, "setMasterPassword": { - "message": "Задаць асноўны пароль" + "message": "Прызначыць асноўны пароль" }, "ssoCompleteRegistration": { - "message": "Для завяршэння працэсу ўваходу з дапамогай SSO, прызначце галоўны пароль для доступу да вашага сховішча і яго абароны." + "message": "Для завяршэння працэсу ўваходу з дапамогай SSO, прызначце асноўны пароль для доступу да вашага сховішча і яго абароны." }, "identifier": { "message": "Ідэнтыфікатар" @@ -3636,7 +3636,7 @@ "message": "Уваходзьце з выкарыстаннем партала адзінага ўваходу вашай арганізацыі. Калі ласка, увядзіце ідэнтыфікатар вашай арганізацыі для пачатку працы." }, "enterpriseSingleSignOn": { - "message": "Адзіны карпаратыўны ўваход (SSO)" + "message": "Адзіны ўваход прадпрыемства (SSO)" }, "ssoHandOff": { "message": "Цяпер вы можаце закрыць гэту ўкладку і працягнуць у пашырэнні." @@ -3663,10 +3663,10 @@ "message": "Вы ўпэўнены, што хочаце адлучыць SSO для гэтай арганізацыі?" }, "linkSso": { - "message": "Падлучыць SSO" + "message": "Звязаць з SSO" }, "singleOrg": { - "message": "Адна арганізацыя" + "message": "Адзіная арганізацыя" }, "singleOrgDesc": { "message": "Забараніць удзельнікам далучацца да іншых арганізацый." @@ -3681,13 +3681,13 @@ "message": "Патрабаваць аўтэнтыфікацыю праз адзіны ўваход (SSO)" }, "requireSsoPolicyDesc": { - "message": "Патрабаваць ад удзельнікаў уваходзіць праз адзіны карпаратыўны ўваход (SSO)." + "message": "Патрабаваць ад удзельнікаў уваходзіць праз адзіны ўваход прадпрыемства (SSO)." }, "prerequisite": { "message": "Перадумова" }, "requireSsoPolicyReq": { - "message": "Перад актывацыяй гэтай палітыкі неабходна ўключыць палітыку адзінага ўваходу (SSO)." + "message": "Перад актывацыяй гэтай палітыкі неабходна ўключыць палітыку адзінага ўваходу (SSO) прадпрыемства." }, "requireSsoPolicyReqError": { "message": "Палітыка адзінай арганізацыі не ўключана." @@ -3706,23 +3706,23 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editSend": { - "message": "Рэдагаваць адпраўленне", + "message": "Рэдагаваць Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "createdSend": { - "message": "Адпраўленне створана", + "message": "Створаны Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "editedSend": { - "message": "Адрэдагаваны Send", + "message": "Send адрэдагаваны", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletedSend": { - "message": "Адпраўленне выдалена", + "message": "Send выдалены", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSend": { - "message": "Выдаленне Send", + "message": "Выдаліць Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deleteSendConfirmation": { @@ -3730,7 +3730,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "whatTypeOfSend": { - "message": "Які гэта тып Send?", + "message": "Які гэта тып Send'a?", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "deletionDate": { @@ -3744,14 +3744,14 @@ "message": "Дата завяршэння" }, "expirationDateDesc": { - "message": "Калі зададзена, то доступ да гэтага Send міне ў азначаную дату і час.", + "message": "Калі прызначана, то доступ да гэтага Send міне ў азначаную дату і час.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "maxAccessCount": { "message": "Максімальная колькасць доступаў" }, "maxAccessCountDesc": { - "message": "Калі зададзена, то карыстальнікі больш не змогуць атрымаць доступ да гэтага Send пасля таго, як будзе дасягнута максімальная колькасць зваротаў.", + "message": "Калі прызначана, то карыстальнікі больш не змогуць атрымаць доступ да гэтага Send пасля таго, як будзе дасягнута максімальная колькасць зваротаў.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "currentAccessCount": { @@ -3772,11 +3772,11 @@ "message": "Адклікана" }, "sendLink": { - "message": "Адправіць спасылку", + "message": "Спасылка на Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "copySendLink": { - "message": "Капіяваць спасылку на Send", + "message": "Скапіяваць спасылку на Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "removePassword": { @@ -3796,7 +3796,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "allSends": { - "message": "Усе адпраўленні" + "message": "Усе Send'ы" }, "maxAccessCountReached": { "message": "Дасягнута максімальная колькасць доступаў", @@ -3809,7 +3809,7 @@ "message": "Пратэрмінавана" }, "searchSends": { - "message": "Шукаць адпраўленні", + "message": "Пошук у Send'ах", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendProtectedPassword": { @@ -3836,14 +3836,14 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "noSendsInList": { - "message": "У спісе адсутнічае Send.", + "message": "У спісе адсутнічаюць Send'ы.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "emergencyAccess": { "message": "Экстранны доступ" }, "emergencyAccessDesc": { - "message": "Забяспечце экстранны доступ давераным кантактам. Давераныя кантакты могуць атрымаць доступ для прагляду або перадачы валодання вашым уліковы запісам у экстранных сітуацыях. Наведайце нашу старонку дапамогі для падрабязнага азнаямлення, як працуе супольны доступ нулявога ўзроўню." + "message": "Дайце экстранны доступ давераным кантактам. Давераныя кантакты могуць атрымаць доступ для прагляду або перадачы валодання вашым уліковы запісам у экстранных сітуацыях. Наведайце нашу старонку дапамогі для падрабязнага азнаямлення, як працуе супольны доступ нулявога ўзроўню." }, "emergencyAccessOwnerWarning": { "message": "Вы ўладальнік адной або некалькіх арганізацый. Калі перадаць доступ валодання экстранным кантактам, то ён будзе мець усе дазволы ўладальніка пасля перадачы." @@ -3861,7 +3861,7 @@ "message": "Прызначаны ў якасці экстраннага кантакту" }, "noGrantedAccess": { - "message": "Вы нікога пакуль не прызначылі ў якасці экстраннага кантакту." + "message": "У вас пакуль няма экстранных кантактаў." }, "inviteEmergencyContact": { "message": "Запрасіць экстранны кантакт" @@ -3885,7 +3885,7 @@ "message": "Перадача ўласнасці" }, "takeoverDesc": { - "message": "Можа скідаць пароль вашага ўліковага запісу." + "message": "Можа скідаць асноўны пароль вашага ўліковага запісу." }, "waitTime": { "message": "Час чакання" @@ -3930,7 +3930,7 @@ "message": "Запытаць доступ" }, "requestAccessConfirmation": { - "message": "Вы ўпэўнены, што хочаце запытаць экстранны доступ? Вам будзе забяспечаны доступ праз $WAITTIME$ дзён або калі карыстальнік уручную ўхваліць вас.", + "message": "Вы ўпэўнены, што хочаце запытаць экстранны доступ? Вам будзе забяспечаны доступ (меркаваная колькасць дзён: $WAITTIME$) або калі карыстальнік уручную ўхваліць запыт.", "placeholders": { "waittime": { "content": "$1", @@ -3939,7 +3939,7 @@ } }, "requestSent": { - "message": "Экстранны доступ запрошаны для $USER$. Вы апавясцім вас па электроннай пошце, калі можна будзе працягнуць.", + "message": "Экстранны доступ запрошаны для $USER$. Мы апавясцім вас па электроннай пошце, калі можна будзе працягнуць.", "placeholders": { "user": { "content": "$1", @@ -3973,7 +3973,7 @@ "message": "Экстранны доступ адхілены" }, "passwordResetFor": { - "message": "Пароль скінуты для $USER$. Цяпер вы ўвайсці з дапамогай новага пароля.", + "message": "Пароль скінуты для $USER$. Цяпер вы можаце ўвайсці з дапамогай новага пароля.", "placeholders": { "user": { "content": "$1", @@ -3991,13 +3991,13 @@ "message": "На ўладальнікаў арганізацыі і адміністратараў гэта палітыка не аказвае ўплыву." }, "personalOwnershipSubmitError": { - "message": "У адпаведнасці з карпаратыўнай палітыкай вам забаронена захоўваць элементы ў асабістым сховішчы. Змяніце параметры ўласнасці на арганізацыю і выберыце з даступных калекцый." + "message": "У адпаведнасці з палітыкай прадпрыемства вам забаронена захоўваць элементы ў асабістым сховішчы. Змяніце параметры ўласнасці на арганізацыю і выберыце з даступных калекцый." }, "disableSend": { "message": "Выдаліць Send" }, "disableSendPolicyDesc": { - "message": "Не дазваляць удзельнікам ствараць або рэдагаваць Send'ы.", + "message": "Не дазваляць удзельнікам ствараць або рэдагаваць Send.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disableSendExemption": { @@ -4008,11 +4008,11 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendDisabledWarning": { - "message": "У адпаведнасці з карпаратыўнай палітыкай, вы можаце выдаліць толькі бягучы Send.", + "message": "У адпаведнасці з палітыкай прадпрыемства, вы можаце выдаліць толькі бягучы Send.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptions": { - "message": "Параметры адпраўкі", + "message": "Параметры Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptionsPolicyDesc": { @@ -4057,6 +4057,12 @@ "permissions": { "message": "Дазволы" }, + "managerPermissions": { + "message": "Дазволы менеджара" + }, + "adminPermissions": { + "message": "Дазволы адміністратара" + }, "accessEventLogs": { "message": "Доступ да журналаў з падзеямі" }, @@ -4070,7 +4076,7 @@ "message": "У вас недастаткова правоў для выканання гэтага дзеяння." }, "manageAllCollections": { - "message": "Кіраваць усімі калекцыямі" + "message": "Кіраванне ўсімі калекцыямі" }, "createNewCollections": { "message": "Старыць новыя калекцыі" @@ -4082,7 +4088,7 @@ "message": "Выдаліць любую калекцыю" }, "manageAssignedCollections": { - "message": "Кіраваць прызначанымі калекцыямі" + "message": "Кіраванне прызначанымі калекцыямі" }, "editAssignedCollections": { "message": "Рэдагаваць прызначаныя калекцыі" @@ -4118,10 +4124,10 @@ "message": "Палітыка арганізацыі ўплывае на вашы параметры ўласнасці." }, "personalOwnershipPolicyInEffectImports": { - "message": "Імпартаванне элементаў у вашым асабістым сховішчы адключаны палітыкай арганізацыі." + "message": "Імпартаванне элементаў у вашым асабістым сховішчы адключана палітыкай арганізацыі." }, "personalOwnershipCheckboxDesc": { - "message": "Адключыць асабістую ўласная для карыстальнікаў арганізацыі" + "message": "Адключыць асабістую ўласнасць для карыстальнікаў арганізацыі" }, "textHiddenByDefault": { "message": "Пры доступе да Send прадвызначана хаваць тэкст", @@ -4141,7 +4147,7 @@ "message": "Скапіяваць спасылку ў буфер абмену пасля захавання, каб абагуліць гэты Send." }, "sendLinkLabel": { - "message": "Адправіць спасылку", + "message": "Спасылка на Send", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "send": { @@ -4250,7 +4256,7 @@ "message": "Адмова паспяхова ўжыта!" }, "eventEnrollPasswordReset": { - "message": "Карыстальнік $ID$ зарэгістраваўся, каб атрымаць дапамогу ў скіданні пароля.", + "message": "Карыстальнік $ID$ падаў запыт, каб атрымаць дапамогу ў скіданні пароля.", "placeholders": { "id": { "content": "$1", @@ -4268,7 +4274,7 @@ } }, "eventAdminPasswordReset": { - "message": "Галоўны пароль скінуты карыстальнікам $ID$.", + "message": "Асноўны пароль скінуты карыстальнікам $ID$.", "placeholders": { "id": { "content": "$1", @@ -4310,79 +4316,79 @@ "message": "гэты карыстальнік" }, "resetPasswordMasterPasswordPolicyInEffect": { - "message": "Згодна з адной або некалькімі палітыкамі арганізацыі асноўны пароль павінен адпавядаць наступным патрабаванням:" + "message": "Адна або больш палітык арганізацыі патрабуе, каб асноўны пароль адпавядаў наступным патрабаванням:" }, "resetPasswordSuccess": { "message": "Пароль паспяхова скінуты!" }, "resetPasswordEnrollmentWarning": { - "message": "Рэгістрацыя дазволіць адміністратарам арганізацыі змяць ваш галоўны пароль" + "message": "Рэгістрацыя дазволіць адміністратарам арганізацыі змяняць ваш асноўны пароль" }, "resetPasswordPolicy": { "message": "Скіданне асноўнага пароля" }, "resetPasswordPolicyDescription": { - "message": "Дазволіць адміністратарам скідаць галоўны пароль для ўдзельнікаў." + "message": "Дазволіць адміністратарам скідаць асноўны пароль для ўдзельнікаў." }, "resetPasswordPolicyWarning": { - "message": "Users in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password." + "message": "Карыстальнікі арганізацыі павінны зарэгістравацца самастойна або быць зарэгістраванымі аўтаматычна, каб адміністратары маглі скінуць іх асноўны пароль." }, "resetPasswordPolicyAutoEnroll": { "message": "Аўтаматычная рэгістрацыя" }, "resetPasswordPolicyAutoEnrollDescription": { - "message": "All users will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw." + "message": "Усе карыстальнікі будуць аўтаматычна зарэгістраваны на скіданне пароля, пасля таго як іх запрашэнне будзе прынята і ім не будзе дазволена адмовіцца ад яго выканання." }, "resetPasswordPolicyAutoEnrollWarning": { - "message": "Users already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password." + "message": "Карыстальнікі, якія ўжо ўваходзяць у арганізацыю не змогуць зарэгістравацца на скіданне пароля папярэднім чыслом. Яны павінны будуць самастойна зарэгістравацца, перад тым як адміністратары змогуць скінуць іх асноўны пароль." }, "resetPasswordPolicyAutoEnrollCheckbox": { - "message": "Require new users to be enrolled automatically" + "message": "Аўтаматычна рэгістраваць новых карыстальнікаў" }, "resetPasswordAutoEnrollInviteWarning": { - "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." + "message": "Гэта арганізацыя мае палітыку прадпрыемства, якая аўтаматычна зарэгіструе ваша скіданне пароля. Рэгістрацыя дазволіць адміністратарам арганізацыі змяняць ваш асноўны пароль." }, "resetPasswordOrgKeysError": { - "message": "Organization Keys response is null" + "message": "Пусты адказ на ключы арганізацыі" }, "resetPasswordDetailsError": { - "message": "Reset Password Details response is null" + "message": "Пусты адказ на скіданне пароля" }, "trashCleanupWarning": { - "message": "Items that have been in Trash more than 30 days will be automatically deleted." + "message": "Элементы, якія знаходзяцца ў сметніцы больш чым 30 дзён будуць выдаляцца аўтаматычна." }, "trashCleanupWarningSelfHosted": { - "message": "Items that have been in Trash for a while will be automatically deleted." + "message": "Элементы, якія знаходзіцца ў сметніцы пэўны час будуць выдаляцца аўтаматычна." }, "passwordPrompt": { - "message": "Master password re-prompt" + "message": "Паўторны запыт асноўнага пароля" }, "passwordConfirmation": { - "message": "Master password confirmation" + "message": "Пацвярджэнне асноўнага пароля" }, "passwordConfirmationDesc": { - "message": "This action is protected. To continue, please re-enter your master password to verify your identity." + "message": "Гэта дзеянне абаронена. Для працягу, калі ласка, паўторна ўвядзіце свой асноўны пароль, каб пацвердзіць вашу асобу." }, "reinviteSelected": { "message": "Паўторна адправіць запрашэнні" }, "noSelectedUsersApplicable": { - "message": "This action is not applicable to any of the selected users." + "message": "Гэта дзеянне нельга ўжыць для ніводнага з выбраных карыстальнікаў." }, "removeUsersWarning": { - "message": "Are you sure you want to remove the following users? The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Вы ўпэўнены, што хочаце выдаліць наступных карыстальнікаў? Для завяршэння працэсу можа спатрэбіцца некалькі секунд і гэта дзеянне нельга перарваць або скасаваць." }, "removeOrgUsersConfirmation": { - "message": "Пасля выдалення ўдзельніка(-ў) яны згубяць доступ да даных арганізацыі і гэта дзеянне з'яўляецца незваротным. Для паўторнага дабаўлення ўдзельніка ў арганізацыю, яго неабходна будзе зноў запрасіць туды. Працэс можа заняць некалькі секунд і яго немагчыма перарваць або скасаваць." + "message": "Пасля выдалення ўдзельніка(-ў) ён згубіць доступ да даных арганізацыі і гэта дзеянне з'яўляецца незваротным. Для паўторнага дабаўлення ўдзельніка ў арганізацыю, яго неабходна будзе зноў запрасіць туды. Працэс можа заняць некалькі секунд і яго немагчыма перарваць або скасаваць." }, "revokeUsersWarning": { - "message": "When member(s) are revoked, they no longer have access to organization data. To quickly restore member access, go to the Revoked tab. The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Калі ўдзельнік(-і) адкліканы, ён больш не зможа атрымаць доступ да даных арганізацыі. Для хуткага аднаўлення доступу ўдзельніка, перайдзіце ва ўкладку \"Адкліканыя\". Для завяршэння працэсу можа спатрэбіцца некалькі секунд і гэта дзеянне не можа быць перарвана або скасавана." }, "theme": { "message": "Тэма" }, "themeDesc": { - "message": "Choose a theme for your web vault." + "message": "Выберыце тэму для свайго вэб-сховішча." }, "themeSystem": { "message": "Выкарыстоўваць сістэмную тэму" @@ -4400,22 +4406,22 @@ "message": "Статус масавага дзеяння" }, "bulkConfirmMessage": { - "message": "Confirmed successfully." + "message": "Паспяхова пацверджана." }, "bulkReinviteMessage": { - "message": "Reinvited successfully." + "message": "Паспяхова паўторна запрошаны." }, "bulkRemovedMessage": { "message": "Паспяхова выдалена" }, "bulkRevokedMessage": { - "message": "Revoked organization access successfully" + "message": "Паспяхова адкліканы доступ да арганізацыі" }, "bulkRestoredMessage": { - "message": "Restored organization access successfully" + "message": "Паспяхова адноўлены доступ да арганізацыі" }, "bulkFilteredMessage": { - "message": "Excluded, not applicable for this action." + "message": "Выключэнне нельга ўжыць для гэтага дзеяння." }, "fingerprint": { "message": "Адбітак" @@ -4433,13 +4439,13 @@ "message": "Памылка" }, "resetPasswordManageUsers": { - "message": "Manage Users must also be enabled with the Manage Password Reset permission" + "message": "Кіраванне карыстальнікамі павінна таксама быць уключана з дазволам \"Кіраванне скіданнем пароля\"" }, "setupProvider": { "message": "Налады пастаўшчыка" }, "setupProviderLoginDesc": { - "message": "Вы былі запрошаны для наладжвання новага пастаўшчыка. Для працягу вам неабходна ўвайсці або стврыць новы ўліковы запіс Bitwarden." + "message": "Вы былі запрошаны для наладжвання новага пастаўшчыка. Для працягу вам неабходна ўвайсці або стварыць новы ўліковы запіс Bitwarden." }, "setupProviderDesc": { "message": "Калі ласка, увядзіце дэталі ніжэй для завяршэння наладжвання правайдара. Вы можаце звязацца са службай падтрымкі, калі ў вас узніклі пытанні." @@ -4463,7 +4469,7 @@ "message": "Сэрвісны карыстальнік" }, "serviceUserDesc": { - "message": "Service users can access and manage all client organizations." + "message": "Сэрвісныя карыстальнікі могуць атрымліваць доступ і кіраваць усімі кліенцкімі арганізацыямі." }, "providerInviteUserDesc": { "message": "Запрасіць новага карыстальніка да вашага пастаўшчыка, увёўшы электронную пошту яго ўліковага запісу Bitwarden ніжэй. Калі ён не мае ўліковага запісу, то ён атрымае запыт на яго стварэнне." @@ -4472,7 +4478,7 @@ "message": "Далучыцца да пастаўшчыка" }, "joinProviderDesc": { - "message": "Вас запрасілі далучыцца да азначанага вышэй пастаўшчыка. Для таго, каб пацвердзіць запрашэнне, вам неабходна ўвайсці ў ваш уліковы запіс Bitwarden або стварыць яго." + "message": "Вас запрасілі далучыцца да азначанага вышэй пастаўшчыка. Для таго, каб пацвердзіць запрашэнне, вам неабходна ўвайсці або стварыць новы ўліковы запіс Bitwarden." }, "providerInviteAcceptFailed": { "message": "Немагчыма прыняць запрашэнне. Папрасіце адміністратара пастаўшчыка адправіць яго яшчэ раз." @@ -4481,7 +4487,7 @@ "message": "Вы можаце атрымаць доступ да гэтага пастаўшчыка адразу пасля таго, як будзе пацверджаны ваш удзел. Мы апавясцім вас, калі гэта адбудзецца." }, "providerUsersNeedConfirmed": { - "message": "У вас ёсць карыстальнікі, якія прынялі запрашэнне, але яшчэ не былі пацверджаны. Яны не будуць мець доступу да пастаўшчыка пакуль не будзе пацверджаны іх удзел." + "message": "У вас ёсць карыстальнікі, якія прынялі запрашэнне, але яшчэ не былі пацверджаны. Яны не будуць мець доступу да пастаўшчыка пакуль не будуць пацверджаны." }, "provider": { "message": "Пастаўшчык" @@ -4554,16 +4560,16 @@ "message": "Дадаць" }, "updatedMasterPassword": { - "message": "Галоўны пароль абноўлены" + "message": "Асноўны пароль абноўлены" }, "updateMasterPassword": { - "message": "Абнавіць галоўны пароль" + "message": "Абнавіць асноўны пароль" }, "updateMasterPasswordWarning": { - "message": "Ваш галоўны пароль быў нядаўна зменены адміністратарам вашай арганізацыі. Для атрымання доступу да сховішча, вы павінны абнавіць галоўны пароль. Працягваючы, вы выйдзіце з бягучага сеанса і вам неабходна будзе ўвайсці паўторна. Сеансы на іншых прыладах могуць заставацца актыўнымі на працягу адной гадзіны." + "message": "Ваш асноўны пароль быў нядаўна зменены адміністратарам вашай арганізацыі. Для атрымання доступу да сховішча, вы павінны абнавіць яго. Працягваючы, вы выйдзіце з бягучага сеанса і вам неабходна будзе ўвайсці паўторна. Сеансы на іншых прыладах могуць заставацца актыўнымі на працягу адной гадзіны." }, "masterPasswordInvalidWarning": { - "message": "Ваш галоўны пароль не адпавядае патрабаванням гэтай арганізацыі. Каб далучыцца да арганізацыі, вам неабходна абнавіць свой галоўны пароль зараз. Працягнуўшы, вы выйдзіце з бягучага сеанса і вам спатрэбіцца ўвайсці зноў. Сеансы на іншых прыладах могуць заставацца актыўнымі на працягу гадзіны." + "message": "Ваш асноўны пароль не адпавядае патрабаванням гэтай арганізацыі. Каб далучыцца да арганізацыі, вам неабходна абнавіць яго зараз. Працягнуўшы, вы выйдзіце з бягучага сеанса і вам спатрэбіцца ўвайсці зноў. Сеансы на іншых прыладах могуць заставацца актыўнымі на працягу гадзіны." }, "maximumVaultTimeout": { "message": "Час чакання сховішча" @@ -4584,7 +4590,7 @@ "message": "Хвіліны" }, "vaultTimeoutPolicyInEffect": { - "message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)", + "message": "Палітыка вашай арганізацыі ўплывае на час чакання сховішча. Максімальны дазволены час чакання сховішча складае $HOURS$ гадз. і $MINUTES$ хв.", "placeholders": { "hours": { "content": "$1", @@ -4600,34 +4606,34 @@ "message": "Карыстальніцкі час чакання сховішча" }, "vaultTimeoutToLarge": { - "message": "Your vault timeout exceeds the restriction set by your organization." + "message": "Час чакання вашага сховішча перавышае дазволеныя абмежаванні, якія прызначыла ваша арганізацыя." }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "Мінімальны карыстальніцкі час чакання складае 1 хвіліну." }, "vaultTimeoutRangeError": { - "message": "Vault Timeout is not within allowed range." + "message": "Час чакання сховішча па-за межамі дазволенага дыяпазону." }, "disablePersonalVaultExport": { - "message": "Remove individual vault export" + "message": "Выдаліць экспартаванне асабістага сховішча" }, "disablePersonalVaultExportDesc": { - "message": "Do not allow members to export their individual vault data." + "message": "Не дазваляць удзельнікам экспартаваць іх індывідуальнае сховішча." }, "vaultExportDisabled": { "message": "Экспартаванне сховішча адключана" }, "personalVaultExportPolicyInEffect": { - "message": "One or more organization policies prevents you from exporting your personal vault." + "message": "Адна або больш палітык арганізацыі не дазваляюць вам экспартаваць асабістае сховішча." }, "selectType": { - "message": "Select SSO Type" + "message": "Выберыце тып SSO" }, "type": { "message": "Тып" }, "openIdConnectConfig": { - "message": "OpenID Connect Configuration" + "message": "Канфігурацыя злучэння OpenID" }, "samlSpConfig": { "message": "Канфігурацыя пастаўшчыка паслуг SAML" @@ -4639,10 +4645,10 @@ "message": "Шлях да зваротнага выкліку" }, "signedOutCallbackPath": { - "message": "Signed Out Callback Path" + "message": "Выйсці са шляху да зваротнага выкліку" }, "authority": { - "message": "Authority" + "message": "Аўтарызацыя" }, "clientId": { "message": "Ідэнт. кліента" @@ -4654,28 +4660,28 @@ "message": "Адрас метаданых" }, "oidcRedirectBehavior": { - "message": "OIDC Redirect Behavior" + "message": "Паводзіны перанакіравання OIDC" }, "getClaimsFromUserInfoEndpoint": { - "message": "Get claims from user info endpoint" + "message": "Атрымліваць патрабаванні ад канцавога пункту інфармацыі аб карыстальніку" }, "additionalScopes": { "message": "Карыстальніцкія вобласці" }, "additionalUserIdClaimTypes": { - "message": "Custom User ID Claim Types" + "message": "Тыпы патрабаванняў да ідэнтыфікатара карыстальніка" }, "additionalEmailClaimTypes": { "message": "Тыпы патрабаванняў электроннай пошты" }, "additionalNameClaimTypes": { - "message": "Custom Name Claim Types" + "message": "Тыпы патрабаванняў да імя карыстальніка" }, "acrValues": { "message": "Запытаныя значэнні спасылак класа кантэксту аўтэнтыфікацыі" }, "expectedReturnAcrValue": { - "message": "Expected \"acr\" Claim Value In Response" + "message": "Чакаецца значэнне запыту \"acr\" у адказе" }, "spEntityId": { "message": "ID аб'екта SP" @@ -4684,106 +4690,106 @@ "message": "URL-адрас метаданых SAML 2.0" }, "spAcsUrl": { - "message": "Assertion Consumer Service (ACS) URL" + "message": "URL-адрасы службы пацвярджэння кліентаў (ACS)" }, "spNameIdFormat": { "message": "Фармат ідэнтыфікатара назвы" }, "spOutboundSigningAlgorithm": { - "message": "Outbound Signing Algorithm" + "message": "Алгарытм выходнага подпісу" }, "spSigningBehavior": { "message": "Паводзіны пры падпісанні" }, "spMinIncomingSigningAlgorithm": { - "message": "Minimum Incoming Signing Algorithm" + "message": "Мінімальны алгарытм уваходнага подпісу" }, "spWantAssertionsSigned": { - "message": "Expect signed assertions" + "message": "Чакаецца подпіс пацвярджэнняў" }, "spValidateCertificates": { "message": "Праверка сертыфікатаў" }, "idpEntityId": { - "message": "Entity ID" + "message": "Ідэнтыфікатар аб'екта" }, "idpBindingType": { "message": "Тып прывязкі" }, "idpSingleSignOnServiceUrl": { - "message": "Single Sign On Service URL" + "message": "URL-службы адзінага ўваходу" }, "idpSingleLogoutServiceUrl": { - "message": "Single Log Out Service URL" + "message": "URL-службы адзінага выхаду" }, "idpX509PublicCert": { - "message": "X509 Public Certificate" + "message": "Публічны сертыфікат X509" }, "idpOutboundSigningAlgorithm": { - "message": "Outbound Signing Algorithm" + "message": "Алгарытм выходнага подпісу" }, "idpAllowUnsolicitedAuthnResponse": { "message": "Дазваляць непажаданы адказ аўтэнтыфікацыі" }, "idpAllowOutboundLogoutRequests": { - "message": "Allow outbound logout requests" + "message": "Дазваляць выходныя запыты для завяршэння сеансу" }, "idpSignAuthenticationRequests": { "message": "Падпісваць запыты аўтэнтыфікацыі" }, "ssoSettingsSaved": { - "message": "Single Sign-On configuration was saved." + "message": "Канфігурацыя адзінага ўваходу захавана." }, "sponsoredFamilies": { - "message": "Free Bitwarden Families" + "message": "Бясплатны тарыфны план Bitwarden Families" }, "sponsoredFamiliesEligible": { - "message": "You and your family are eligible for Free Bitwarden Families. Redeem with your personal email to keep your data secure even when you are not at work." + "message": "Вы і ваша сям'я маеце права на бясплатны тарыфны план Bitwarden Families. Актывуйце доступ з асабістай электроннай поштай, каб захаваць свае даныя ў бяспецы, нават калі вы не на працы." }, "sponsoredFamiliesEligibleCard": { - "message": "Redeem your Free Bitwarden for Families plan today to keep your data secure even when you are not at work." + "message": "Актывуйце сёння бясплатны тарыфны план Bitwarden Families, каб захаваць свае даныя ў бяспецы, нават калі вы не на працы." }, "sponsoredFamiliesInclude": { - "message": "The Bitwarden for Families plan include" + "message": "Тарыфны план Bitwarden Families уключае" }, "sponsoredFamiliesPremiumAccess": { - "message": "Premium access for up to 6 users" + "message": "Прэміяльны доступ, які абмяжоўваецца 6 карыстальнікамі" }, "sponsoredFamiliesSharedCollections": { - "message": "Shared collections for Family secrets" + "message": "Абагуленыя калекцыі для сямейных сакрэтаў" }, "badToken": { - "message": "The link is no longer valid. Please have the sponsor resend the offer." + "message": "Спасылка больш не дзейнічае. Калі ласка, папрасіце спонсара паўторна адправіць прапанову." }, "reclaimedFreePlan": { - "message": "Бясплатны план адноўлены" + "message": "Бясплатны тарыфны план адноўлены" }, "redeem": { "message": "Актываваць" }, "sponsoredFamiliesSelectOffer": { - "message": "Select the organization you would like sponsored" + "message": "Выберыце арганізацыю, якую хочаце спансіраваць" }, "familiesSponsoringOrgSelect": { - "message": "Which Free Families offer would you like to redeem?" + "message": "Якую бясплатную сямейную прапанову вы хочаце актываваць?" }, "sponsoredFamiliesEmail": { - "message": "Enter your personal email to redeem Bitwarden Families" + "message": "Увядзіце свой асабісты адрас электроннай пошты Bitwarden Families" }, "sponsoredFamiliesLeaveCopy": { - "message": "If you remove an offer or are removed from the sponsoring organization, your Families sponsorship will expire at the next renewal date." + "message": "Калі вы выдаліце прапанову або будзеце выключаны са спонсарскай арганізацыі, ваш доступ да тарыфнага плана Bitwarden Families завершыцца ў наступную дату падаўжэння." }, "acceptBitwardenFamiliesHelp": { - "message": "Accept offer for an existing organization or create a new Families organization." + "message": "Пагадзіцеся на прапанову для існуючай арганізацыі або стварыце новую сямейную арганізацыю." }, "setupSponsoredFamiliesLoginDesc": { - "message": "You've been offered a free Bitwarden Families Plan Organization. To continue, you need to log in to the account that received the offer." + "message": "Вам прапанаваны бясплатны тарыфны план Bitwarden Families ад арганізацыі. Для працягу, вам неабходна ўвайсці ва ўліковы запіс з якога вы атрымалі прапанову." }, "sponsoredFamiliesAcceptFailed": { - "message": "Unable to accept offer. Please resend the offer email from your enterprise account and try again." + "message": "Немагчыма праняць прапанову. Калі ласка, адпраўце прапанову на электронную пошту паўторна са свайго ўліковага запісу прадпрыемства." }, "sponsoredFamiliesAcceptFailedShort": { - "message": "Unable to accept offer. $DESCRIPTION$", + "message": "Немагчыма праняць прапанову. $DESCRIPTION$", "placeholders": { "description": { "content": "$1", @@ -4792,10 +4798,10 @@ } }, "sponsoredFamiliesOffer": { - "message": "Accept Free Bitwarden Families" + "message": "Прыняць бясплатна Bitwarden Families" }, "sponsoredFamiliesOfferRedeemed": { - "message": "Free Bitwarden Families offer successfully redeemed" + "message": "Прапанова на бясплатны тарыфны план Bitwarden Families паспяхова актывавана" }, "redeemed": { "message": "Актывавана" @@ -4813,7 +4819,7 @@ } }, "resendEmailLabel": { - "message": "Resend Sponsorship email to $NAME$ sponsorship", + "message": "Паўторна адправіць ліст пра спансіраванне карыстальніку $NAME$", "placeholders": { "name": { "content": "$1", @@ -4822,7 +4828,7 @@ } }, "freeFamiliesPlan": { - "message": "Бясплатны сямейны план" + "message": "Бясплатны тарыфны план Bitwarden Families" }, "redeemNow": { "message": "Актываваць зараз" @@ -4831,25 +4837,25 @@ "message": "Атрымальнік" }, "removeSponsorship": { - "message": "Выдаліць спонсара" + "message": "Выдаліць спансіраванне" }, "removeSponsorshipConfirmation": { - "message": "After removing a sponsorship, you will be responsible for this subscription and related invoices. Are you sure you want to continue?" + "message": "Пасля выдалення спонсарства, вы будзеце адказваць за гэту падпіску і звязаныя рахункі. Вы ўпэўнены, што хочаце працягнуць?" }, "sponsorshipCreated": { - "message": "Спонсар створаны" + "message": "Спансіраванне створана" }, "emailSent": { "message": "Ліст адпраўлены" }, "revokeSponsorshipConfirmation": { - "message": "After removing this account, the Families plan sponsorship will expire at the end of the billing period. You will not be able to redeem a new sponsorship offer until the existing one expires. Are you sure you want to continue?" + "message": "Пасля выдалення гэтага ўліковага запісу, спонсарства тарыфнага плана Bitwarden Families завяршыцца ў канцы плацежнага перыяду. У вас не будзе магчымасці скарыстацца новай спонсарскай прапановай, пакуль не завяршыцца тэрмін бягучай прапановы. Вы ўпэўнены, што хочаце працягнуць?" }, "removeSponsorshipSuccess": { - "message": "Спонсар выдалены" + "message": "Спансіраванне выдалена" }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Памылка Key Connector: пераканайцеся, што Key Connector даступны і карэктна працуе." }, "keyConnectorUrl": { "message": "URL-адрас Key Connector" @@ -4867,7 +4873,7 @@ "message": "Праверачны код" }, "confirmIdentity": { - "message": "Confirm your identity to continue." + "message": "Пацвердзіце сваю асобу для працягу." }, "verificationCodeRequired": { "message": "Патрабуецца праверачны код." @@ -4876,7 +4882,7 @@ "message": "Памылковы праверачны код" }, "convertOrganizationEncryptionDesc": { - "message": "$ORGANIZATION$ is using SSO with a self-hosted key server. A master password is no longer required to log in for members of this organization.", + "message": "$ORGANIZATION$ выкарыстоўвае SSO з уласным серверам ключоў. Асноўны пароль для ўдзельнікаў гэтай арганізацыі больш не патрабуецца.", "placeholders": { "organization": { "content": "$1", @@ -4885,13 +4891,13 @@ } }, "leaveOrganization": { - "message": "Пакінуць арганізацыю" + "message": "Выйсці з арганізацыі" }, "removeMasterPassword": { - "message": "Remove Master Password" + "message": "Выдаліць асноўны пароль" }, "removedMasterPassword": { - "message": "Master password removed." + "message": "Асноўны пароль выдалены." }, "allowSso": { "message": "Дазволіць аўтэнтыфікацыю SSO" @@ -4915,19 +4921,19 @@ "message": "Для наладжвання расшыфроўкі Key Connector неабходна палітыка аўтэнтыфікацыі SSO і адзінай арганізацыі." }, "memberDecryptionOption": { - "message": "Member Decryption Options" + "message": "Параметры расшыфроўкі ўдзельніка" }, "memberDecryptionPassDesc": { - "message": "Once authenticated, members will decrypt vault data using their Master Passwords." + "message": "Пасля аўтэнтыфікацыі ўдзельнікі будуць расшыфроўваць даныя сховішча з выкарыстаннем сваіх асноўных пароляў." }, "keyConnector": { "message": "Key Connector" }, "memberDecryptionKeyConnectorDesc": { - "message": "Connect Login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their Master Passwords to decrypt vault data. Contact Bitwarden Support for set up assistance." + "message": "Падключыце аўтарызацыю з дапамогай SSO да свайго ўласнага сервера расшыфроўкі ключоў. Пры дапамозе гэтага параметра ўдзельнікам больш непатрэбна будзе выкарыстоўваць свае асноўныя паролі для расшыфроўкі даных сховішча. Звярніцеся ў службу падтрымкі, каб атрымаць дапамогу з наладжваннем." }, "keyConnectorPolicyRestriction": { - "message": "\"Login with SSO and Key Connector Decryption\" is enabled. This policy will only apply to Owners and Admins." + "message": "\"Уваход з дапамогай SSO і расшыфроўкай Key Connector\" уключаны. Гэта палітыка распаўсюджваецца толькі на ўладальнікаў і адміністратараў." }, "enabledSso": { "message": "SSO уключана" @@ -4939,58 +4945,58 @@ "message": "Key Connector уключаны" }, "disabledKeyConnector": { - "message": "Disabled Key Connector" + "message": "Key Connector адключаны" }, "keyConnectorWarning": { - "message": "Once members begin using Key Connector, your Organization cannot revert to Master Password decryption. Proceed only if you are comfortable deploying and managing a key server." + "message": "Пасля таго, як удзельнікі пачнуць выкарыстоўваць Key Connector, ваша арганізацыя не зможа вярнуцца да расшыфроўкі з асноўным паролем. Працягвайце толькі калі вы гатовы разгарнуць сервер ключоў і кіраваць ім." }, "migratedKeyConnector": { - "message": "Migrated to Key Connector" + "message": "Выканана міграцыя на Key Connector" }, "paymentSponsored": { - "message": "Please provide a payment method to associate with the organization. Don't worry, we won't charge you anything unless you select additional features or your sponsorship expires. " + "message": "Калі ласка, забяспечце спосаб аплаты для звязанай арганізацыі. Не хвалюйцеся, мы нічога не будзем спаганяць з вас, калі вы не выберыце дадатковыя функцыі або ваша спонсарская прапанова не будзе пратэрмінавана. " }, "orgCreatedSponsorshipInvalid": { - "message": "The sponsorship offer has expired. You may delete the organization you created to avoid a charge at the end of your 7 day trial. Otherwise you may close this prompt to keep the organization and assume billing responsibility." + "message": "Спонсарская прапанова пратэрмінавана. Вы можаце выдаліць створаную арганізацыю, каб пазбегнуць спагнання грашовых сродкаў пасля завяршэння 7-дзённага выпрабавальнага перыяду. У адваротным выпадку вы можаце закрыць гэта апавяшчэнне і ўзяць на сябе плацежныя абавязкі." }, "newFamiliesOrganization": { - "message": "New Families Organization" + "message": "Новая сямейная арганізацыя" }, "acceptOffer": { "message": "Прыняць прапанову" }, "sponsoringOrg": { - "message": "Sponsoring Organization" + "message": "Спонсарская арганізацыя" }, "keyConnectorTest": { "message": "Тэст" }, "keyConnectorTestSuccess": { - "message": "Success! Key Connector reached." + "message": "Паспяхова! Key Connector падлучаны." }, "keyConnectorTestFail": { - "message": "Cannot reach Key Connector. Check URL." + "message": "Немагчыма падлучыцца да Key Connector. Праверце URL-адрас." }, "sponsorshipTokenHasExpired": { - "message": "The sponsorship offer has expired." + "message": "Тэрмін дзеяння спонсарскай прапановы пратэрмінаваны." }, "freeWithSponsorship": { - "message": "БЯСПЛАТНА дзякуючы спонсару" + "message": "БЯСПЛАТНА дзякуючы спонсарству" }, "viewBillingSyncToken": { - "message": "View Billing Sync Token" + "message": "Прагледзець плацежны токен сінхранізацыі" }, "generateBillingSyncToken": { - "message": "Generate Billing Sync Token" + "message": "Генерыраваць плацежны токен сінхранізацыі" }, "copyPasteBillingSync": { - "message": "Copy and paste this token into the Billing Sync settings of your self-hosted organization." + "message": "Скапіюйце і ўстаўце гэты токен у налады плацежнай сінхранізацыі сваёй уласнай размешчанай арганізацыі." }, "billingSyncCanAccess": { - "message": "Your Billing Sync token can access and edit this organization's subscription settings." + "message": "Ваш токен плацежнай сінхранізацыі можа атрымаць доступ і адрэдагаваць налады падпіскі гэтай арганізацыі." }, "manageBillingSync": { - "message": "Кіраваць плацежнай сінхранізацыяй" + "message": "Кіраванне плацежнай сінхранізацыяй" }, "setUpBillingSync": { "message": "Наладзіць плацежную сінхранізацыю" @@ -5002,16 +5008,16 @@ "message": "Змяніць токен" }, "rotateBillingSyncTokenWarning": { - "message": "If you proceed, you will need to re-setup billing sync on your self-hosted server." + "message": "Калі вы працягніце, вам будзе неабходна паўторна наладзіць плацежную сінхранізацыю на вашым серверы." }, "rotateBillingSyncTokenTitle": { - "message": "Rotating the Billing Sync Token will invalidate the previous token." + "message": "Змяненне токена плацежнай сінхранізацыі прывядзе да скасавання папярэдняга токена." }, "selfHostingTitle": { "message": "Уласнае размяшчэнне" }, "selfHostingEnterpriseOrganizationSectionCopy": { - "message": "To set-up your organization on your own server, you will need to upload your license file. To support Free Families plans and advanced billing capabilities for your self-hosted organization, you will need to set up billing sync." + "message": "Для наладжвання арганізацыі на вашым уласным серверы, вам неабходна будзе загрузіць файл з ліцэнзіяй. Для падтрымкі тарыфных планаў Bitwarden Families і пашыраных магчымасцей выстаўлення рахункаў для вашай арганізацыі, вам неабходна наладзіць плацежную сінхранізацыю." }, "billingSyncApiKeyRotated": { "message": "Токен зменены." @@ -5020,10 +5026,10 @@ "message": "Плацежная сінхранізацыя" }, "billingSyncDesc": { - "message": "Billing Sync provides Free Families plans for members and advanced billing capabilities by linking your self-hosted Bitwarden to the Bitwarden cloud server." + "message": "Плацежная сінхранізацыя дае магчымасць удзельнікам атрымаць бясплатны тарыфны план Bitwarden Families і пашыраныя магчымасці выстаўлення рахункаў звязваючы ваш уласны сервер Bitwarden з воблачным серверам нашай кампаніі." }, "billingSyncKeyDesc": { - "message": "A Billing Sync Token from your cloud organization's subscription settings is required to complete this form." + "message": "Для запаўнення гэтай формы неабходны токен плацежнай сінхранізацыі з наладаў падпіскі арганізацыі ў воблачным сховішчы." }, "billingSyncKey": { "message": "Токен плацежнай сінхранізацыі" @@ -5041,13 +5047,13 @@ "message": "Адпраўлена" }, "requestRemoved": { - "message": "Removed (Awaiting Sync)" + "message": "Выдалены (чакаецца сінхранізацыя)" }, "requested": { "message": "Запытана" }, "formErrorSummaryPlural": { - "message": "$COUNT$ fields above need your attention.", + "message": "$COUNT$ поле вышэй патрабуе вашай увагі.", "placeholders": { "count": { "content": "$1", @@ -5068,7 +5074,7 @@ } }, "required": { - "message": "абавязкова" + "message": "патрабуецца" }, "idpSingleSignOnServiceUrlRequired": { "message": "Патрабуецца, калі ідэнтыфікатар аб'екта не з'яўляецца URL-адрасам." @@ -5077,22 +5083,22 @@ "message": "Дадатковыя дапасаванні" }, "openIdAuthorityRequired": { - "message": "Required if Authority is not valid." + "message": "Патрабуецца, калі ўстанова не дзейнічае." }, "separateMultipleWithComma": { - "message": "Separate multiple with a comma." + "message": "Некалькі значэнняў, якія раздзелены коскай." }, "sessionTimeout": { - "message": "Your session has timed out. Please go back and try logging in again." + "message": "Час чакання вашага сеанса завяршыўся. Калі ласка, увайдзіце паўторна." }, "exportingPersonalVaultTitle": { - "message": "Exporting Personal Vault" + "message": "Экспартаванне асабістага сховішча" }, "exportingOrganizationVaultTitle": { - "message": "Exporting Organization Vault" + "message": "Экспартаванне сховішча арганізацыі" }, "exportingPersonalVaultDescription": { - "message": "Only the personal vault items associated with $EMAIL$ will be exported. Organization vault items will not be included.", + "message": "Будуць экспартаваны толькі асабістыя элементы сховішча, якія звязаны з $EMAIL$. Элементы сховішча арганізацыі не будуць уключаны.", "placeholders": { "email": { "content": "$1", @@ -5101,7 +5107,7 @@ } }, "exportingOrganizationVaultDescription": { - "message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Personal vault items and items from other organizations will not be included.", + "message": "Будуць экспартаваны толькі запісы сховішча арганізацыі, якія звязаны з $ORGANIZATION$. Элементы асабістага сховішча і элементы з іншых арганізацый не будуць уключаны.", "placeholders": { "organization": { "content": "$1", @@ -5110,7 +5116,7 @@ } }, "accessDenied": { - "message": "Access Denied. You do not have permission to view this page." + "message": "Доступ забаронены. У вас не дастаткова правоў для прагляду гэтай старонкі." }, "masterPassword": { "message": "Асноўны пароль" @@ -5125,7 +5131,7 @@ "message": "Гісторыя плацяжоў" }, "backToReports": { - "message": "Back to Reports" + "message": "Вярнуцца да справаздач" }, "organizationPicker": { "message": "Выбар арганізацыі" @@ -5141,7 +5147,7 @@ "message": "Генератар" }, "whatWouldYouLikeToGenerate": { - "message": "What would you like to generate?" + "message": "Што вы хочаце генерыраваць?" }, "passwordType": { "message": "Тып пароля" @@ -5160,13 +5166,13 @@ "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { - "message": "Use your email provider's sub-addressing capabilities." + "message": "Выкарыстоўвайце магчымасці пададрасацыі вашага пастаўшчыка паслуг электроннай пошты." }, "catchallEmail": { - "message": "Catch-all Email" + "message": "Адрас для ўсёй пошты дамена" }, "catchallEmailDesc": { - "message": "Use your domain's configured catch-all inbox." + "message": "Выкарыстоўвайце сваю сканфігураваную скрыню для ўсёй пошты дамена." }, "random": { "message": "Выпадкова", @@ -5179,10 +5185,10 @@ "message": "Сэрвіс" }, "unknownCipher": { - "message": "Unknown Item, you may need to request permission to access this item." + "message": "Невядомы элемент. Магчыма, што вам неабходна запытаць дазвол на доступ да гэтага элемента." }, "cannotSponsorSelf": { - "message": "You cannot redeem for the active account. Enter a different email." + "message": "Вы не можаце актываваць бягучы ўліковы запіс. Увядзіце іншы адрас электроннай пошты." }, "revokeWhenExpired": { "message": "Міне $DATE$", @@ -5194,7 +5200,7 @@ } }, "awaitingSyncSingular": { - "message": "Token rotated $DAYS$ day ago. Update the billing sync token in your self-hosted organization settings.", + "message": "Токен зменены $DAYS$ дзень таму. Абнавіце токен плацежнай сінхранізацыі ў наладах уласнай размешчанай арганізацыі.", "placeholders": { "days": { "content": "$1", @@ -5203,7 +5209,7 @@ } }, "awaitingSyncPlural": { - "message": "Token rotated $DAYS$ days ago. Update the billing sync token in your self-hosted organization settings.", + "message": "Токен зменены $DAYS$ дні/дзён таму. Абнавіце токен плацежнай сінхранізацыі ў наладах уласнай размешчанай арганізацыі.", "placeholders": { "days": { "content": "$1", @@ -5216,7 +5222,7 @@ "Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\"" }, "sponsorshipsSynced": { - "message": "Self-hosted sponsorships synced." + "message": "Уласнае размяшчэнне спансіравання сінхранізавана." }, "billingManagedByProvider": { "message": "Кіруецца $PROVIDER$", @@ -5273,7 +5279,7 @@ "description": "The text, 'SCIM', is an acronymn and should not be translated." }, "scimDescription": { - "message": "Аўтаматычна забяспечваць карыстальнікаў і групы пажаданымі пасведчаннямі пастаўшчыка праз забеспячэнне SCIM", + "message": "Аўтаматычна забяспечваць карыстальнікаў і групы пажаданымі пасведчаннямі пастаўшчыка праз SCIM", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimEnabledCheckboxDesc": { @@ -5285,18 +5291,18 @@ "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimApiKeyHelperText": { - "message": "This API key has access to manage users within your organization. It should be kept secret." + "message": "Гэты ключ API мае доступ да кіравання карыстальнікаў у межах вашай арганізацыі. Яго неабходна захоўваць у надзейным месцы." }, "copyScimKey": { - "message": "Copy the SCIM API Key to your clipboard", + "message": "Скапіяваць ключ API для SCIM у буфер абмену", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateScimKey": { - "message": "Rotate the SCIM API Key", + "message": "Змяніць ключ API для SCIM", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateScimKeyWarning": { - "message": "Are you sure you want to rotate the SCIM API Key? The current key will no longer work for any existing integrations.", + "message": "Вы ўпэўнены, што хочаце змяніць ключ API для SCIM? Бягучы ключ не будзе больш працаваць для любых бягучых інтэграцый.", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateKey": { @@ -5307,7 +5313,7 @@ "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "copyScimUrl": { - "message": "Copy the SCIM endpoint URL to your clipboard", + "message": "Скапіяваць SCIM канцавога пункту URL-адраса ў ваш буфер абмену", "description": "the text, 'SCIM' and 'URL', are acronymns and should not be translated." }, "scimUrl": { @@ -5315,21 +5321,21 @@ "description": "the text, 'SCIM' and 'URL', are acronymns and should not be translated." }, "scimApiKeyRotated": { - "message": "The SCIM API Key has been successfully rotated", + "message": "Ключ API для SCIM быў паспяхова зменены", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "scimSettingsSaved": { - "message": "SCIM settings have been saved successfully", + "message": "Налады SCIM былі паспяхова захаваны", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "inputRequired": { "message": "Неабходны ўвод даных." }, "inputEmail": { - "message": "Input is not an email-address." + "message": "Уведзеныя даныя не з'яўляюцца адрасам электроннай пошты." }, "inputMinLength": { - "message": "Input must be at least $COUNT$ characters long.", + "message": "Даўжыня ўведзеных даных павінна складаць прынамсі $COUNT$ сімв.", "placeholders": { "count": { "content": "$1", @@ -5338,7 +5344,7 @@ } }, "fieldsNeedAttention": { - "message": "$COUNT$ field(s) above need your attention.", + "message": "$COUNT$ полі(-ёў) вышэй патрабуе вашай увагі.", "placeholders": { "count": { "content": "$1", diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 419ace835ea..200a343abaf 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -2257,7 +2257,7 @@ "message": "Годишно" }, "annual": { - "message": "Annual" + "message": "Годишно" }, "basePrice": { "message": "Базова цена" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Права" }, + "managerPermissions": { + "message": "Права на управителя" + }, + "adminPermissions": { + "message": "Права на администратора" + }, "accessEventLogs": { "message": "Достъп до журналите" }, diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index d3e7a5f6a1d..837c9cf7190 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index fbc629ef7fe..2f14bb380f0 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 08cc2b165f2..953e79fbf13 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permisos" }, + "managerPermissions": { + "message": "Permisos de l'administrador" + }, + "adminPermissions": { + "message": "Permisos de l'administrador" + }, "accessEventLogs": { "message": "Registres d'esdeveniments dels accessos" }, diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index 2e18e2c5923..3bba318dd47 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Oprávnění" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Přístup k logům" }, diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index c2a64d74c91..67fdbc44188 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -912,10 +912,10 @@ "message": "Bekræft filadgangskode" }, "accountBackupOptionDescription": { - "message": "Udnytter din Bitwarden-kontokryptering, ikke hovedadgangskode, for at beskytte eksporten. Denne eksport kan kun importeres til den aktuelle konto. Brug denne til at oprette en sikkerhedskopi, der ikke kan bruges andre steder." + "message": "Brug din kontos krypteringsnøgle til at kryptere eksporten og begrænse importen til udelukkende den aktuelle Bitwarden-konto." }, "passwordProtectedOptionDescription": { - "message": "Opret en brugergenereret adgangskode for at beskytte eksporten. Brug denne til at oprette en eksport, der kan bruges via andre konti." + "message": "Opret en adgangskode til at kryptere eksporten og importér den til enhver Bitwarden-konto ved hjælp af adgangskoden til dekryptering." }, "fileTypeHeading": { "message": "Filtype" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Tilladelser" }, + "managerPermissions": { + "message": "Håndtér rettigheder" + }, + "adminPermissions": { + "message": "Admin-tilladelser" + }, "accessEventLogs": { "message": "Tilgå begivenhedslogger" }, diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index a31fb03b2f2..a00359ce98c 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -679,7 +679,7 @@ "message": "Ungültiges Master-Passwort" }, "invalidFilePassword": { - "message": "Ungültiges Dateipasswort, bitte verwende das Passwort, das du beim Erstellen der Exportdatei eingegeben hast." + "message": "Ungültiges Dateipasswort. Bitte verwende das Passwort, das du beim Erstellen der Exportdatei eingegeben hast." }, "lockNow": { "message": "Jetzt sperren" @@ -912,10 +912,10 @@ "message": "Dateipasswort bestätigen" }, "accountBackupOptionDescription": { - "message": "Nutzt die Verschlüsselung Ihres Bitwarden-Kontos, nicht das Master-Passwort, zum Schutz des Exports. Dieser Export kann nur in das aktuelle Konto importiert werden. Hiermit kannst du ein Backup erstellen, das nicht anderweitig verwendet werden kann." + "message": "Nutze den Verschlüsselungscode deines Kontos, um den Export zu verschlüsseln und den Import allein auf das aktuelle Bitwarden-Konto zu beschränken." }, "passwordProtectedOptionDescription": { - "message": "Erstelle ein benutzergeneriertes Passwort, um den Export zu schützen. Verwende dies, um einen Export zu erstellen, der in anderen Konten verwendet werden kann." + "message": "Lege ein Passwort fest, um den Export zu verschlüsseln und ihn in ein beliebiges Bitwarden-Konto zu importieren, wobei das Passwort zum Entschlüsseln genutzt wird." }, "fileTypeHeading": { "message": "Dateityp" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Berechtigungen" }, + "managerPermissions": { + "message": "Manager-Berechtigungen" + }, + "adminPermissions": { + "message": "Administrator-Berechtigungen" + }, "accessEventLogs": { "message": "Zugriff auf Ereignisprotokolle" }, diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index a8324937f85..b8ac7e6c385 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -918,7 +918,7 @@ "message": "Set a password to encrypt the export and import it to any Bitwarden account using the password for decryption." }, "fileTypeHeading": { - "message": "File Type" + "message": "Τύπος αρχείου" }, "accountBackup": { "message": "Account Backup" @@ -1721,7 +1721,7 @@ "message": "Billing Plan" }, "paymentType": { - "message": "Payment Type" + "message": "Τύπος πληρωμής" }, "accountCredit": { "message": "Λογαριασμός Πίστωσης", @@ -4057,6 +4057,12 @@ "permissions": { "message": "Άδειες" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Αρχείο Καταγραφής Πρόσβασης" }, @@ -4424,10 +4430,10 @@ "message": "Αφαίρεση Χρηστών" }, "revokeUsers": { - "message": "Revoke Users" + "message": "Ανάκληση χρηστών" }, "restoreUsers": { - "message": "Restore Users" + "message": "Επαναφορά χρηστών" }, "error": { "message": "Σφάλμα" @@ -5116,13 +5122,13 @@ "message": "Master Password" }, "security": { - "message": "Security" + "message": "Ασφάλεια" }, "keys": { - "message": "Keys" + "message": "Κλειδιά" }, "billingHistory": { - "message": "Billing History" + "message": "Ιστορικό χρέωσης" }, "backToReports": { "message": "Επιστροφή στις Αναφορές" @@ -5135,7 +5141,7 @@ "description": "This is used by screen readers to indicate the organization that is currently being shown to the user." }, "accountSettings": { - "message": "Account Settings" + "message": "Ρυθμίσεις λογαριασμού" }, "generator": { "message": "Γεννήτρια" @@ -5303,7 +5309,7 @@ "message": "Rotate Key" }, "scimApiKey": { - "message": "SCIM API Key", + "message": "Κλειδί API SCIM", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "copyScimUrl": { @@ -5347,7 +5353,7 @@ } }, "turnOn": { - "message": "Turn on" + "message": "Ενεργοποίηση" }, "on": { "message": "On" diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 79269935aee..d4231a4aed7 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -569,15 +569,27 @@ "loginOrCreateNewAccount": { "message": "Log in or create a new account to access your secure vault." }, + "loginWithDevice" : { + "message": "Log in with device" + }, + "loginWithDeviceEnabledInfo": { + "message": "Log in with device must be enabled in the settings of the Bitwarden mobile app. Need another option?" + }, "createAccount": { "message": "Create Account" }, + "newAroundHere": { + "message": "New around here?" + }, "startTrial": { "message": "Start Trial" }, "logIn": { "message": "Log In" }, + "logInInitiated": { + "message": "Log in initiated" + }, "submit": { "message": "Submit" }, @@ -635,7 +647,7 @@ "confirmMasterPasswordRequired": { "message": "Master password retype is required." }, - "masterPasswordMinLength": { + "masterPasswordMinlength": { "message": "Master password must be at least 8 characters long." }, "masterPassDoesntMatch": { @@ -705,6 +717,9 @@ "noOrganizationsList": { "message": "You do not belong to any organizations. Organizations allow you to securely share items with other users." }, + "notificationSentDevice":{ + "message": "A notification has been sent to your device." + }, "versionNumber": { "message": "Version $VERSION_NUMBER$", "placeholders": { @@ -1273,11 +1288,24 @@ "twoStepLogin": { "message": "Two-step login" }, + "twoStepLoginEnforcement": { + "message": "Two-step Login Enforcement" + }, "twoStepLoginDesc": { "message": "Secure your account by requiring an additional step when logging in." }, - "twoStepLoginOrganizationDesc": { - "message": "Require two-step login for your organization's users by configuring providers at the organization level." + "twoStepLoginOrganizationDescStart": { + "message": "Enforce Bitwarden Two-step Login options for members by using the ", + "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Enforce Bitwarden Two-step Login options for members by using the Two-step Login Policy.'" + }, + "twoStepLoginPolicy": { + "message": "Two-step Login Policy" + }, + "twoStepLoginOrganizationDuoDesc": { + "message": "To enforce Two-step Login through Duo, use the options below." + }, + "twoStepLoginOrganizationSsoDesc": { + "message": "If you have setup SSO or plan to, Two-step Login may already be enforced through your Identity Provider." }, "twoStepLoginRecoveryWarning": { "message": "Enabling two-step login can permanently lock you out of your Bitwarden account. A recovery code allows you to access your account in the event that you can no longer use your normal two-step login provider (ex. you lose your device). Bitwarden support will not be able to assist you if you lose access to your account. We recommend you write down or print the recovery code and keep it in a safe place." @@ -2545,6 +2573,9 @@ } } }, + "viewAllLoginOptions": { + "message": "View all log in options" + }, "viewedItemId": { "message": "Viewed item $ID$.", "placeholders": { @@ -3397,6 +3428,12 @@ "message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." }, + "fingerprintMatchInfo": { + "message": "Please make sure your vault is unlocked and Fingerprint phrase matches the other device." + }, + "fingerprintPhraseHeader": { + "message": "Fingerprint phrase" + }, "dontAskFingerprintAgain": { "message": "Never prompt to verify fingerprint phrases for invited users (Not recommended)", "description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing." @@ -3681,6 +3718,12 @@ "ssoIdentifierRequired": { "message": "Organization Identifier is required." }, + "ssoIdentifier": { + "message": "SSO Identifier" + }, + "ssoIdentifierHint": { + "message": "Provide this ID to your members to login with SSO." + }, "unlinkSso": { "message": "Unlink SSO" }, @@ -4026,7 +4069,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disableSendExemption": { - "message": "Organization users that can manage the organization's policies are exempt from this policy's enforcement." + "message": "Organization members that can manage the organization's policies are exempt from this policy's enforcement." }, "sendDisabled": { "message": "Send disabled", @@ -4045,7 +4088,7 @@ "description": "'Sends' is a plural noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptionsExemption": { - "message": "Organization users that can manage the organization's policies are exempt from this policy's enforcement." + "message": "Organization members that can manage the organization's policies are exempt from this policy's enforcement." }, "disableHideEmail": { "message": "Always show member’s email address with recipients when creating or editing a send.", @@ -4082,6 +4125,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, @@ -4350,19 +4399,19 @@ "message": "Allow admins to reset master passwords for members." }, "resetPasswordPolicyWarning": { - "message": "Users in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password." + "message": "Members in the organization will need to self-enroll or be auto-enrolled before administrators can reset their master password." }, "resetPasswordPolicyAutoEnroll": { "message": "Automatic Enrollment" }, "resetPasswordPolicyAutoEnrollDescription": { - "message": "All users will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw." + "message": "All members will be automatically enrolled in password reset once their invite is accepted and will not be allowed to withdraw." }, "resetPasswordPolicyAutoEnrollWarning": { - "message": "Users already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password." + "message": "Members already in the organization will not be retroactively enrolled in password reset. They will need to self-enroll before administrators can reset their master password." }, "resetPasswordPolicyAutoEnrollCheckbox": { - "message": "Require new users to be enrolled automatically" + "message": "Require new members to be enrolled automatically" }, "resetPasswordAutoEnrollInviteWarning": { "message": "This organization has an enterprise policy that will automatically enroll you in password reset. Enrollment will allow organization administrators to change your master password." @@ -4391,6 +4440,9 @@ "reinviteSelected": { "message": "Resend Invitations" }, + "resendNotification": { + "message": "Resend notification" + }, "noSelectedUsersApplicable": { "message": "This action is not applicable to any of the selected users." }, @@ -5362,6 +5414,15 @@ } } }, + "inputMaxLength": { + "message": "Input must not exceed $COUNT$ characters in length.", + "placeholders": { + "count": { + "content": "$1", + "example": "20" + } + } + }, "fieldsNeedAttention": { "message": "$COUNT$ field(s) above need your attention.", "placeholders": { diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index b9a10e569b0..3f7beb72d16 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -912,10 +912,10 @@ "message": "Confirm File Password" }, "accountBackupOptionDescription": { - "message": "Leverages your Bitwarden account encryption, not master password, to protect the export. This export can only be imported into the current account. Use this to create a backup that cannot be used elsewhere." + "message": "Use your account encryption key to encrypt the export and restrict import to only the current Bitwarden account." }, "passwordProtectedOptionDescription": { - "message": "Create a user-generated password to protect the export. Use this to create an export that can be used in other accounts." + "message": "Set a password to encrypt the export and import it to any Bitwarden account using the password for decryption." }, "fileTypeHeading": { "message": "File Type" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 14a07c48e2d..939d41b015d 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 327bc12f086..960cb3250e7 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permesoj" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Aliri Eventajn Registrojn" }, diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index 2ec91552fd3..062e7326340 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permisos" }, + "managerPermissions": { + "message": "Permisos del Administrador" + }, + "adminPermissions": { + "message": "Permisos del administrador" + }, "accessEventLogs": { "message": "Acceder a los registros de eventos" }, @@ -4729,7 +4735,7 @@ "message": "Permitir peticiones de cierre de sesión" }, "idpSignAuthenticationRequests": { - "message": "Sign authentication requests" + "message": "Solicitud de inicio de sesión" }, "ssoSettingsSaved": { "message": "Single Sign-On configuration was saved." @@ -4771,13 +4777,13 @@ "message": "Enter your personal email to redeem Bitwarden Families" }, "sponsoredFamiliesLeaveCopy": { - "message": "If you remove an offer or are removed from the sponsoring organization, your Families sponsorship will expire at the next renewal date." + "message": "Si eliminas una oferta o la eliminas de la organización patrocinadora, el patrocinio de tu familia caducará en la próxima fecha de renovación." }, "acceptBitwardenFamiliesHelp": { - "message": "Accept offer for an existing organization or create a new Families organization." + "message": "Aceptar oferta para una organización existente o crear una nueva organización familiar." }, "setupSponsoredFamiliesLoginDesc": { - "message": "You've been offered a free Bitwarden Families Plan Organization. To continue, you need to log in to the account that received the offer." + "message": "Se le ha ofrecido una organización gratuita del Plan de Familias Bitwarden. Para continuar, necesita iniciar sesión en la cuenta que recibió la oferta." }, "sponsoredFamiliesAcceptFailed": { "message": "No se puede aceptar la oferta. Por favor, reenvíe el correo electrónico de la oferta desde su cuenta de empresa e inténtelo de nuevo." @@ -4984,10 +4990,10 @@ "message": "Generar el token de sincronización de facturación" }, "copyPasteBillingSync": { - "message": "Copy and paste this token into the Billing Sync settings of your self-hosted organization." + "message": "Copia y pega este token en la configuración de la sincronización de facturación de tu propia organización." }, "billingSyncCanAccess": { - "message": "Your Billing Sync token can access and edit this organization's subscription settings." + "message": "Su token de sincronización de facturación puede acceder y editar la configuración de suscripción de esta organización." }, "manageBillingSync": { "message": "Administrar la sincronización de facturación" @@ -5002,10 +5008,10 @@ "message": "Regenerar token" }, "rotateBillingSyncTokenWarning": { - "message": "If you proceed, you will need to re-setup billing sync on your self-hosted server." + "message": "Si continúa, necesitará reconfigurar la sincronización de facturación en su servidor autoalojado." }, "rotateBillingSyncTokenTitle": { - "message": "Rotating the Billing Sync Token will invalidate the previous token." + "message": "Rotar el token de sincronización de facturación invalidará el token anterior." }, "selfHostingTitle": { "message": "Autoalojamiento" diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index 542914b221d..f4242fe946d 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Õigused" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Ligipääs sündmuste logile" }, diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index d9eca7116d4..467f257db3d 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -425,7 +425,7 @@ "message": "Ni" }, "myVault": { - "message": "Nire Kutxa Gotorra" + "message": "Kutxa Gotorra" }, "allVaults": { "message": "Kutxa Gotor guztiak" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Baimenak" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Sarreren erregistroak" }, diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 370a51952ab..5bd081806c6 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -2248,7 +2248,7 @@ } }, "trialConfirmationEmail": { - "message": "Olemme lähettäneet vahvistusviestin tiimisi laskutussähköpostiosoitteeseen " + "message": "Olemme lähettäneet sähköpostivahvistuksen tiimisi laskutusoitteeseen " }, "monthly": { "message": "Kuukausittainen" @@ -2326,10 +2326,10 @@ "message": "Haluatko varmasti poistaa käyttäjän?" }, "removeOrgUserConfirmation": { - "message": "Kun jäsen poistetaan, hänellä ei ole enää pääsyä organisaation tietoihin, eikä poistoa ole mahdollista perua. Jos haluat lisätä jäsenen takaisin organisaatioon, hänet on kutsuttava ja perehdytettävä uudelleen." + "message": "Poisteltulla jäsenellä ei ole enää organisaation tietojen käyttöoikeutta, eikä poiston peruminen ole mahdollista. Jos jäsen halutaan palauttaa organisaatioon, hänet on kutsuttava ja määritettävä uudelleen." }, "revokeUserConfirmation": { - "message": "Kun jäsenen käyttöoikeus perutaan, hänellä ei ole enää pääsyä organisaation tietoihin. Voit palauttaa käyttöoikeuden nopeasti Perutut-välilehdeltä." + "message": "Perutulla jäsenellä ei ole enää organisaation tietojen käyttöoikeutta. Käyttöoikeus voidaan palauttaa nopeasti Perutut-välilehdeltä." }, "removeUserConfirmationKeyConnector": { "message": "Varoitus! Tämä käyttäjä tarvitsee salauksensa hallintaan Key Connectoria. Käyttäjän poistaminen organisaatiostasi poistaa heidän tilinsä käytöstä pysvästi. Toimenpide on pysyvä, eikä sen peruminen ole mahdollista. Haluatko jatkaa?" @@ -2395,10 +2395,10 @@ "message": "Hae" }, "invited": { - "message": "Kutsuttu" + "message": "Kutsutut" }, "accepted": { - "message": "Hyväksytty" + "message": "Hyväksytyt" }, "confirmed": { "message": "Vahvistettu" @@ -2686,7 +2686,7 @@ } }, "revokedUserId": { - "message": "Jäsenen $ID$ organisaation käyttöoikeus peruttiin.", + "message": "Käyttäjän $ID$ organisaation käyttöoikeus on peruttu.", "placeholders": { "id": { "content": "$1", @@ -2704,7 +2704,7 @@ } }, "revokeUserId": { - "message": "Peru jäsenen $ID$ käyttöoikeus", + "message": "Peru käyttäjän $ID$ käyttöoikeus", "placeholders": { "id": { "content": "$1", @@ -4023,7 +4023,7 @@ "message": "Käytäntöä ei pakoteta käyttöön niille organisaation käyttäjille, joilla on organisaation käytäntöjen hallintaoikeudet." }, "disableHideEmail": { - "message": "Näytä jäsenen sähköpostiosoite aina vastaanottajien kanssa, kun luodaan tai muokataan Sendiä.", + "message": "Näytä jäsenen sähköpostiosoite aina vastaanottajien ohessa, kun Send luodaan tai sitä muokataan.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "sendOptionsPolicyInEffect": { @@ -4057,6 +4057,12 @@ "permissions": { "message": "Käyttöoikeudet" }, + "managerPermissions": { + "message": "Valvojan oikeudet" + }, + "adminPermissions": { + "message": "Ylläpitäjän oikeudet" + }, "accessEventLogs": { "message": "Tapahtumalokien käyttö" }, @@ -4370,13 +4376,13 @@ "message": "Toiminto ei koske valittuja käyttäjiä." }, "removeUsersWarning": { - "message": "Haluatko varmasti poistaa seuraavat käyttäjät? Toiminto saattaa kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." + "message": "Haluatko varmasti poistaa seuraavat käyttäjät? Käsittely voi kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." }, "removeOrgUsersConfirmation": { - "message": "Kun jäseniä poistetaan, heillä ei ole enää pääsyä organisaation tietoihin, eikä poistoa ole mahdollista perua. Jos haluat lisätä jäsenen takaisin organisaatioon, hänet on kutsuttava ja perehdytettävä uudelleen. Käsittely voi kestää muutamia sekunteja, eikä sitä ole mahdollista keskeyttää tai perua." + "message": "Poisteltuilla jäsenillä ei ole enää organisaation tietojen käyttöoikeutta, eikä poiston peruminen ole mahdollista. Jos jäsniä halutaan palauttaa organisaatioon, heidät on kutsuttava ja määritettävä uudelleen. Käsittely voi kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." }, "revokeUsersWarning": { - "message": "Kun jäsenien käyttöoikeudet perutaan, heillä ei ole enää pääsyä organisaation tietoihin. Voit palauttaa käyttöoikeudet nopeasti Perutut-välilehdeltä. Käsittely voi kestää muutamia sekunteja, eikä sitä ole mahdollista keskeyttää tai perua." + "message": "Perutuilla jäsenillä ei ole enää organisaation tietojen käyttöoikeutta. Käyttöoikeudet voidaan palauttaa nopeasti Perutut-välilehdeltä. Käsittely voi kestää muutamia sekunteja, eikä sen keskeytys tai peruminen ole mahdollista." }, "theme": { "message": "Teema" @@ -5273,7 +5279,7 @@ "description": "The text, 'SCIM', is an acronymn and should not be translated." }, "scimDescription": { - "message": "Provisioi käyttäjät ja ryhmät suosimasi tunnistustietojen tarjoajan kanssa SCIM-provisioinnilla", + "message": "Provisioi käyttäjät ja ryhmät haluamasi tunnistustietojen tarjoajan kanssa SCIM-provisioinnilla", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimEnabledCheckboxDesc": { @@ -5281,7 +5287,7 @@ "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimEnabledCheckboxDescHelpText": { - "message": "Määritä haluamasi SAML-tunnistustietojen tarjoaja määrittämällä URL-osoite ja SCIM API-avain", + "message": "Määritä haluamasi tunnistustietojen tarjoaja määrittämällä URL-osoite ja SCIM API -avain", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimApiKeyHelperText": { diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 37f65c83d49..874faf9c552 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index 51dd966dea1..ce1b38ac01d 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Permissions du Gestionnaire" + }, + "adminPermissions": { + "message": "Permissions de l'Administrateur" + }, "accessEventLogs": { "message": "Accéder aux journaux d'événements" }, diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index fce1aa9d41e..7097f742461 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 63abb103a71..ebdb4cd0ac2 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index 0207bb4e595..5ae0ed2b8a7 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Dozvole" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Pristup zapisnicima događaja" }, diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index e97ce8698b7..2d673d6e654 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -1215,7 +1215,7 @@ "message": "Felismerhető kép megjelenítése minden bejelentkezés mellett." }, "enableGravatars": { - "message": "Gravatarok engedélyezése", + "message": "Gravatarok megjelenítése", "description": "Use avatar images loaded from gravatar.com." }, "enableGravatarsDesc": { @@ -3433,7 +3433,7 @@ "message": "Mesterjelszó követelmények" }, "masterPassPolicyDesc": { - "message": "A minimális követelmények beállítása a mesterjelszó hozzához." + "message": "A minimális követelmények beállítása a mesterjelszó hosszához." }, "twoStepLoginPolicyTitle": { "message": "Kétlépéses bejelentkezés szükséges" @@ -3994,10 +3994,10 @@ "message": "Egy vállalati házirend miatt korlátozásra került az elemek személyes tárolóba történő mentése. Módosítsuk a Tulajdon opciót egy szervezetre és válasszunk az elérhető gyűjtemények közül." }, "disableSend": { - "message": "Küdlés letiltása" + "message": "Send letiltása" }, "disableSendPolicyDesc": { - "message": "Ne engedjük a felhasználóknak a Bitwarden Küldés létrehozását vagy szerkesztését. A meglévő küldés törlése továbbra is megengedett.", + "message": "Ne engedjük a felhasználóknak a Bitwarden Send létrehozását vagy szerkesztését. A meglévő küldés törlése továbbra is megengedett.", "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "disableSendExemption": { @@ -4057,6 +4057,12 @@ "permissions": { "message": "Jogosultságok" }, + "managerPermissions": { + "message": "Jogosultságok kezelése" + }, + "adminPermissions": { + "message": "Adminisztrátori jogosultságok" + }, "accessEventLogs": { "message": "Eseménynapló elérése" }, @@ -4319,7 +4325,7 @@ "message": "A regisztráció lehetővé teszi a szervezet adminisztrátorainak a saját mesterjelszó megváltoztatását. Biztosan feliratkozunk?" }, "resetPasswordPolicy": { - "message": "Mesterjelszó alaphelyzetbe állítása" + "message": "Mesterjelszó alaphelyzetbe állítás" }, "resetPasswordPolicyDescription": { "message": "A szervezet adminisztrátorai alaphelyzetbe állíthatják a szervezet mesterjelszavát." @@ -4603,16 +4609,16 @@ "message": "A széf időkorlátja túllépi a szervezet által beállított korlátozást." }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "A minimális egyedi időkifutás 1 perc." }, "vaultTimeoutRangeError": { - "message": "Vault Timeout is not within allowed range." + "message": "A széf időkifutás nincs az engedélyezett intervallunban." }, "disablePersonalVaultExport": { - "message": "A személyes széf exportálás nem engedélyezett." + "message": "A személyes széf exportálás eltávolítása" }, "disablePersonalVaultExportDesc": { - "message": "Biztosan leválasztjuk ezt a szervezetet? A szervezet továbbra is fennáll, de már nem a szolgáltató kezeli." + "message": "A tagok nem exportálhatnak személyes széf adatokat." }, "vaultExportDisabled": { "message": "A széf exportálás nem engedélyezett." @@ -4900,11 +4906,11 @@ "message": "A beüzemeléskor a konfiguráció mentésre kerül és a tagok hitelesíthetnek az azonosítási szolgáltató hitelesítő adataival." }, "ssoPolicyHelpStart": { - "message": "Engedélyezzük az", + "message": "Használat:", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpLink": { - "message": "SSO hitelesítési szabályzat", + "message": "önálló bejekentkezés hitelesítés szükséges", "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpEnd": { @@ -4912,7 +4918,7 @@ "description": "This will be used as part of a larger sentence, broken up to include links. The full sentence will read 'Use the require single-sign-on authentication policy to require all members to log in with SSO.'" }, "ssoPolicyHelpKeyConnector": { - "message": "A kulcscsatlakozó visszafejtésének beállításához SSO hitelesítés és egy szervezeti szabályzat szükséges." + "message": "A kulcscsatlakozó visszafejtésének beállításához SSO hitelesítés és egy önálló szervezeti szabályzat szükséges." }, "memberDecryptionOption": { "message": "Tagi visszafejtési opciók" diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index 46f191e077b..07e2c67bdf0 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Izin" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Akses Log Peristiwa" }, diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 3c095b31c7a..f92c5c349e6 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -679,7 +679,7 @@ "message": "Password principale errata" }, "invalidFilePassword": { - "message": "Password errata, usa la password che hai inserito quando hai creato il file di esportazione." + "message": "Password errata, usa la password che hai inserito alla creazione del file di esportazione." }, "lockNow": { "message": "Blocca" @@ -894,46 +894,46 @@ "message": "Formato file" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "Il file esportato sarà crittato, sarà necessaria una password per decrittare il file." }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "La password sarà utilizzata per importare ed esportare il file" }, "confirmMasterPassword": { - "message": "Confirm Master Password" + "message": "Conferma password principale" }, "confirmFormat": { - "message": "Confirm Format" + "message": "Conferma formato" }, "filePassword": { - "message": "File Password" + "message": "Password del file" }, "confirmFilePassword": { - "message": "Confirm File Password" + "message": "Conferma password del file" }, "accountBackupOptionDescription": { - "message": "Use your account encryption key to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Utilizza la chiave di crittografia del tuo account per crittare l'esportazione e limitare l'import all'attuale account Bitwarden." }, "passwordProtectedOptionDescription": { - "message": "Set a password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Imposta una password per crittare l'esportazione e importala in qualsiasi account Bitwarden, utilizzando la password impostata." }, "fileTypeHeading": { - "message": "File Type" + "message": "Tipo di file" }, "accountBackup": { - "message": "Account Backup" + "message": "Backup dell'account" }, "passwordProtected": { - "message": "Password Protected" + "message": "Protetto da password" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“File password” and “Confirm File Password“ do not match." + "message": "La password del file e la password inserita nel campo di conferma non corrispondono." }, "confirmVaultImport": { - "message": "Confirm Vault Import" + "message": "Conferma importazione della cassaforte" }, "confirmVaultImportDesc": { - "message": "This file is password-protected. Please enter the file password to import data." + "message": "Questo file è protetto da password. Inserisci la password del file per importare i dati." }, "exportSuccess": { "message": "I dati della tua cassaforte sono stati esportati." @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permessi" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Accedi ai log degli eventi" }, diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 9345261bc3c..e415d837534 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "権限" }, + "managerPermissions": { + "message": "権限の管理" + }, + "adminPermissions": { + "message": "管理者権限" + }, "accessEventLogs": { "message": "イベントログにアクセス" }, @@ -4627,16 +4633,16 @@ "message": "タイプ" }, "openIdConnectConfig": { - "message": "OpenID Connect Configuration" + "message": "OpenID Connectの設定" }, "samlSpConfig": { - "message": "SAML Service Provider Configuration" + "message": "SAML サービス プロバイダーの設定" }, "samlIdpConfig": { - "message": "SAML Identity Provider Configuration" + "message": "SAML IDプロバイダーの設定" }, "callbackPath": { - "message": "Callback Path" + "message": "コールバックパス" }, "signedOutCallbackPath": { "message": "Signed Out Callback Path" @@ -4705,10 +4711,10 @@ "message": "証明書を検証する" }, "idpEntityId": { - "message": "Entity ID" + "message": "エンティティID" }, "idpBindingType": { - "message": "Binding Type" + "message": "バインディングの種類" }, "idpSingleSignOnServiceUrl": { "message": "Single Sign On Service URL" @@ -4762,7 +4768,7 @@ "message": "引き換える" }, "sponsoredFamiliesSelectOffer": { - "message": "Select the organization you would like sponsored" + "message": "スポンサーしたい組織を選択してください" }, "familiesSponsoringOrgSelect": { "message": "どの家族向けプランの無償提供に引き換えますか?" @@ -4804,7 +4810,7 @@ "message": "引き換えに使用したアカウント" }, "revokeAccount": { - "message": "Revoke account $NAME$", + "message": "アカウント $NAME$ を取り消す", "placeholders": { "name": { "content": "$1", @@ -4813,7 +4819,7 @@ } }, "resendEmailLabel": { - "message": "Resend Sponsorship email to $NAME$ sponsorship", + "message": "$NAME$ スポンサーシップにスポンサーシップメールを再送信する", "placeholders": { "name": { "content": "$1", diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index 5ca96affb7a..80755183b9f 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 5ca96affb7a..80755183b9f 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index e49c178c6be..0f57d99a739 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "ಅನುಮತಿಗಳು" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "ಈವೆಂಟ್ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ" }, diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index 5e9ec49e03a..9ea99f04446 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -306,7 +306,7 @@ "message": "보안 메모" }, "typeLoginPlural": { - "message": "Logins" + "message": "로그인" }, "typeCardPlural": { "message": "카드" @@ -4057,6 +4057,12 @@ "permissions": { "message": "권한" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "이벤트 로그 접근" }, diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index f1d428388a6..8b5956c696c 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -679,7 +679,7 @@ "message": "Nederīga galvenā parole" }, "invalidFilePassword": { - "message": "Invalid file password, please use the password you entered when you created the export file." + "message": "Nederīga datnes parole, lūgums izmantot to paroli, kas tika ievadīta izdošanas datnes izveidošanas brīdī." }, "lockNow": { "message": "Aizslēgt" @@ -894,46 +894,46 @@ "message": "Datnes veids" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "Šī datņu izdošana būs aizsargāta ar paroli, un būs nepieciešama datnes parole, lai to atšifrētu." }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "Šī parole tiks izmantota, lai izdotu un ievietotu šo datni" }, "confirmMasterPassword": { - "message": "Confirm Master Password" + "message": "Apstiprināt galveno paroli" }, "confirmFormat": { - "message": "Confirm Format" + "message": "Apstiprināt veidolu" }, "filePassword": { - "message": "File Password" + "message": "Datnes parole" }, "confirmFilePassword": { - "message": "Confirm File Password" + "message": "Apstiprināt datnes paroli" }, "accountBackupOptionDescription": { - "message": "Use your account encryption key to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Jāizmanto konta šifrēšanas atslēga, lai šifrētu izdošanu un ierobežotu ievietošanu tikai pašreizējā Bitwarden kontā." }, "passwordProtectedOptionDescription": { - "message": "Set a password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Uzstādīt paroli, lai šifrētu izdošanu un tad to ievietotu jebkurā Bitwarden kontā, izmantojot atšifrēšanas paroli." }, "fileTypeHeading": { - "message": "File Type" + "message": "Datnes veids" }, "accountBackup": { - "message": "Account Backup" + "message": "Konta rezerves kopija" }, "passwordProtected": { - "message": "Password Protected" + "message": "Aizsargāts ar paroli" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“File password” and “Confirm File Password“ do not match." + "message": "\"Datnes parole\" un \"Apstiprināt datnes paroli\" vērtības nesakrīt." }, "confirmVaultImport": { - "message": "Confirm Vault Import" + "message": "Apstiprināt glabātavas satura ievietošanu" }, "confirmVaultImportDesc": { - "message": "This file is password-protected. Please enter the file password to import data." + "message": "Šī datne ir aizsargāta ar paroli. Lūgums ievadīt datnes paroli, lai ievietotu datus." }, "exportSuccess": { "message": "Glabātavas saturs ir izgūts." @@ -4057,6 +4057,12 @@ "permissions": { "message": "Atļaujas" }, + "managerPermissions": { + "message": "Pārvaldnieka atļaujas" + }, + "adminPermissions": { + "message": "Administratora atļaujas" + }, "accessEventLogs": { "message": "Piekļūt notikumu žurnāla ierakstiem" }, diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index 3daff3c6492..ea6689a9b80 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "അനുമതികൾ" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index 3f8bec3fd68..372bd618e02 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Rettigheter" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Få tilgang til hendelseslogger" }, diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index 4459abac692..002abcd8852 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -1296,7 +1296,7 @@ "message": "Ingeschakeld" }, "restoreAccess": { - "message": "Restore Access" + "message": "Toegang herstellen" }, "premium": { "message": "Premium", @@ -1324,7 +1324,7 @@ "message": "Uitschakelen" }, "revokeAccess": { - "message": "Revoke Access" + "message": "Toegang intrekken" }, "twoStepLoginProviderEnabled": { "message": "Deze tweestapsaanmeldingsaanbieder is geactiveerd voor je account." @@ -2326,10 +2326,10 @@ "message": "Weet je zeker dat je deze gebruiker wilt verwijderen?" }, "removeOrgUserConfirmation": { - "message": "When a member is removed, they no longer have access to organization data and this action is irreversible. To add the member back to the organization, they must be invited and onboarded again." + "message": "Na het verwijderen heeft een lid onherroepelijk geen toegang meer tot de gegevens van de organisatie. Om een lid opnieuw aan de organisatie toe te voegen, moet je deze uitnodigen en opnieuw on-boarden." }, "revokeUserConfirmation": { - "message": "When a member is revoked, they no longer have access to organization data. To quickly restore member access, go to the Revoked tab." + "message": "Na het intrekken van toegang heeft een lid geen toegang meer tot de gegevens van de organisatie. Om de toegang snel te herstellen, ga je naar het tabblad Ingetrokken." }, "removeUserConfirmationKeyConnector": { "message": "Waarschuwing! Deze gebruiker vereist de Key Connector om de versleuteling te beheren. Als je deze gebruiker uit je organisatie verwijdert, wordt zijn account permanent uitgeschakeld. Deze actie kan niet ongedaan worden gemaakt. Wil je doorgaan?" @@ -2677,7 +2677,7 @@ } }, "removeUserIdAccess": { - "message": "Remove $ID$ access", + "message": "Toegang $ID$ verwijderen", "placeholders": { "id": { "content": "$1", @@ -2686,7 +2686,7 @@ } }, "revokedUserId": { - "message": "Revoked organization access for $ID$.", + "message": "Toegang tot de organisatie ingetrokken voor $ID$.", "placeholders": { "id": { "content": "$1", @@ -2695,7 +2695,7 @@ } }, "restoredUserId": { - "message": "Restored organization access for $ID$.", + "message": "Toegang tot de organisatie hersteld voor $ID$.", "placeholders": { "id": { "content": "$1", @@ -2704,7 +2704,7 @@ } }, "revokeUserId": { - "message": "Revoke $ID$ access", + "message": "Toegang $ID$ intrekken", "placeholders": { "id": { "content": "$1", @@ -3769,7 +3769,7 @@ "message": "Uitgeschakeld" }, "revoked": { - "message": "Revoked" + "message": "Ingetrokken" }, "sendLink": { "message": "Send-koppeling", @@ -4057,6 +4057,12 @@ "permissions": { "message": "Rechten" }, + "managerPermissions": { + "message": "Managersrechten" + }, + "adminPermissions": { + "message": "Beheerdersrechten" + }, "accessEventLogs": { "message": "Eventlogs" }, @@ -4373,10 +4379,10 @@ "message": "Weet je zeker dat je de volgende gebruikers wilt verwijderen? Dit proces duurt enkele seconden en kan niet worden onderbroken of geannuleerd." }, "removeOrgUsersConfirmation": { - "message": "When member(s) are removed, they no longer have access to organization data and this action is irreversible. To add the member back to the organization, they must be invited and onboarded again. The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Na het verwijderen hebben leden onherroepelijk geen toegang meer tot de gegevens van de organisatie. Om een lid opnieuw aan de organisatie toe te voegen, moet je deze uitnodigen en opnieuw on-boarden. Dit proces neemt een paar seconden in beslag en je kunt het niet interrumperen of annuleren." }, "revokeUsersWarning": { - "message": "When member(s) are revoked, they no longer have access to organization data. To quickly restore member access, go to the Revoked tab. The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Na het intrekken van toegang hebben leden geen toegang meer tot de gegevens van de organisatie. Om de toegang snel te herstellen, ga je naar het tabblad Ingetrokken. Dit proces neemt een paar seconden in beslag en je kunt het niet interrumperen of annuleren." }, "theme": { "message": "Thema" @@ -4409,10 +4415,10 @@ "message": "Succesvol verwijderd" }, "bulkRevokedMessage": { - "message": "Revoked organization access successfully" + "message": "Toegang tot de organisatie ingetrokkeb" }, "bulkRestoredMessage": { - "message": "Restored organization access successfully" + "message": "Toegang tot de organisatie hersteld" }, "bulkFilteredMessage": { "message": "Uitgezonderd, niet van toepassing voor deze actie." @@ -4424,10 +4430,10 @@ "message": "Gebruikers verwijderen" }, "revokeUsers": { - "message": "Revoke Users" + "message": "Gebruikers intrekken" }, "restoreUsers": { - "message": "Restore Users" + "message": "Gebruikers herstellen" }, "error": { "message": "Fout" @@ -4849,7 +4855,7 @@ "message": "Sponsoring verwijderd" }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Key-connector fout: zorg ervoor dat Key-connector beschikbaar is en werkt." }, "keyConnectorUrl": { "message": "Key Connector URL" @@ -5156,17 +5162,17 @@ "message": "Type gebruikersnaam" }, "plusAddressedEmail": { - "message": "Plus Addressed Email", + "message": "E-mailadres-met-plus", "description": "Username generator option that appends a random sub-address to the username. For example: address+subaddress@email.com" }, "plusAddressedEmailDesc": { - "message": "Use your email provider's sub-addressing capabilities." + "message": "Gebruik de subadressen van je e-mailprovider." }, "catchallEmail": { "message": "Catch-all e-mail" }, "catchallEmailDesc": { - "message": "Use your domain's configured catch-all inbox." + "message": "Gebruik de catch-all inbox van je domein." }, "random": { "message": "Willekeurig", diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 1b27527fc3a..fa3ea5e5272 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index fc3f0ff1b83..ea9e0cba533 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -645,7 +645,7 @@ "message": "Konto zostało utworzone! Teraz możesz się zalogować." }, "trialAccountCreated": { - "message": "Konto zostało pomyślnie utworzone." + "message": "Konto zostało utworzone." }, "masterPassSent": { "message": "Wysłaliśmy Tobie wiadomość e-mail z podpowiedzią do hasła głównego." @@ -918,7 +918,7 @@ "message": "Utwórz hasło wygenerowane przez użytkownika, aby chronić eksport. Użyj tego, aby utworzyć eksport, który może być używany na innych kontach." }, "fileTypeHeading": { - "message": "Typ Pliku" + "message": "Rodzaj pliku" }, "accountBackup": { "message": "Kopia zapasowa konta" @@ -1324,7 +1324,7 @@ "message": "Wyłącz" }, "revokeAccess": { - "message": "Odwołaj dostęp" + "message": "Unieważnij dostęp" }, "twoStepLoginProviderEnabled": { "message": "Ten dostawca logowania dwustopniowego jest już włączony na koncie." @@ -1840,7 +1840,7 @@ "message": "rok" }, "yr": { - "message": "r." + "message": "rok" }, "month": { "message": "miesiąc" @@ -2257,7 +2257,7 @@ "message": "Rocznie" }, "annual": { - "message": "Raz w roku" + "message": "Rocznie" }, "basePrice": { "message": "Cena netto" @@ -2329,7 +2329,7 @@ "message": "Gdy członek zostanie usunięty, nie ma już dostępu do danych organizacji, a ta czynność jest nieodwracalna. Aby ponownie dodać członka do organizacji, należy go zaprosić i ponownie wprowadzić." }, "revokeUserConfirmation": { - "message": "Gdy członek zostanie odwołany, nie ma już dostępu do danych organizacji. Aby szybko przywrócić dostęp członków, przejdź do karty Odwołani." + "message": "Jeśli użytkownik zostanie unieważniony, nie będzie miał dostępu do danych organizacji. Aby przywrócić dostęp użytkownika, przejdź do karty Unieważnieni." }, "removeUserConfirmationKeyConnector": { "message": "Ostrzeżenie! Ten użytkownik wymaga serwera Key Connector do zarządzania szyfrowaniem. Usunięcie tego użytkownika z organizacji spowoduje trwałe wyłączenie jego konta. Nie możesz cofnąć tej akcji. Czy chcesz kontynuować?" @@ -2686,7 +2686,7 @@ } }, "revokedUserId": { - "message": "Odwołano dostęp organizacji dla $ID$.", + "message": "Dostęp do organizacji dla użytkownika $ID$ został unieważniony.", "placeholders": { "id": { "content": "$1", @@ -2704,7 +2704,7 @@ } }, "revokeUserId": { - "message": "Odwołano dostęp $ID$", + "message": "Unieważnij dostęp dla użytkownika $ID$", "placeholders": { "id": { "content": "$1", @@ -3769,7 +3769,7 @@ "message": "Wyłączone" }, "revoked": { - "message": "Odwołani" + "message": "Unieważnieni" }, "sendLink": { "message": "Link wysyłki", @@ -4057,6 +4057,12 @@ "permissions": { "message": "Uprawnienia" }, + "managerPermissions": { + "message": "Menedżer uprawnień" + }, + "adminPermissions": { + "message": "Administrator uprawnień" + }, "accessEventLogs": { "message": "Dostęp do dziennika zdarzeń" }, @@ -4376,7 +4382,7 @@ "message": "Kiedy członek (członkowie) zostaje usunięty, nie ma już dostępu do danych organizacji i działanie to jest nieodwracalne. Aby dodać członka z powrotem do organizacji, musi on zostać ponownie zaproszony i włączony do organizacji. Proces ten może trwać kilka sekund i nie może być przerwany ani anulowany." }, "revokeUsersWarning": { - "message": "Gdy członek (członkowie) zostanie odwołany, nie ma już dostępu do danych organizacji. Aby szybko przywrócić dostęp do danych członka, przejdź do zakładki Odwołano. Proces ten może potrwać kilka sekund i nie można go przerwać ani anulować." + "message": "Jeśli użytkownicy zostaną unieważnieni, nie będą mieli dostępu do danych organizacji. Aby przywrócić dostęp użytkownika, przejdź do karty Unieważnieni. Proces może potrwać kilka sekund i nie można go przerwać lub anulować." }, "theme": { "message": "Motyw" @@ -4409,7 +4415,7 @@ "message": "Usunięto" }, "bulkRevokedMessage": { - "message": "Odwołano dostęp do organizacji" + "message": "Dostęp do organizacji został unieważniony" }, "bulkRestoredMessage": { "message": "Przywrócono dostęp do organizacji" @@ -4424,7 +4430,7 @@ "message": "Usuń użytkowników" }, "revokeUsers": { - "message": "Odwołaj użytkowników" + "message": "Unieważnij użytkowników" }, "restoreUsers": { "message": "Przywróć użytkowników" diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index 6944ffec979..fcb778e6d9b 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissões" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Acessar Registro de Eventos" }, diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index bdf34e78aec..38025cfcab3 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissões" }, + "managerPermissions": { + "message": "Gestão de permissões" + }, + "adminPermissions": { + "message": "Permissões de Administrador" + }, "accessEventLogs": { "message": "Aceder ao Registro de Eventos" }, diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index ac5b652a525..79ec219b22e 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permisiuni" }, + "managerPermissions": { + "message": "Permisiuni manager" + }, + "adminPermissions": { + "message": "Permisiuni Admin" + }, "accessEventLogs": { "message": "Acces la jurnalele de evenimente" }, diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 9039b0e70c8..e6a40602e3b 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Разрешения" }, + "managerPermissions": { + "message": "Права менеджера" + }, + "adminPermissions": { + "message": "Права администратора" + }, "accessEventLogs": { "message": "Доступ к журналам событий" }, diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index ae91788759d..26e5893ffce 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index add48f608c5..0a76deafa2c 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -930,7 +930,7 @@ "message": "\"Heslo súboru\" a \"Potvrdiť heslo súboru\" sa nezhodujú." }, "confirmVaultImport": { - "message": "Potvrdiť importu trezoru" + "message": "Potvrdiť import trezoru" }, "confirmVaultImportDesc": { "message": "Tento súbor je chránený heslom. Ak chcete importovať údaje, zadajte heslo súboru." @@ -1523,14 +1523,14 @@ "message": "Reporty" }, "reportsDesc": { - "message": "Identify and close security gaps in your online accounts by clicking the reports below.", + "message": "Identifikujte a opravte bezpečnostné nedostatky kliknutím na reporty nižšie.", "description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault." }, "unsecuredWebsitesReport": { "message": "Nezabezpečené stránky" }, "unsecuredWebsitesReportDesc": { - "message": "URLs that start with http:// don’t use the best available encryption. Change the Login URIs for these accounts to https:// for safer browsing." + "message": "URL, ktoré začínajú s http:// nepoužívajú najlepšie dostupné šifrovanie. Upravte URL prihlásenia pre tieto kontá na https:// pre bezpečnejšie surfovanie na internete." }, "unsecuredWebsitesFound": { "message": "Našli sa nezabezpečené stránky" @@ -1575,7 +1575,7 @@ "message": "Uniknuté heslá" }, "exposedPasswordsReportDesc": { - "message": "Passwords exposed in a data breach are easy targets for attackers. Change these passwords to prevent potential break-ins." + "message": "Heslá odhalené pri úniku dát sú pre útočníkov jednoduchým cieľom. Zmeňte tieto heslá aby ste sa vyhli možnému vlámaniu." }, "exposedPasswordsFound": { "message": "Našli sme uniknuté heslá" @@ -1608,7 +1608,7 @@ "message": "Slabé heslá" }, "weakPasswordsReportDesc": { - "message": "Weak passwords can be easily guessed by attackers. Change these passwords to strong ones using the Password Generator." + "message": "Jednoduché heslá môže útočník ľahko uhádnuť. Vymeňte tieto heslá za silné s použitím Generátora Hesiel." }, "weakPasswordsFound": { "message": "Našli sa slabé heslá" @@ -1629,7 +1629,7 @@ "message": "Viacnásobne použité heslá" }, "reusedPasswordsReportDesc": { - "message": "Reusing passwords makes it easier for attackers to break into multiple accounts. Change these passwords so that each is unique." + "message": "Opakované používanie hesiel uľahčuje útočníkom vlámať sa do viacerých účtov. Zmeňte si tieto heslá tak aby bolo každé unikátne." }, "reusedPasswordsFound": { "message": "Našli sa viacnásobne použité heslá" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Povolenia" }, + "managerPermissions": { + "message": "Oprávnenia manažéra" + }, + "adminPermissions": { + "message": "Oprávnenia správcu" + }, "accessEventLogs": { "message": "Prístup k protokolom udalostí" }, diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index b98db470a0c..2290771cdf4 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index 53726c7c596..77530eb1340 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Дозволе" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Приступе извештаја догађаја" }, diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index ad332f42106..73b53363e46 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index b08424cb977..2812a6047f9 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -573,7 +573,7 @@ "message": "Skapa konto" }, "startTrial": { - "message": "Start Trial" + "message": "Påbörja utvärdering" }, "logIn": { "message": "Logga in" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Behörigheter" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Åtkomst till händelseloggar" }, diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 5b7da9a8422..e40011655b0 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -597,7 +597,7 @@ "message": "Ana parola, kasanıza ulaşmak için kullanacağınız paroladır. Ana parolanızı unutmamanız çok önemlidir. Unutursanız parolalarınızı asla kurtaramazsınız." }, "masterPassImportant": { - "message": "Master passwords cannot be recovered if you forget it!" + "message": "Ana şifreler, unutursanız kurtarılamaz!" }, "masterPassHintDesc": { "message": "Ana parolanızı unutursanız bu ipucuna bakınca size ana parolanızı hatırlatacak bir şey yazabilirsiniz." @@ -679,7 +679,7 @@ "message": "Geçersiz ana parola" }, "invalidFilePassword": { - "message": "Invalid file password, please use the password you entered when you created the export file." + "message": "Geçersiz dosya şifresi, lütfen dışa aktarma dosyasını oluştururken girdiğiniz şifreyi kullanın." }, "lockNow": { "message": "Şimdi kilitle" @@ -894,46 +894,46 @@ "message": "Dosya biçimi" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "Bu dosya dışa aktarma, şifre korumalı olacak ve şifrenin çözülmesi için dosya şifresi gerektirecek." }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "Bu şifre, bu dosyayı dışa ve içe aktarmak için kullanılacaktır" }, "confirmMasterPassword": { - "message": "Confirm Master Password" + "message": "Ana Şifreyi Onayla" }, "confirmFormat": { - "message": "Confirm Format" + "message": "Biçimi Onayla" }, "filePassword": { - "message": "File Password" + "message": "Dosya Şifresi" }, "confirmFilePassword": { - "message": "Confirm File Password" + "message": "Dosya Şifresini Onayla" }, "accountBackupOptionDescription": { - "message": "Use your account encryption key to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Dışa aktarmayı şifrelemek ve içe aktarmayı yalnızca geçerli Bitwarden hesabıyla kısıtlamak için hesap çözme anahtarınızı kullanın." }, "passwordProtectedOptionDescription": { - "message": "Set a password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Dışa aktarmayı şifrelemek için bir şifre belirleyin ve şifre çözme parolasını kullanarak herhangi bir Bitwarden hesabına içe aktarın." }, "fileTypeHeading": { - "message": "File Type" + "message": "Dosya Tipi" }, "accountBackup": { - "message": "Account Backup" + "message": "Hesap Yedeği" }, "passwordProtected": { - "message": "Password Protected" + "message": "Şifre Korumalı" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“File password” and “Confirm File Password“ do not match." + "message": "\"Dosya şifresi\" ve \"Dosya Şifresini Onayla\" eşleşmiyor." }, "confirmVaultImport": { - "message": "Confirm Vault Import" + "message": "Kasayı İçe Aktarmayı Onaylayın" }, "confirmVaultImportDesc": { - "message": "This file is password-protected. Please enter the file password to import data." + "message": "Bu dosya şifre korumalıdır. Verileri içe aktarmak için lütfen dosya şifresini girin." }, "exportSuccess": { "message": "Kasadaki verileriniz dışa aktarıldı." @@ -1296,7 +1296,7 @@ "message": "Etkin" }, "restoreAccess": { - "message": "Restore Access" + "message": "Erişimi geri yükle" }, "premium": { "message": "Premium", @@ -1324,7 +1324,7 @@ "message": "Devre dışı bırak" }, "revokeAccess": { - "message": "Revoke Access" + "message": "Erişimi iptal et" }, "twoStepLoginProviderEnabled": { "message": "Bu iki aşamalı giriş sağlayıcısı hesabınızda etkin durumda." @@ -1871,7 +1871,7 @@ "message": "Fatura Bilgileri" }, "billingTrialSubLabel": { - "message": "Your payment method will not be charged during the 7 day free trial." + "message": "7 günlük ücretsiz deneme süresi boyunca ödeme yönteminizden ücret alınmayacaktır." }, "creditCard": { "message": "Kredi kartı" @@ -2230,7 +2230,7 @@ } }, "trialThankYou": { - "message": "Thanks for signing up for Bitwarden for $PLAN$!", + "message": "$PLAN$ karşılığında Bitwarden'a kaydolduğunuz için teşekkür ederiz!", "placeholders": { "plan": { "content": "$1", @@ -2239,7 +2239,7 @@ } }, "trialPaidInfoMessage": { - "message": "Your $PLAN$ 7 day free trial will be converted to a paid subscription after 7 days.", + "message": "$PLAN$ 7 günlük ücretsiz denemeniz, 7 gün sonra ücretli aboneliğe dönüştürülecektir.", "placeholders": { "plan": { "content": "$1", @@ -2248,7 +2248,7 @@ } }, "trialConfirmationEmail": { - "message": "We've sent a confirmation email to your team's billing email at " + "message": "Ekibinizin şu adresteki faturalandırma e-postasına bir onay e-postası gönderdik " }, "monthly": { "message": "Aylık" @@ -2326,10 +2326,10 @@ "message": "Bu kullanıcıyı silmek istediğinizden emin misiniz?" }, "removeOrgUserConfirmation": { - "message": "When a member is removed, they no longer have access to organization data and this action is irreversible. To add the member back to the organization, they must be invited and onboarded again." + "message": "Bir üye kaldırıldığında, artık kuruluş verilerine erişimi olmaz ve bu işlem geri alınamaz. Üyeyi kuruluşa geri eklemek için davet edilmeleri ve tekrar katılmaları gerekir." }, "revokeUserConfirmation": { - "message": "When a member is revoked, they no longer have access to organization data. To quickly restore member access, go to the Revoked tab." + "message": "Bir üye feshedildiğinde, artık kuruluş verilerine erişimi olmaz. Üye erişimini hızlı bir şekilde geri yüklemek için İptal Edildi sekmesine gidin." }, "removeUserConfirmationKeyConnector": { "message": "Uyarı! Bu kullanıcı, şifrelemelerini yönetmek için Key Connector'a ihtiyaç duyuyor. Bu kullanıcıyı kuruluşunuzdan çıkarırsanız hesabı kalıcı olarak devre dışı kalacaktır. Bu işlem geri alınamaz. Devam etmek istiyor musunuz?" @@ -2428,7 +2428,7 @@ "message": "Kuruluşunuzda atanmış koleksiyonlara erişimi olan normal bir kullanıcı." }, "manager": { - "message": "Yönetici" + "message": "Yetkili" }, "managerDesc": { "message": "Yetkililer kuruluşunuzdaki kendilerine atanmış koleksiyonlara erişebilir ve onları yönetebilir." @@ -2677,7 +2677,7 @@ } }, "removeUserIdAccess": { - "message": "Remove $ID$ access", + "message": "$ID$ Erişimini kaldır", "placeholders": { "id": { "content": "$1", @@ -2686,7 +2686,7 @@ } }, "revokedUserId": { - "message": "Revoked organization access for $ID$.", + "message": "$ID$ İçin kuruluş erişimi iptal edildi.", "placeholders": { "id": { "content": "$1", @@ -2695,7 +2695,7 @@ } }, "restoredUserId": { - "message": "Restored organization access for $ID$.", + "message": "$ID$ İçin kuruluş erişimi geri yüklendi.", "placeholders": { "id": { "content": "$1", @@ -2704,7 +2704,7 @@ } }, "revokeUserId": { - "message": "Revoke $ID$ access", + "message": "$ID$ Erişimini iptal et", "placeholders": { "id": { "content": "$1", @@ -2950,7 +2950,7 @@ "message": "Eğer hesabınıza iki aşamalı doğrulama ile erişimde bir sorun yaşıyorsanız, kurtarma kodunuz ile iki aşamalı doğrulama özelliğini kapatabilirsiniz." }, "recoverAccountTwoStep": { - "message": "Recover Account Two-Step Login" + "message": "İki-Adımlı Hesap Girişini Kurtar" }, "twoStepRecoverDisabled": { "message": "İki aşamalı doğrulama hesabınızda devre dışı bırakıldı." @@ -3289,7 +3289,7 @@ "message": "4 saat" }, "onRefresh": { - "message": "On browser refresh" + "message": "Tarayıcıda yenileme" }, "dateUpdated": { "message": "Güncelleme", @@ -3436,13 +3436,13 @@ "message": "Ana parola gücü için minimum gereksinimleri ayarlayın." }, "twoStepLoginPolicyTitle": { - "message": "Require two-step login" + "message": "İki adımlı giriş gereklidir" }, "twoStepLoginPolicyDesc": { "message": "Kullanıcıların hesaplarında iki aşamalı giriş kullanmalarını zorunlu tutun." }, "twoStepLoginPolicyWarning": { - "message": "Organization members who are not Owners or Administrators and do not have two-step login turned on for their account will be removed from the organization and will receive an email notifying them about the change." + "message": "Sahip veya Yönetici olmayan ve hesapları için iki adımlı oturum açma özelliğini açmamış kuruluş üyeleri kuruluştan çıkarılır ve kendilerine değişiklik hakkında bilgi veren bir e-posta gönderilir." }, "twoStepLoginPolicyUserWarning": { "message": "İki aşamalı girişin etkinleştirilmesi gereken bir kuruluşa üyesisiniz. İki aşamalı giriş sağlayıcılarının tümünü devre dışı bırakırsanız bu kuruluşlardan otomatik olarak kaldırılırsınız." @@ -3660,7 +3660,7 @@ "message": "SSO bağlantısını kes" }, "unlinkSsoConfirmation": { - "message": "Are you sure you want to unlink SSO for this organization?" + "message": "Bu kuruluş için TOA bağlantısını kaldırmak istediğinizden emin misiniz?" }, "linkSso": { "message": "SSO bağla" @@ -3769,7 +3769,7 @@ "message": "Devre dışı" }, "revoked": { - "message": "Revoked" + "message": "İptal Edildi" }, "sendLink": { "message": "Send bağlantısı", @@ -4057,6 +4057,12 @@ "permissions": { "message": "İzinler" }, + "managerPermissions": { + "message": "Yetkili İzinleri" + }, + "adminPermissions": { + "message": "Yönetici İzinleri" + }, "accessEventLogs": { "message": "Olay günlüklerine erişme" }, @@ -4118,7 +4124,7 @@ "message": "Bir kuruluş ilkesi sahiplik seçeneklerinizi etkiliyor." }, "personalOwnershipPolicyInEffectImports": { - "message": "An organization policy has disabled importing items into your personal vault." + "message": "Bir kuruluş politikası, öğeleri kişisel kasanıza içe aktarmayı devre dışı bıraktı." }, "personalOwnershipCheckboxDesc": { "message": "Kuruluş kullanıcıları için kişisel sahipliği kapatma" @@ -4277,7 +4283,7 @@ } }, "eventResetSsoLink": { - "message": "Reset Sso link for user $ID$", + "message": "$ID$ kullanıcısı için Toa bağlantısını sıfırla", "placeholders": { "id": { "content": "$1", @@ -4373,10 +4379,10 @@ "message": "Aşağıdaki kullanıcıları kaldırmak istediğinize emin misiniz? İşlemin tamamlanması birkaç saniye sürer ve durdurulamaz veya iptal edilemez." }, "removeOrgUsersConfirmation": { - "message": "When member(s) are removed, they no longer have access to organization data and this action is irreversible. To add the member back to the organization, they must be invited and onboarded again. The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Üye(ler) kaldırıldığında, artık organizasyon verilerine erişimleri olmaz ve bu işlem geri alınamaz. Üyeyi kuruluşa geri eklemek için davet edilmeleri ve tekrar katılmaları gerekir. İşlemin tamamlanması birkaç saniye sürebilir ve kesintiye uğratılamaz veya iptal edilemez." }, "revokeUsersWarning": { - "message": "When member(s) are revoked, they no longer have access to organization data. To quickly restore member access, go to the Revoked tab. The process may take a few seconds to complete and cannot be interrupted or canceled." + "message": "Üye(ler) iptal edildiğinde, artık organizasyon verilerine erişimleri olmaz. Üye erişimini hızlı bir şekilde geri yüklemek için İptal Edildi sekmesine gidin. İşlemin tamamlanması birkaç saniye sürebilir ve kesintiye uğratılamaz veya iptal edilemez." }, "theme": { "message": "Tema" @@ -4409,10 +4415,10 @@ "message": "Başarıyla kaldırıldı" }, "bulkRevokedMessage": { - "message": "Revoked organization access successfully" + "message": "Kuruluş erişimi başarıyla iptal edildi" }, "bulkRestoredMessage": { - "message": "Restored organization access successfully" + "message": "Kuruluş erişimi başarıyla geri yüklendi" }, "bulkFilteredMessage": { "message": "İstisna. Bu eylem için geçerli değildir." @@ -4424,10 +4430,10 @@ "message": "Kullanıcıları kaldır" }, "revokeUsers": { - "message": "Revoke Users" + "message": "Kullanıcıları İptal Et" }, "restoreUsers": { - "message": "Restore Users" + "message": "Kullanıcıları geri yükle" }, "error": { "message": "Hata" @@ -4439,10 +4445,10 @@ "message": "Sağlayıcı kurulumu" }, "setupProviderLoginDesc": { - "message": "You've been invited to setup a new provider. To continue, you need to log in or create a new Bitwarden account." + "message": "Yeni bir sağlayıcı kurmaya davet edildiniz. Devam etmek için oturum açmanız veya yeni bir Bitwarden hesabı oluşturmanız gerekir." }, "setupProviderDesc": { - "message": "Please enter the details below to complete the provider setup. Contact Customer Support if you have any questions." + "message": "Sağlayıcı kurulumunu tamamlamak için lütfen aşağıdaki ayrıntıları girin. Herhangi bir sorunuz varsa Müşteri Desteği ile iletişime geçin." }, "providerName": { "message": "Sağlayıcı adı" @@ -4457,16 +4463,16 @@ "message": "Sağlayıcı yöneticisi" }, "providerAdminDesc": { - "message": "The highest access user that can manage all aspects of your provider as well as access and manage client organizations." + "message": "Sağlayıcınızın tüm yönlerini yönetebilen ve müşteri organizasyonlarına erişebilen ve yönetebilen en yüksek erişimli kullanıcı." }, "serviceUser": { "message": "Hizmet kullanıcısı" }, "serviceUserDesc": { - "message": "Service users can access and manage all client organizations." + "message": "Hizmet kullanıcıları, tüm istemci kuruluşlara erişebilir ve bunları yönetebilir." }, "providerInviteUserDesc": { - "message": "Invite a new user to your provider by entering their Bitwarden account email address below. If they do not have a Bitwarden account already, they will be prompted to create a new account." + "message": "Aşağıya Bitwarden hesabının e-posta adresini girerek sağlayıcınıza yeni bir kullanıcı davet edin. Halihazırda bir Bitwarden hesabı yoksa yeni bir hesap oluşturması istenecektir." }, "joinProvider": { "message": "Sağlayıcıya katıl" @@ -4490,7 +4496,7 @@ "message": "Yeni müşteri kuruluşu" }, "newClientOrganizationDesc": { - "message": "Create a new client organization that will be associated with you as the provider. You will be able to access and manage this organization." + "message": "Sağlayıcı olarak sizinle ilişkilendirilecek yeni bir müşteri organizasyonu oluşturun. Bu kuruluşa erişebilecek ve yönetebileceksiniz." }, "addExistingOrganization": { "message": "Mevcut kuruluşu ekle" @@ -4499,7 +4505,7 @@ "message": "Sağlayıcım" }, "addOrganizationConfirmation": { - "message": "Are you sure you want to add $ORGANIZATION$ as a client to $PROVIDER$?", + "message": "$PROVIDER$'a müşteri olarak $ORGANIZATION$ eklemek istediğinizden emin misiniz?", "placeholders": { "organization": { "content": "$1", @@ -4548,7 +4554,7 @@ } }, "detachOrganizationConfirmation": { - "message": "Are you sure you want to detach this organization? The organization will continue to exist but will no longer be managed by the provider." + "message": "Bu organizasyonu ayırmak istediğinizden emin misiniz? Kuruluş var olmaya devam edecek, ancak artık sağlayıcı tarafından yönetilmeyecek." }, "add": { "message": "Ekle" @@ -4569,7 +4575,7 @@ "message": "Kasa zaman aşımı" }, "maximumVaultTimeoutDesc": { - "message": "Set a maximum vault timeout for members." + "message": "Üyeler için maksimum kasa zaman aşımı ayarlayın." }, "maximumVaultTimeoutLabel": { "message": "Maksimum kasa zaman aşımı" @@ -4603,10 +4609,10 @@ "message": "Kasa zaman aşımınız, kuruluşunuz tarafından belirlenen kısıtlamaları aşıyor." }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "Minimum özel zaman aşımı 1 dakikadır." }, "vaultTimeoutRangeError": { - "message": "Vault Timeout is not within allowed range." + "message": "Kasa Zaman Aşımı izin verilen aralıkta değil." }, "disablePersonalVaultExport": { "message": "Kişisel kasayı dışa aktarmayı devre dışı bırak" @@ -4657,25 +4663,25 @@ "message": "OIDC yönlendirme davranışı" }, "getClaimsFromUserInfoEndpoint": { - "message": "Get claims from user info endpoint" + "message": "Kullanıcı bilgileri uç noktasından hak talepleri alın" }, "additionalScopes": { - "message": "Custom Scopes" + "message": "Özel Kapsamlar" }, "additionalUserIdClaimTypes": { - "message": "Custom User ID Claim Types" + "message": "Özel Kullanıcı Kimliği Talep Türleri" }, "additionalEmailClaimTypes": { - "message": "Email Claim Types" + "message": "E-posta Talep Türleri" }, "additionalNameClaimTypes": { - "message": "Custom Name Claim Types" + "message": "Özel Ad Talep Türleri" }, "acrValues": { - "message": "Requested Authentication Context Class Reference values" + "message": "İstenen Kimlik Doğrulama Bağlam Sınıfı Referans değerleri" }, "expectedReturnAcrValue": { - "message": "Expected \"acr\" Claim Value In Response" + "message": "Yanıt Olarak Beklenen \"acr\" Talep Değeri" }, "spEntityId": { "message": "SP varlık kimliği" @@ -4699,7 +4705,7 @@ "message": "Minimum gelen imza algoritması" }, "spWantAssertionsSigned": { - "message": "Expect signed assertions" + "message": "İmzalı assertions'lar bekleyin" }, "spValidateCertificates": { "message": "Sertifikaları doğrula" @@ -4717,28 +4723,28 @@ "message": "Tek çıkış (SLO) servis URL'si" }, "idpX509PublicCert": { - "message": "X509 Public Certificate" + "message": "X509 Genel Sertifika" }, "idpOutboundSigningAlgorithm": { - "message": "Outbound Signing Algorithm" + "message": "Çıkış imza algoritması" }, "idpAllowUnsolicitedAuthnResponse": { - "message": "Allow unsolicited authentication response" + "message": "İstenmeyen kimlik doğrulama yanıtına izin ver" }, "idpAllowOutboundLogoutRequests": { - "message": "Allow outbound logout requests" + "message": "Çıkış isteklerine izin ver" }, "idpSignAuthenticationRequests": { - "message": "Sign authentication requests" + "message": "İmza doğrulama istekleri" }, "ssoSettingsSaved": { - "message": "Single Sign-On configuration was saved." + "message": "Tek Oturum Açma yapılandırması kaydedildi." }, "sponsoredFamilies": { "message": "Ücretsiz Bitwarden Aile" }, "sponsoredFamiliesEligible": { - "message": "You and your family are eligible for Free Bitwarden Families. Redeem with your personal email to keep your data secure even when you are not at work." + "message": "Siz ve aileniz Ücretsiz Bitwarden Aileleri için uygunsunuz. Verilerinizi işte olmadığınızda bile güvende tutmak için kişisel e-postanızla kullanın." }, "sponsoredFamiliesEligibleCard": { "message": "Verilerinizi evde de güvenle depolamak için Ücretsiz Bitwarden Aile paketinizi hemen kullanmaya başlayın." @@ -4750,10 +4756,10 @@ "message": "6 kullanıcı için premium erişim" }, "sponsoredFamiliesSharedCollections": { - "message": "Shared collections for Family secrets" + "message": "Aile sırları için paylaşılan koleksiyonlar" }, "badToken": { - "message": "The link is no longer valid. Please have the sponsor resend the offer." + "message": "Bağlantı artık geçerli değil. Lütfen sponsorun teklifi yeniden göndermesini sağlayın." }, "reclaimedFreePlan": { "message": "Ücretsiz paket kullanıldı" @@ -4762,25 +4768,25 @@ "message": "Kullan" }, "sponsoredFamiliesSelectOffer": { - "message": "Select the organization you would like sponsored" + "message": "Sponsor olmasını istediğiniz kuruluşu seçin" }, "familiesSponsoringOrgSelect": { - "message": "Which Free Families offer would you like to redeem?" + "message": "Hangi Ücretsiz Aileler teklifinden yararlanmak istersiniz?" }, "sponsoredFamiliesEmail": { - "message": "Enter your personal email to redeem Bitwarden Families" + "message": "Bitwarden Families kullanmak için kişisel e-postanızı girin" }, "sponsoredFamiliesLeaveCopy": { "message": "Sponsor kuruluştan ayrılır veya çıkarılırsanız Aile paketiniz ödeme döneminin sonunda sonra erecektir." }, "acceptBitwardenFamiliesHelp": { - "message": "Accept offer for an existing organization or create a new Families organization." + "message": "Mevcut bir kuruluş için teklifi kabul edin veya yeni bir Aile kuruluşu oluşturun." }, "setupSponsoredFamiliesLoginDesc": { "message": "Ücretsiz Bitwarden Aile Paketi Kuruluşuna davet edildiniz. Devam etmek için bu teklifi alan hesaba giriş yapmanız gerekiyor." }, "sponsoredFamiliesAcceptFailed": { - "message": "Unable to accept offer. Please resend the offer email from your enterprise account and try again." + "message": "Teklif kabul edilemiyor. Lütfen kurumsal hesabınızdan teklif e-postasını yeniden gönderin ve tekrar deneyin." }, "sponsoredFamiliesAcceptFailedShort": { "message": "Teklif kabul edilemedi. $DESCRIPTION$", @@ -4795,13 +4801,13 @@ "message": "Ücretsiz Bitwarden Aile'yi kabul et" }, "sponsoredFamiliesOfferRedeemed": { - "message": "Free Bitwarden Families offer successfully redeemed" + "message": "Ücretsiz Bitwarden Families teklifi başarıyla kullanıldı" }, "redeemed": { "message": "Kullanıldı" }, "redeemedAccount": { - "message": "Redeemed Account" + "message": "Kullanılmış Hesap" }, "revokeAccount": { "message": "$NAME$ hesabını iptal et", @@ -4813,7 +4819,7 @@ } }, "resendEmailLabel": { - "message": "Resend Sponsorship email to $NAME$ sponsorship", + "message": "Sponsorluk e-postasını $NAME$ sponsorluğuna yeniden gönder", "placeholders": { "name": { "content": "$1", @@ -4834,7 +4840,7 @@ "message": "Sponsorluğu kaldır" }, "removeSponsorshipConfirmation": { - "message": "After removing a sponsorship, you will be responsible for this subscription and related invoices. Are you sure you want to continue?" + "message": "Bir sponsorluğu kaldırdıktan sonra, bu abonelikten ve ilgili faturalardan siz sorumlu olacaksınız. Devam etmek istediğine emin misin?" }, "sponsorshipCreated": { "message": "Sponsorluk oluştur" @@ -4843,13 +4849,13 @@ "message": "E-posta gönderildi" }, "revokeSponsorshipConfirmation": { - "message": "After removing this account, the Families plan sponsorship will expire at the end of the billing period. You will not be able to redeem a new sponsorship offer until the existing one expires. Are you sure you want to continue?" + "message": "Bu hesap kaldırıldıktan sonra, fatura döneminin sonunda Aile planı sponsorluğu sona erecektir. Mevcut olanın süresi dolana kadar yeni bir sponsorluk teklifinden yararlanamazsınız. Devam etmek istediğine emin misin?" }, "removeSponsorshipSuccess": { "message": "Sponsorluk kaldırdıldı" }, "ssoKeyConnectorError": { - "message": "Key Connector error: make sure Key Connector is available and working correctly." + "message": "Anahtar Bağlayıcı hatası: Anahtar Bağlayıcının mevcut olduğundan ve doğru çalıştığından emin olun." }, "keyConnectorUrl": { "message": "Key Connector adresi" @@ -4897,7 +4903,7 @@ "message": "SSO doğrulamasına izin ver" }, "allowSsoDesc": { - "message": "Once set up, your configuration will be saved and members will be able to authenticate using their Identity Provider credentials." + "message": "Ayarlandıktan sonra yapılandırmanız kaydedilecek ve üyeler, Kimlik Sağlayıcı kimlik bilgilerini kullanarak kimliklerini doğrulayabilecektir." }, "ssoPolicyHelpStart": { "message": "Tüm üyelerin SSO ile giriş yapmasını zorunlu tutmak için", @@ -4915,7 +4921,7 @@ "message": "Key Connector ile çözmeyi kurmak için \"SSO kimlik doğrulama\" ve \"tek kuruluş\" ilkeleri gereklidir." }, "memberDecryptionOption": { - "message": "Member Decryption Options" + "message": "Üye Şifre Çözme Seçenekleri" }, "memberDecryptionPassDesc": { "message": "Kimlik doğrulamanın ardından üyeler ana parolalarını kullanarak kasadaki verilere erişebilecekler." @@ -4924,10 +4930,10 @@ "message": "Key Connector" }, "memberDecryptionKeyConnectorDesc": { - "message": "Connect Login with SSO to your self-hosted decryption key server. Using this option, members won’t need to use their Master Passwords to decrypt vault data. Contact Bitwarden Support for set up assistance." + "message": "Oturum Açma ile TOA'yı kendi kendine barındırılan şifre çözme anahtarı sunucunuza bağlayın. Bu seçeneği kullanarak üyelerin kasa verilerinin şifresini çözmek için Ana şifrelerini kullanmaları gerekmez. Kurulum yardımı için Bitwarden Destek ile iletişime geçin." }, "keyConnectorPolicyRestriction": { - "message": "\"Login with SSO and Key Connector Decryption\" is enabled. This policy will only apply to Owners and Admins." + "message": "\"TOA ve Anahtar Bağlayıcı Şifre Çözme ile Oturum Açma\" etkinleştirildi. Bu politika yalnızca Sahipler ve Yöneticiler için geçerli olacaktır." }, "enabledSso": { "message": "SSO etkinleştirildi" @@ -4942,19 +4948,19 @@ "message": "Key Connector devre dışı bırakıldı" }, "keyConnectorWarning": { - "message": "Once members begin using Key Connector, your Organization cannot revert to Master Password decryption. Proceed only if you are comfortable deploying and managing a key server." + "message": "Üyeler Anahtar Bağlayıcı'yı kullanmaya başladığında, Kuruluşunuz Ana şifresi şifre çözmeye geri dönemez. Yalnızca bir anahtar sunucuyu dağıtma ve yönetme konusunda rahatsanız devam edin." }, "migratedKeyConnector": { "message": "Key Connector'a taşındı" }, "paymentSponsored": { - "message": "Please provide a payment method to associate with the organization. Don't worry, we won't charge you anything unless you select additional features or your sponsorship expires. " + "message": "Lütfen kuruluşla ilişkilendirmek için bir ödeme yöntemi sağlayın. Merak etmeyin, ek özellikler seçmediğiniz veya sponsorluğunuz sona ermediği sürece sizden hiçbir ücret talep etmeyeceğiz. " }, "orgCreatedSponsorshipInvalid": { - "message": "The sponsorship offer has expired. You may delete the organization you created to avoid a charge at the end of your 7 day trial. Otherwise you may close this prompt to keep the organization and assume billing responsibility." + "message": "Sponsorluk teklifinin süresi doldu. 7 günlük deneme sürenizin sonunda ücret ödememek için oluşturduğunuz organizasyonu silebilirsiniz. Aksi takdirde, kuruluşu korumak ve faturalandırma sorumluluğunu üstlenmek için bu istemi kapatabilirsiniz." }, "newFamiliesOrganization": { - "message": "New Families Organization" + "message": "Yeni Aileler Kuruluşu" }, "acceptOffer": { "message": "Teklifi kabul et" @@ -4978,55 +4984,55 @@ "message": "Sponsorluk ile ÜCRETSİZ" }, "viewBillingSyncToken": { - "message": "View Billing Sync Token" + "message": "Faturalandırma Eşitleme Anahtarını Görüntüle" }, "generateBillingSyncToken": { - "message": "Generate Billing Sync Token" + "message": "Faturalandırma Eşitleme Anahtarı Oluştur" }, "copyPasteBillingSync": { - "message": "Copy and paste this token into the Billing Sync settings of your self-hosted organization." + "message": "Bu anahtarı kopyalayıp şirket içinde barındırılan kuruluşunuzun Faturalandırma Eşitleme ayarlarına yapıştırın." }, "billingSyncCanAccess": { - "message": "Your Billing Sync token can access and edit this organization's subscription settings." + "message": "Faturalandırma Eşitleme anahtarınız bu kuruluşun abonelik ayarlarına erişebilir ve bunları düzenleyebilir." }, "manageBillingSync": { - "message": "Manage Billing Sync" + "message": "Faturalandırma Eşitlemesini Yönet" }, "setUpBillingSync": { - "message": "Set Up Billing Sync" + "message": "Faturalandırma Eşitlemesini Ayarla" }, "generateToken": { - "message": "Generate Token" + "message": "Anahtar Üret" }, "rotateToken": { - "message": "Rotate Token" + "message": "Anahtar Yenile" }, "rotateBillingSyncTokenWarning": { - "message": "If you proceed, you will need to re-setup billing sync on your self-hosted server." + "message": "Devam ederseniz, kendi kendine barındırılan sunucunuzda faturalandırma eşitlemesini yeniden kurmanız gerekecek." }, "rotateBillingSyncTokenTitle": { - "message": "Rotating the Billing Sync Token will invalidate the previous token." + "message": "Faturalandırma Senkronizasyonu Anahtarını yenilemek, önceki anahtarı geçersiz kılar." }, "selfHostingTitle": { - "message": "Self-Hosting" + "message": "Kendi Kendine Barındırılan" }, "selfHostingEnterpriseOrganizationSectionCopy": { - "message": "To set-up your organization on your own server, you will need to upload your license file. To support Free Families plans and advanced billing capabilities for your self-hosted organization, you will need to set up billing sync." + "message": "Kuruluşunuzu kendi sunucunuzda kurmak için lisans dosyanızı yüklemeniz gerekir. Kendi kendine barındırılan kuruluşunuz için Ücretsiz Aile planlarını ve gelişmiş faturalandırma özelliklerini desteklemek için faturalandırma eşitlemesini ayarlamanız gerekir." }, "billingSyncApiKeyRotated": { - "message": "Token rotated." + "message": "Anahtar yenilendi." }, "billingSync": { - "message": "Billing Sync" + "message": "Faturalandırma Eşitlemesi" }, "billingSyncDesc": { - "message": "Billing Sync provides Free Families plans for members and advanced billing capabilities by linking your self-hosted Bitwarden to the Bitwarden cloud server." + "message": "Faturalandırma Eşitlemesi, şirket içinde barındırılan Bitwarden'ınızı Bitwarden bulut sunucusuna bağlayarak üyeler için Ücretsiz Aile planları ve gelişmiş faturalandırma özellikleri sağlar." }, "billingSyncKeyDesc": { - "message": "A Billing Sync Token from your cloud organization's subscription settings is required to complete this form." + "message": "Bu formu doldurmak için bulut kuruluşunuzun abonelik ayarlarından bir Faturalandırma Eşitleme Anahtarı gerekir." }, "billingSyncKey": { - "message": "Billing Sync Token" + "message": "Faturalandırma Eşitleme Anahtarı" }, "active": { "message": "Aktif" @@ -5071,13 +5077,13 @@ "message": "zorunlu" }, "idpSingleSignOnServiceUrlRequired": { - "message": "Required if Entity ID is not a URL." + "message": "Varlık Kimliği bir URL değilse gereklidir." }, "openIdOptionalCustomizations": { "message": "İsteğe Bağlı Özelleştirmeler" }, "openIdAuthorityRequired": { - "message": "Required if Authority is not valid." + "message": "Yetki geçerli değilse gereklidir." }, "separateMultipleWithComma": { "message": "Birden fazla değeri virgülle ayırabilirsiniz." @@ -5179,10 +5185,10 @@ "message": "Servis" }, "unknownCipher": { - "message": "Unknown Item, you may need to request permission to access this item." + "message": "Bilinmeyen Öğe, bu öğeye erişmek için izin istemeniz gerekebilir." }, "cannotSponsorSelf": { - "message": "You cannot redeem for the active account. Enter a different email." + "message": "Aktif hesap için kullanamazsınız. Farklı bir e-posta girin." }, "revokeWhenExpired": { "message": "Süre sonu: $DATE$", @@ -5194,7 +5200,7 @@ } }, "awaitingSyncSingular": { - "message": "Token rotated $DAYS$ day ago. Update the billing sync token in your self-hosted organization settings.", + "message": "Anahtar $DAYS$ gün önce yenilendi. Şirket içinde barındırılan kuruluş ayarlarınızda faturalandırma eşitleme anahtarını güncelleyin.", "placeholders": { "days": { "content": "$1", @@ -5203,7 +5209,7 @@ } }, "awaitingSyncPlural": { - "message": "Token rotated $DAYS$ days ago. Update the billing sync token in your self-hosted organization settings.", + "message": "Anahtar $DAYS$ gün önce yenilendi. Şirket içinde barındırılan kuruluş ayarlarınızda faturalandırma eşitleme anahtarını güncelleyin.", "placeholders": { "days": { "content": "$1", @@ -5216,7 +5222,7 @@ "Description": "Used as a prefix to indicate the last time a sync occured. Example \"Last sync 1968-11-16 00:00:00\"" }, "sponsorshipsSynced": { - "message": "Self-hosted sponsorships synced." + "message": "Kendi kendine barındırılan sponsorluklar eşitlendi." }, "billingManagedByProvider": { "message": "Yönetici: $PROVIDER$", @@ -5251,13 +5257,13 @@ "message": "Cihaz doğrulamasını etkinleştir" }, "deviceVerificationDesc": { - "message": "When enabled, verification codes are sent to your email address when logging in from an unrecognized device" + "message": "Etkinleştirildiğinde, tanınmayan bir cihazdan oturum açarken e-posta adresinize doğrulama kodları gönderilir" }, "updatedDeviceVerification": { "message": "Cihaz doğrulaması güncellendi" }, "areYouSureYouWantToEnableDeviceVerificationTheVerificationCodeEmailsWillArriveAtX": { - "message": "Are you sure you want to enable Device Verification? The verification code emails will arrive at: $EMAIL$", + "message": "Cihaz Doğrulamayı etkinleştirmek istediğinizden emin misiniz? Doğrulama kodu e-postaları şu adrese gelecek: $EMAIL$", "placeholders": { "email": { "content": "$1", @@ -5269,67 +5275,67 @@ "message": "Premium abonelik gerekli" }, "scim": { - "message": "SCIM Provisioning", + "message": "SCIM Sağlama", "description": "The text, 'SCIM', is an acronymn and should not be translated." }, "scimDescription": { - "message": "Automatically provision users and groups with your preferred identity provider via SCIM provisioning", + "message": "SCIM sağlama yoluyla tercih ettiğiniz kimlik sağlayıcıyla kullanıcıları ve grupları otomatik olarak sağlayın", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimEnabledCheckboxDesc": { - "message": "Enable SCIM", + "message": "SCIM'i etkinleştir", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimEnabledCheckboxDescHelpText": { - "message": "Set up your preferred identity provider by configuring the URL and SCIM API Key", + "message": "URL'yi ve SCIM API Anahtarını yapılandırarak tercih ettiğiniz kimlik sağlayıcısını ayarlayın", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "scimApiKeyHelperText": { - "message": "This API key has access to manage users within your organization. It should be kept secret." + "message": "Bu API anahtarı, kuruluşunuzdaki kullanıcıları yönetme erişimine sahiptir. Gizli tutulmalıdır." }, "copyScimKey": { - "message": "Copy the SCIM API Key to your clipboard", + "message": "SCIM API Anahtarını panonuza kopyalayın", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateScimKey": { - "message": "Rotate the SCIM API Key", + "message": "SCIM API Anahtarını yenileyin", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateScimKeyWarning": { - "message": "Are you sure you want to rotate the SCIM API Key? The current key will no longer work for any existing integrations.", + "message": "SCIM API Anahtarını yenilemek istediğinizden emin misiniz? Geçerli anahtar, mevcut tüm entegrasyonlar için artık çalışmayacaktır.", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "rotateKey": { - "message": "Rotate Key" + "message": "Anahtarı Yenile" }, "scimApiKey": { - "message": "SCIM API Key", + "message": "SCIM API Anahtarı", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "copyScimUrl": { - "message": "Copy the SCIM endpoint URL to your clipboard", + "message": "SCIM uç noktası URL'sini panonuza kopyalayın", "description": "the text, 'SCIM' and 'URL', are acronymns and should not be translated." }, "scimUrl": { - "message": "SCIM URL", + "message": "SCIM URL'si", "description": "the text, 'SCIM' and 'URL', are acronymns and should not be translated." }, "scimApiKeyRotated": { - "message": "The SCIM API Key has been successfully rotated", + "message": "SCIM API Anahtarı başarıyla yenilendi", "description": "the text, 'SCIM' and 'API', are acronymns and should not be translated." }, "scimSettingsSaved": { - "message": "SCIM settings have been saved successfully", + "message": "SCIM ayarları başarıyla kaydedildi", "description": "the text, 'SCIM', is an acronymn and should not be translated." }, "inputRequired": { "message": "Girdi gerekli." }, "inputEmail": { - "message": "Input is not an email-address." + "message": "Girdi bir e-posta adresi değil." }, "inputMinLength": { - "message": "Input must be at least $COUNT$ characters long.", + "message": "Giriş, en az $COUNT$ karakter uzunluğunda olmalıdır.", "placeholders": { "count": { "content": "$1", @@ -5338,7 +5344,7 @@ } }, "fieldsNeedAttention": { - "message": "$COUNT$ field(s) above need your attention.", + "message": "Üstteki $COUNT$ alan(lar) la ilgilenmeniz gerekiyor.", "placeholders": { "count": { "content": "$1", diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 464af5736fa..b774c28e298 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -912,10 +912,10 @@ "message": "Підтвердьте пароль файлу" }, "accountBackupOptionDescription": { - "message": "Завжди використовує шифрування облікового запису Bitwarden, а не головний пароль для захисту експорту. Цей експорт можна імпортувати лише в поточний обліковий запис. Використовуйте його для створення резервної копії, яку не можна використовувати в іншому місці." + "message": "Використовуйте ключ шифрування облікового запису, щоб зашифрувати експортований файл і дозволити його імпорт лише до поточного облікового запису Bitwarden." }, "passwordProtectedOptionDescription": { - "message": "Створити користувацький пароль для захисту експорту. Використовуйте це для створення експорту, який може бути використаний в інших облікових записах." + "message": "Встановіть пароль, щоб зашифрувати експортований файл та дозволити імпорт до будь-якого облікового запису Bitwarden за допомогою цього пароля." }, "fileTypeHeading": { "message": "Тип файлу" @@ -4057,6 +4057,12 @@ "permissions": { "message": "Дозволи" }, + "managerPermissions": { + "message": "Дозволи менеджера" + }, + "adminPermissions": { + "message": "Дозволи адміністратора" + }, "accessEventLogs": { "message": "Доступ до журналів подій" }, diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index 7842e65b5fe..dfad84612e8 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -4057,6 +4057,12 @@ "permissions": { "message": "Permissions" }, + "managerPermissions": { + "message": "Manager Permissions" + }, + "adminPermissions": { + "message": "Admin Permissions" + }, "accessEventLogs": { "message": "Access Event Logs" }, diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index ac34e62c36c..3e7d64fa465 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -915,7 +915,7 @@ "message": "使用您的账户加密密钥来加密导出的数据,并且限制只能导入到当前的 Bitwarden 账户。" }, "passwordProtectedOptionDescription": { - "message": "设置一个密码用来加密导出的数据,并使用此密码解密以导入到任何 Bitwarden 账户。" + "message": "设置一个密码用来加密导出的数据,并使用此密码解密以导入到任意 Bitwarden 账户。" }, "fileTypeHeading": { "message": "文件类型" @@ -4057,6 +4057,12 @@ "permissions": { "message": "权限" }, + "managerPermissions": { + "message": "经理权限" + }, + "adminPermissions": { + "message": "管理员权限" + }, "accessEventLogs": { "message": "访问事件日志" }, diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index a083d86e490..a125fe17477 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -679,7 +679,7 @@ "message": "無效的主密碼" }, "invalidFilePassword": { - "message": "檔案密碼無效,請使用創建匯出檔案時輸入的密碼。" + "message": "檔案密碼無效,請使用您當初匯出檔案時輸入的密碼。" }, "lockNow": { "message": "立即鎖定" @@ -912,10 +912,10 @@ "message": "確認檔案密碼" }, "accountBackupOptionDescription": { - "message": "使用您的帳戶加密金鑰來加密匯出的資料,並限制只能匯入到目前的 Bitwarden 帳戶。" + "message": "使用您的帳戶加密金鑰來加密匯出的資料,並限制它只能匯入至目前的 Bitwarden 帳戶。" }, "passwordProtectedOptionDescription": { - "message": "設定一个密碼來加密匯出的資料,並使用此密碼解密以匯入到任何 Bitwarden 帳戶。" + "message": "設定一組密碼來加密匯出的資料,並使用此密碼解密以匯入至任意 Bitwarden 帳戶。" }, "fileTypeHeading": { "message": "檔案類型" @@ -4057,6 +4057,12 @@ "permissions": { "message": "權限" }, + "managerPermissions": { + "message": "權限管理" + }, + "adminPermissions": { + "message": "管理員權限" + }, "accessEventLogs": { "message": "存取事件紀錄" }, diff --git a/apps/web/src/scss/modals.scss b/apps/web/src/scss/modals.scss index f28dab845dd..29e7191cd72 100644 --- a/apps/web/src/scss/modals.scss +++ b/apps/web/src/scss/modals.scss @@ -41,6 +41,10 @@ border-bottom: 1px solid themed("separator"); color: themed("textColor"); } + + .modal-title { + font-size: 1.3rem; + } } .modal-body { diff --git a/apps/web/src/utils/flags.ts b/apps/web/src/utils/flags.ts index 5cc3b930bb4..195bc8e5f54 100644 --- a/apps/web/src/utils/flags.ts +++ b/apps/web/src/utils/flags.ts @@ -10,6 +10,7 @@ import { /* eslint-disable-next-line @typescript-eslint/ban-types */ export type Flags = { showTrial?: boolean; + showPasswordless?: boolean; } & SharedFlags; // required to avoid linting errors when there are no flags diff --git a/apps/web/webpack.config.js b/apps/web/webpack.config.js index 6ddff6edd5a..3b472c45d4e 100644 --- a/apps/web/webpack.config.js +++ b/apps/web/webpack.config.js @@ -235,7 +235,7 @@ const devServer = https://*.paypal.com 'sha256-47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' 'sha256-JVRXyYPueLWdwGwY9m/7u4QlZ1xeQdqUj2t8OVIzZE4='; - 'sha256-0xHKHIT3+e2Gknxsm/cpErSprhL+o254L/y5bljg74U=' + 'sha256-or0p3LaHetJ4FRq+flVORVFFNsOjQGWrDvX8Jf7ACWg=' img-src 'self' data: @@ -273,7 +273,8 @@ const devServer = https://app.simplelogin.io/api/alias/random/new https://quack.duckduckgo.com/api/email/addresses https://app.anonaddy.com/api/v1/aliases - https://api.fastmail.com/jmap/api; + https://api.fastmail.com + https://quack.duckduckgo.com/api/email/addresses; object-src 'self' blob:;`, diff --git a/bitwarden_license/bit-web/src/app/organizations/components/base-cva.component.ts b/bitwarden_license/bit-web/src/app/organizations/components/base-cva.component.ts index e49eac0c596..11fb78e41e0 100644 --- a/bitwarden_license/bit-web/src/app/organizations/components/base-cva.component.ts +++ b/bitwarden_license/bit-web/src/app/organizations/components/base-cva.component.ts @@ -1,8 +1,6 @@ import { Directive, Input, OnInit, Self } from "@angular/core"; import { ControlValueAccessor, UntypedFormControl, NgControl, Validators } from "@angular/forms"; -import { dirtyRequired } from "@bitwarden/angular/validators/dirty.validator"; - /** For use in the SSO Config Form only - will be deprecated by the Component Library */ @Directive() export abstract class BaseCvaComponent implements ControlValueAccessor, OnInit { @@ -15,10 +13,7 @@ export abstract class BaseCvaComponent implements ControlValueAccessor, OnInit { } get isRequired() { - return ( - this.controlDir.control.hasValidator(Validators.required) || - this.controlDir.control.hasValidator(dirtyRequired) - ); + return this.controlDir.control.hasValidator(Validators.required); } @Input() label: string; diff --git a/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.html b/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.html deleted file mode 100644 index b25edf63636..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
      - -
      - -
      - -
      -
      - -
      -
      -
      diff --git a/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.ts b/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.ts deleted file mode 100644 index 4b9a675b087..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/input-text-readonly.component.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service"; - -/** For use in the SSO Config Form only - will be deprecated by the Component Library */ -@Component({ - selector: "app-input-text-readonly", - templateUrl: "input-text-readonly.component.html", -}) -export class InputTextReadOnlyComponent { - @Input() controlValue: string; - @Input() label: string; - @Input() showCopy = true; - @Input() showLaunch = false; - - constructor(private platformUtilsService: PlatformUtilsService) {} - - copy(value: string) { - this.platformUtilsService.copyToClipboard(value); - } - - launchUri(url: string) { - this.platformUtilsService.launchUri(url); - } -} diff --git a/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.html b/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.html deleted file mode 100644 index e19963474ca..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.html +++ /dev/null @@ -1,33 +0,0 @@ -
      - - -
      - - {{ helperText }} - - - - {{ "error" | i18n }}: - {{ - controlDir.control.hasError(helperTextSameAsError) - ? helperText - : ("fieldRequiredError" | i18n: label) - }} - -
      -
      diff --git a/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.ts b/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.ts deleted file mode 100644 index a8810e38068..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/input-text.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Component, Input, OnInit } from "@angular/core"; - -import { BaseCvaComponent } from "./base-cva.component"; - -/** For use in the SSO Config Form only - will be deprecated by the Component Library */ -@Component({ - selector: "app-input-text[label][controlId]", - templateUrl: "input-text.component.html", -}) -export class InputTextComponent extends BaseCvaComponent implements OnInit { - @Input() helperTextSameAsError: string; - @Input() requiredErrorMessage: string; - @Input() stripSpaces = false; - - transformValue: (value: string) => string = null; - - ngOnInit() { - super.ngOnInit(); - if (this.stripSpaces) { - this.transformValue = this.doStripSpaces; - } - } - - writeValue(value: string) { - this.internalControl.setValue(value == null ? "" : value); - } - - protected onValueChangesInternal: any = (value: string) => { - let newValue = value; - if (this.transformValue != null) { - newValue = this.transformValue(value); - this.internalControl.setValue(newValue, { emitEvent: false }); - } - this.onChange(newValue); - }; - - protected onValueChangeInternal(value: string) { - let newValue = value; - if (this.transformValue != null) { - newValue = this.transformValue(value); - this.internalControl.setValue(newValue, { emitEvent: false }); - } - } - - private doStripSpaces(value: string) { - return value.replace(/ /g, ""); - } -} diff --git a/bitwarden_license/bit-web/src/app/organizations/components/select.component.html b/bitwarden_license/bit-web/src/app/organizations/components/select.component.html deleted file mode 100644 index bc2108e8afe..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/select.component.html +++ /dev/null @@ -1,19 +0,0 @@ -
      - - -
      diff --git a/bitwarden_license/bit-web/src/app/organizations/components/select.component.ts b/bitwarden_license/bit-web/src/app/organizations/components/select.component.ts deleted file mode 100644 index 5c2ab308672..00000000000 --- a/bitwarden_license/bit-web/src/app/organizations/components/select.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { SelectOptions } from "@bitwarden/angular/interfaces/selectOptions"; - -import { BaseCvaComponent } from "./base-cva.component"; - -/** For use in the SSO Config Form only - will be deprecated by the Component Library */ -@Component({ - selector: "app-select", - templateUrl: "select.component.html", -}) -export class SelectComponent extends BaseCvaComponent { - @Input() selectOptions: SelectOptions[]; -} diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html index 54fe44e073c..3d27448753f 100644 --- a/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html +++ b/bitwarden_license/bit-web/src/app/organizations/manage/scim.component.html @@ -81,7 +81,13 @@ {{ "scimApiKeyHelperText" | i18n }} - + diff --git a/bitwarden_license/bit-web/src/app/organizations/manage/sso.component.html b/bitwarden_license/bit-web/src/app/organizations/manage/sso.component.html index 525dc22b8ed..fdb613d44f2 100644 --- a/bitwarden_license/bit-web/src/app/organizations/manage/sso.component.html +++ b/bitwarden_license/bit-web/src/app/organizations/manage/sso.component.html @@ -35,6 +35,14 @@ [helperText]="'allowSsoDesc' | i18n" > + + {{ "ssoIdentifier" | i18n }} + + {{ "ssoIdentifierHint" | i18n }} + + +
      +
      @@ -80,66 +88,55 @@ {{ "keyConnectorWarning" | i18n }} -
      - -
      - -
      - -
      -
      -
      - - - {{ "error" | i18n }}: - {{ "keyConnectorTestFail" | i18n }} + + {{ "keyConnectorUrl" | i18n }} + + + + + + {{ "keyConnectorTestSuccess" | i18n }} - - - - {{ "keyConnectorTestSuccess" | i18n }} - - -
      -
      + + - - +
      + + + {{ "type" | i18n }} + + @@ -150,52 +147,67 @@

      {{ "openIdConnectConfig" | i18n }}

      - + + {{ "callbackPath" | i18n }} + + + - + + {{ "signedOutCallbackPath" | i18n }} + + + - + + {{ "authority" | i18n }} + + - + + {{ "clientId" | i18n }} + + - + + {{ "clientSecret" | i18n }} + + - + + {{ "metadataAddress" | i18n }} + + {{ "openIdAuthorityRequired" | i18n }} + - - + + {{ "oidcRedirectBehavior" | i18n }} + +
      - + + {{ "additionalScopes" | i18n }} + + {{ "separateMultipleWithComma" | i18n }} + - + + {{ "additionalUserIdClaimTypes" | i18n }} + + {{ "separateMultipleWithComma" | i18n }} + - + + {{ "additionalEmailClaimTypes" | i18n }} + + {{ "separateMultipleWithComma" | i18n }} + - + + {{ "additionalNameClaimTypes" | i18n }} + + {{ "separateMultipleWithComma" | i18n }} + - + + {{ "acrValues" | i18n }} + + acr_values + - + + {{ "expectedReturnAcrValue" | i18n }} + + acr_validaton +
      @@ -282,53 +288,108 @@

      {{ "samlSpConfig" | i18n }}

      - + + {{ "spEntityId" | i18n }} + + + - + + {{ "spMetadataUrl" | i18n }} + + + + - + + {{ "spAcsUrl" | i18n }} + + + - - + + {{ "spNameIdFormat" | i18n }} + + - - + + {{ "spOutboundSigningAlgorithm" | i18n }} + + - - + + {{ "spSigningBehavior" | i18n }} + + - - + + {{ "spMinIncomingSigningAlgorithm" | i18n }} + +

      {{ "samlIdpConfig" | i18n }}

      - + + {{ "idpEntityId" | i18n }} + + - - + + {{ "idpBindingType" | i18n }} + + - + + {{ "idpSingleSignOnServiceUrl" | i18n }} + + {{ "idpSingleSignOnServiceUrlRequired" | i18n }} + - + + {{ "idpSingleLogoutServiceUrl" | i18n }} + + -
      - - - - - {{ "error" | i18n }}: - {{ "fieldRequiredError" | i18n: ("idpX509PublicCert" | i18n) }} - -
      + + {{ "idpX509PublicCert" | i18n }} + + - - + + {{ "idpOutboundSigningAlgorithm" | i18n }} + +