mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-24 21:41:33 +01:00
Merge branch 'main' into auth/pm-8111/browser-refresh-login-component
This commit is contained in:
commit
b564ff4ca5
45
.github/workflows/build-desktop.yml
vendored
45
.github/workflows/build-desktop.yml
vendored
@ -174,21 +174,20 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
apps/desktop/desktop_native/napi/*.node
|
apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
${{ env.RUNNER_TEMP }}/.cargo/registry
|
${{ env.RUNNER_TEMP }}/.cargo/registry
|
||||||
${{ env.RUNNER_TEMP }}/.cargo/git
|
${{ env.RUNNER_TEMP }}/.cargo/git
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
env:
|
env:
|
||||||
PKG_CONFIG_ALLOW_CROSS: true
|
PKG_CONFIG_ALLOW_CROSS: true
|
||||||
PKG_CONFIG_ALL_STATIC: true
|
PKG_CONFIG_ALL_STATIC: true
|
||||||
TARGET: musl
|
TARGET: musl
|
||||||
run: |
|
run: |
|
||||||
rustup target add x86_64-unknown-linux-musl
|
rustup target add x86_64-unknown-linux-musl
|
||||||
node build.js cross-platform
|
npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build application
|
- name: Build application
|
||||||
run: npm run dist:lin
|
run: npm run dist:lin
|
||||||
@ -302,15 +301,13 @@ jobs:
|
|||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/napi/*.node
|
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
run: node build.js cross-platform
|
run: npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build & Sign (dev)
|
- name: Build & Sign (dev)
|
||||||
env:
|
env:
|
||||||
@ -587,15 +584,13 @@ jobs:
|
|||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/napi/*.node
|
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
run: node build.js cross-platform
|
run: npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build application (dev)
|
- name: Build application (dev)
|
||||||
run: npm run build
|
run: npm run build
|
||||||
@ -753,15 +748,13 @@ jobs:
|
|||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/napi/*.node
|
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
run: node build.js cross-platform
|
run: npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||||
@ -972,15 +965,13 @@ jobs:
|
|||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/napi/*.node
|
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
run: node build.js cross-platform
|
run: npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||||
@ -1177,15 +1168,13 @@ jobs:
|
|||||||
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
|
||||||
id: cache
|
id: cache
|
||||||
with:
|
with:
|
||||||
path: |
|
path: apps/desktop/desktop_native/napi/*.node
|
||||||
apps/desktop/desktop_native/napi/*.node
|
|
||||||
apps/desktop/desktop_native/dist/*
|
|
||||||
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
key: rust-${{ runner.os }}-${{ hashFiles('apps/desktop/desktop_native/**/*') }}
|
||||||
|
|
||||||
- name: Build Native Module
|
- name: Build Native Module
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
working-directory: apps/desktop/desktop_native
|
working-directory: apps/desktop/desktop_native/napi
|
||||||
run: node build.js cross-platform
|
run: npm run build:cross-platform
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
if: steps.build-cache.outputs.cache-hit != 'true'
|
if: steps.build-cache.outputs.cache-hit != 'true'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/browser",
|
"name": "@bitwarden/browser",
|
||||||
"version": "2024.8.2",
|
"version": "2024.9.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "cross-env MANIFEST_VERSION=3 webpack",
|
"build": "cross-env MANIFEST_VERSION=3 webpack",
|
||||||
"build:mv2": "webpack",
|
"build:mv2": "webpack",
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "لا توجد كلمات مرور للعرض."
|
"message": "لا توجد كلمات مرور للعرض."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "إزالة"
|
"message": "إزالة"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Sadalanacaq heç bir parol yoxdur."
|
"message": "Sadalanacaq heç bir parol yoxdur."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Çıxart"
|
"message": "Çıxart"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Müəssisə siyasət tələbləri bu ayara tətbiq edildi"
|
"message": "Müəssisə siyasət tələbləri bu ayara tətbiq edildi"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Əlavə məzmun əlçatandır"
|
"message": "Xarakter sayını göstər"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Xarakter sayını gizlət"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Tullantıdakı elementlər"
|
"message": "Tullantıdakı elementlər"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "У спісе адсутнічаюць паролі."
|
"message": "У спісе адсутнічаюць паролі."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Выдаліць"
|
"message": "Выдаліць"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Няма пароли за показване."
|
"message": "Няма пароли за показване."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Изчистване на историята"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "Няма пароли за показване"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "Скоро не сте генерирали пароли"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Премахване"
|
"message": "Премахване"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Изискванията на политиката за големи компании бяха приложени към тази настройка"
|
"message": "Изискванията на политиката за големи компании бяха приложени към тази настройка"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Има налично допълнително съдържание"
|
"message": "Показване на броя знаци"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Скриване на броя знаци"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Елементи в кошчето"
|
"message": "Елементи в кошчето"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "তালিকার জন্য কোনও পাসওয়ার্ড নেই।"
|
"message": "তালিকার জন্য কোনও পাসওয়ার্ড নেই।"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "সরান"
|
"message": "সরান"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "No hi ha cap contrasenya a llistar."
|
"message": "No hi ha cap contrasenya a llistar."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Suprimeix"
|
"message": "Suprimeix"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Nejsou k dispozici žádná hesla."
|
"message": "Nejsou k dispozici žádná hesla."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Odebrat"
|
"message": "Odebrat"
|
||||||
},
|
},
|
||||||
@ -4125,7 +4134,7 @@
|
|||||||
"message": "Použijte zaškrtávací políčka, pokud chcete automaticky vyplnit zaškrtávací políčko formuláře (např. pro zapamatování e-mailu)"
|
"message": "Použijte zaškrtávací políčka, pokud chcete automaticky vyplnit zaškrtávací políčko formuláře (např. pro zapamatování e-mailu)"
|
||||||
},
|
},
|
||||||
"linkedHelpText": {
|
"linkedHelpText": {
|
||||||
"message": "Použijte propojené pole, pokud máte problémy s automatickým vyplňováním na konkrétní webové stránce"
|
"message": "Použijte propojené pole, pokud máte problémy s automatickým vyplňováním na konkrétní webové stránce."
|
||||||
},
|
},
|
||||||
"linkedLabelHelpText": {
|
"linkedLabelHelpText": {
|
||||||
"message": "Zadejte ID pole z HTML, název, popisek nebo zástupný znak pole."
|
"message": "Zadejte ID pole z HTML, název, popisek nebo zástupný znak pole."
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Na toto nastavení byly uplatněny požadavky podnikových zásad"
|
"message": "Na toto nastavení byly uplatněny požadavky podnikových zásad"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Je k dispozici další obsah"
|
"message": "Zobrazit počet znaků"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Skrýt počet znaků"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Položky v koši"
|
"message": "Položky v koši"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Does dim cyfrineiriau i'w rhestru."
|
"message": "Does dim cyfrineiriau i'w rhestru."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Tynnu"
|
"message": "Tynnu"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Der er ingen kodeord at vise."
|
"message": "Der er ingen kodeord at vise."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Fjern"
|
"message": "Fjern"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Virksomhedspolitikkrav er anvendt på denne indstilling"
|
"message": "Virksomhedspolitikkrav er anvendt på denne indstilling"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Yderligere indhold er tilgængeligt"
|
"message": "Vis tegnantal"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Skjul tegnantal"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Emner i papirkurv"
|
"message": "Emner i papirkurv"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Keine Einträge zum Anzeigen vorhanden."
|
"message": "Keine Einträge zum Anzeigen vorhanden."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Entfernen"
|
"message": "Entfernen"
|
||||||
},
|
},
|
||||||
@ -3478,7 +3487,7 @@
|
|||||||
"message": "Überprüfung durch die initiierende Website erforderlich. Diese Funktion ist noch nicht für Konten ohne Master-Passwort implementiert."
|
"message": "Überprüfung durch die initiierende Website erforderlich. Diese Funktion ist noch nicht für Konten ohne Master-Passwort implementiert."
|
||||||
},
|
},
|
||||||
"logInWithPasskeyQuestion": {
|
"logInWithPasskeyQuestion": {
|
||||||
"message": "Log in with passkey?"
|
"message": "Mit Passkey anmelden?"
|
||||||
},
|
},
|
||||||
"passkeyAlreadyExists": {
|
"passkeyAlreadyExists": {
|
||||||
"message": "Für diese Anwendung existiert bereits ein Passkey."
|
"message": "Für diese Anwendung existiert bereits ein Passkey."
|
||||||
@ -3490,7 +3499,7 @@
|
|||||||
"message": "Du hast keinen passenden Zugangsdaten für diese Website."
|
"message": "Du hast keinen passenden Zugangsdaten für diese Website."
|
||||||
},
|
},
|
||||||
"noMatchingLoginsForSite": {
|
"noMatchingLoginsForSite": {
|
||||||
"message": "No matching logins for this site"
|
"message": "Keine passenden Zugangsdaten für diese Seite"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Bestätigen"
|
"message": "Bestätigen"
|
||||||
@ -3502,10 +3511,10 @@
|
|||||||
"message": "Passkey als neue Zugangsdaten speichern"
|
"message": "Passkey als neue Zugangsdaten speichern"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeySave": {
|
"chooseCipherForPasskeySave": {
|
||||||
"message": "Choose a login to save this passkey to"
|
"message": "Wähle die Zugangsdaten aus, in die dieser Passkey gespeichert werden soll"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeyAuth": {
|
"chooseCipherForPasskeyAuth": {
|
||||||
"message": "Choose a passkey to log in with"
|
"message": "Wähle einen Passkey zum Anmelden"
|
||||||
},
|
},
|
||||||
"passkeyItem": {
|
"passkeyItem": {
|
||||||
"message": "Passkey-Eintrag"
|
"message": "Passkey-Eintrag"
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Unternehmens-Richtlinienanforderungen wurden auf diese Einstellung angewandt"
|
"message": "Unternehmens-Richtlinienanforderungen wurden auf diese Einstellung angewandt"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Zusätzlicher Inhalt ist verfügbar"
|
"message": "Zeichenanzahl anzeigen"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Zeichenanzahl ausblenden"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Einträge im Papierkorb"
|
"message": "Einträge im Papierkorb"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Δεν υπάρχουν κωδικοί στη λίστα."
|
"message": "Δεν υπάρχουν κωδικοί στη λίστα."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Αφαίρεση"
|
"message": "Αφαίρεση"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Οι απαιτήσεις της πολιτικής για επιχειρήσεις έχουν εφαρμοστεί σε αυτήν τη ρύθμιση"
|
"message": "Οι απαιτήσεις της πολιτικής για επιχειρήσεις έχουν εφαρμοστεί σε αυτήν τη ρύθμιση"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Πρόσθετο περιεχόμενο είναι διαθέσιμο"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Αντικείμενα στον κάδο"
|
"message": "Αντικείμενα στον κάδο"
|
||||||
|
@ -1799,6 +1799,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in the bin"
|
"message": "Items in the bin"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in bin"
|
"message": "Items in bin"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "No hay contraseñas que listar."
|
"message": "No hay contraseñas que listar."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Eliminar"
|
"message": "Eliminar"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Elementos en la papelera"
|
"message": "Elementos en la papelera"
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"message": "Logi oma olemasolevasse kontosse sisse või loo uus konto."
|
"message": "Logi oma olemasolevasse kontosse sisse või loo uus konto."
|
||||||
},
|
},
|
||||||
"inviteAccepted": {
|
"inviteAccepted": {
|
||||||
"message": "Invitation accepted"
|
"message": "Kutse vastu võetud"
|
||||||
},
|
},
|
||||||
"createAccount": {
|
"createAccount": {
|
||||||
"message": "Konto loomine"
|
"message": "Konto loomine"
|
||||||
@ -69,10 +69,10 @@
|
|||||||
"message": "Ülemparooli vihje (ei ole kohustuslik)"
|
"message": "Ülemparooli vihje (ei ole kohustuslik)"
|
||||||
},
|
},
|
||||||
"joinOrganization": {
|
"joinOrganization": {
|
||||||
"message": "Join organization"
|
"message": "Liitu organisatsiooniga"
|
||||||
},
|
},
|
||||||
"finishJoiningThisOrganizationBySettingAMasterPassword": {
|
"finishJoiningThisOrganizationBySettingAMasterPassword": {
|
||||||
"message": "Finish joining this organization by setting a master password."
|
"message": "Lõpeta organisatsiooniga liitumine määrates ülemparool."
|
||||||
},
|
},
|
||||||
"tab": {
|
"tab": {
|
||||||
"message": "Kaart"
|
"message": "Kaart"
|
||||||
@ -114,19 +114,19 @@
|
|||||||
"message": "Kopeeri turvakood"
|
"message": "Kopeeri turvakood"
|
||||||
},
|
},
|
||||||
"copyName": {
|
"copyName": {
|
||||||
"message": "Copy name"
|
"message": "Kopeeri nimi"
|
||||||
},
|
},
|
||||||
"copyCompany": {
|
"copyCompany": {
|
||||||
"message": "Copy company"
|
"message": "Kopeeri firma nimi"
|
||||||
},
|
},
|
||||||
"copySSN": {
|
"copySSN": {
|
||||||
"message": "Copy Social Security number"
|
"message": "Kopeeri isikukood"
|
||||||
},
|
},
|
||||||
"copyPassportNumber": {
|
"copyPassportNumber": {
|
||||||
"message": "Copy passport number"
|
"message": "Kopeeri passi number"
|
||||||
},
|
},
|
||||||
"copyLicenseNumber": {
|
"copyLicenseNumber": {
|
||||||
"message": "Copy license number"
|
"message": "Kopeeri litsentsi number"
|
||||||
},
|
},
|
||||||
"autoFill": {
|
"autoFill": {
|
||||||
"message": "Automaatne täitmine"
|
"message": "Automaatne täitmine"
|
||||||
@ -225,7 +225,7 @@
|
|||||||
"message": "Mine edasi veebilaienduste poodi?"
|
"message": "Mine edasi veebilaienduste poodi?"
|
||||||
},
|
},
|
||||||
"continueToBrowserExtensionStoreDesc": {
|
"continueToBrowserExtensionStoreDesc": {
|
||||||
"message": "Help others find out if Bitwarden is right for them. Visit your browser's extension store and leave a rating now."
|
"message": "Aita meil jõuda rohkemate inimesteni. Külasta enda laienduste veebipoodi ja jäta sinna positiivne hinnang."
|
||||||
},
|
},
|
||||||
"changeMasterPasswordOnWebConfirmation": {
|
"changeMasterPasswordOnWebConfirmation": {
|
||||||
"message": "Ülemparooli saab muuta Bitwardeni veebirakenduses."
|
"message": "Ülemparooli saab muuta Bitwardeni veebirakenduses."
|
||||||
@ -251,7 +251,7 @@
|
|||||||
"message": "Rakenduse info"
|
"message": "Rakenduse info"
|
||||||
},
|
},
|
||||||
"moreFromBitwarden": {
|
"moreFromBitwarden": {
|
||||||
"message": "More from Bitwarden"
|
"message": "Rohkem Bitwardeni kohta"
|
||||||
},
|
},
|
||||||
"continueToBitwardenDotCom": {
|
"continueToBitwardenDotCom": {
|
||||||
"message": "Mine edasi bitwarden.com-i?"
|
"message": "Mine edasi bitwarden.com-i?"
|
||||||
@ -263,25 +263,25 @@
|
|||||||
"message": "Bitwarden Authenticator"
|
"message": "Bitwarden Authenticator"
|
||||||
},
|
},
|
||||||
"continueToAuthenticatorPageDesc": {
|
"continueToAuthenticatorPageDesc": {
|
||||||
"message": "Bitwarden Authenticator allows you to store authenticator keys and generate TOTP codes for 2-step verification flows. Learn more on the bitwarden.com website"
|
"message": "Bitwardeni Autentiteerijaga saad sa hoiustada autentiteerimise võtmeid ja luua TOTP koode kaheastmeliseks kinnitamiseks. Uuri lähemalt veebilehelt bitwarden.com"
|
||||||
},
|
},
|
||||||
"bitwardenSecretsManager": {
|
"bitwardenSecretsManager": {
|
||||||
"message": "Bitwarden Secrets Manager"
|
"message": "Bitwarden Secrets Manager"
|
||||||
},
|
},
|
||||||
"continueToSecretsManagerPageDesc": {
|
"continueToSecretsManagerPageDesc": {
|
||||||
"message": "Securely store, manage, and share developer secrets with Bitwarden Secrets Manager. Learn more on the bitwarden.com website."
|
"message": "Hoiusta, halda ja jaga turvaliselt arendajate saladusi läbi Bitwarden Secrets Manageri. Uuri lähemalt veebilehelt bitwarden.com."
|
||||||
},
|
},
|
||||||
"passwordlessDotDev": {
|
"passwordlessDotDev": {
|
||||||
"message": "Passwordless.dev"
|
"message": "Passwordless.dev"
|
||||||
},
|
},
|
||||||
"continueToPasswordlessDotDevPageDesc": {
|
"continueToPasswordlessDotDevPageDesc": {
|
||||||
"message": "Create smooth and secure login experiences free from traditional passwords with Passwordless.dev. Learn more on the bitwarden.com website."
|
"message": "Loo sujuv ja turvaline kogemus sisselogimisel Passwordless.dev-iga ja ilma traditsiooniliste paroolideta. Uuri lähemalt veebilehelt bitwarden.com."
|
||||||
},
|
},
|
||||||
"freeBitwardenFamilies": {
|
"freeBitwardenFamilies": {
|
||||||
"message": "Tasuta Bitwarden Peredele"
|
"message": "Tasuta Bitwarden Peredele"
|
||||||
},
|
},
|
||||||
"freeBitwardenFamiliesPageDesc": {
|
"freeBitwardenFamiliesPageDesc": {
|
||||||
"message": "You are eligible for Free Bitwarden Families. Redeem this offer today in the web app."
|
"message": "Sul on võimalik saada endale tasuta Bitwarden Families plaan. Lunasta see pakkumine meie veebirakenduses."
|
||||||
},
|
},
|
||||||
"version": {
|
"version": {
|
||||||
"message": "Versioon"
|
"message": "Versioon"
|
||||||
@ -302,22 +302,22 @@
|
|||||||
"message": "Muuda kausta"
|
"message": "Muuda kausta"
|
||||||
},
|
},
|
||||||
"newFolder": {
|
"newFolder": {
|
||||||
"message": "New folder"
|
"message": "Uus kaust"
|
||||||
},
|
},
|
||||||
"folderName": {
|
"folderName": {
|
||||||
"message": "Folder name"
|
"message": "Kausta nimi"
|
||||||
},
|
},
|
||||||
"folderHintText": {
|
"folderHintText": {
|
||||||
"message": "Nest a folder by adding the parent folder's name followed by a “/”. Example: Social/Forums"
|
"message": "Kausta teise kasuta panemiseks lisa sihtkausta nimi, millele järgneb \"/\". Näiteks: Sotsiaalmeedia/Foorumid"
|
||||||
},
|
},
|
||||||
"noFoldersAdded": {
|
"noFoldersAdded": {
|
||||||
"message": "No folders added"
|
"message": "Ei lisanud ühtegi kausta"
|
||||||
},
|
},
|
||||||
"createFoldersToOrganize": {
|
"createFoldersToOrganize": {
|
||||||
"message": "Create folders to organize your vault items"
|
"message": "Loo kaustasid, et oma hoidla kirjeid organiseerida"
|
||||||
},
|
},
|
||||||
"deleteFolderPermanently": {
|
"deleteFolderPermanently": {
|
||||||
"message": "Are you sure you want to permanently delete this folder?"
|
"message": "Kas sa oled kindel, et soovid selle kausta jäädavalt kustutada?"
|
||||||
},
|
},
|
||||||
"deleteFolder": {
|
"deleteFolder": {
|
||||||
"message": "Kustuta Kaust"
|
"message": "Kustuta Kaust"
|
||||||
@ -400,11 +400,11 @@
|
|||||||
"description": "deprecated. Use specialCharactersLabel instead."
|
"description": "deprecated. Use specialCharactersLabel instead."
|
||||||
},
|
},
|
||||||
"include": {
|
"include": {
|
||||||
"message": "Include",
|
"message": "Kasuta",
|
||||||
"description": "Card header for password generator include block"
|
"description": "Card header for password generator include block"
|
||||||
},
|
},
|
||||||
"uppercaseDescription": {
|
"uppercaseDescription": {
|
||||||
"message": "Include uppercase characters",
|
"message": "Kasuta trükitähti",
|
||||||
"description": "Tooltip for the password generator uppercase character checkbox"
|
"description": "Tooltip for the password generator uppercase character checkbox"
|
||||||
},
|
},
|
||||||
"uppercaseLabel": {
|
"uppercaseLabel": {
|
||||||
@ -412,7 +412,7 @@
|
|||||||
"description": "Label for the password generator uppercase character checkbox"
|
"description": "Label for the password generator uppercase character checkbox"
|
||||||
},
|
},
|
||||||
"lowercaseDescription": {
|
"lowercaseDescription": {
|
||||||
"message": "Include lowercase characters",
|
"message": "Kasuta kirjatähti",
|
||||||
"description": "Full description for the password generator lowercase character checkbox"
|
"description": "Full description for the password generator lowercase character checkbox"
|
||||||
},
|
},
|
||||||
"lowercaseLabel": {
|
"lowercaseLabel": {
|
||||||
@ -420,7 +420,7 @@
|
|||||||
"description": "Label for the password generator lowercase character checkbox"
|
"description": "Label for the password generator lowercase character checkbox"
|
||||||
},
|
},
|
||||||
"numbersDescription": {
|
"numbersDescription": {
|
||||||
"message": "Include numbers",
|
"message": "Kasuta numbreid",
|
||||||
"description": "Full description for the password generator numbers checkbox"
|
"description": "Full description for the password generator numbers checkbox"
|
||||||
},
|
},
|
||||||
"numbersLabel": {
|
"numbersLabel": {
|
||||||
@ -428,7 +428,7 @@
|
|||||||
"description": "Label for the password generator numbers checkbox"
|
"description": "Label for the password generator numbers checkbox"
|
||||||
},
|
},
|
||||||
"specialCharactersDescription": {
|
"specialCharactersDescription": {
|
||||||
"message": "Include special characters",
|
"message": "Kasuta sümboleid",
|
||||||
"description": "Full description for the password generator special characters checkbox"
|
"description": "Full description for the password generator special characters checkbox"
|
||||||
},
|
},
|
||||||
"specialCharactersLabel": {
|
"specialCharactersLabel": {
|
||||||
@ -459,7 +459,7 @@
|
|||||||
"description": "deprecated. Use avoidAmbiguous instead."
|
"description": "deprecated. Use avoidAmbiguous instead."
|
||||||
},
|
},
|
||||||
"avoidAmbiguous": {
|
"avoidAmbiguous": {
|
||||||
"message": "Avoid ambiguous characters",
|
"message": "Väldi raskesti eristatavaid tähti ja sümboleid",
|
||||||
"description": "Label for the avoid ambiguous characters checkbox."
|
"description": "Label for the avoid ambiguous characters checkbox."
|
||||||
},
|
},
|
||||||
"searchVault": {
|
"searchVault": {
|
||||||
@ -484,7 +484,7 @@
|
|||||||
"message": "Parool"
|
"message": "Parool"
|
||||||
},
|
},
|
||||||
"totp": {
|
"totp": {
|
||||||
"message": "Authenticator secret"
|
"message": "Salajane autentikaatori võti"
|
||||||
},
|
},
|
||||||
"passphrase": {
|
"passphrase": {
|
||||||
"message": "Paroolifraas"
|
"message": "Paroolifraas"
|
||||||
@ -538,13 +538,13 @@
|
|||||||
"message": "Muu"
|
"message": "Muu"
|
||||||
},
|
},
|
||||||
"unlockMethods": {
|
"unlockMethods": {
|
||||||
"message": "Unlock options"
|
"message": "Avamise valikud"
|
||||||
},
|
},
|
||||||
"unlockMethodNeededToChangeTimeoutActionDesc": {
|
"unlockMethodNeededToChangeTimeoutActionDesc": {
|
||||||
"message": "Hoidla ajalõpu tegevuse muutmiseks vali esmalt lahtilukustamise meetod."
|
"message": "Hoidla ajalõpu tegevuse muutmiseks vali esmalt lahtilukustamise meetod."
|
||||||
},
|
},
|
||||||
"unlockMethodNeeded": {
|
"unlockMethodNeeded": {
|
||||||
"message": "Set up an unlock method in Settings"
|
"message": "Määra avamise meetod seadetes"
|
||||||
},
|
},
|
||||||
"sessionTimeoutHeader": {
|
"sessionTimeoutHeader": {
|
||||||
"message": "Sessiooni ajalõpp"
|
"message": "Sessiooni ajalõpp"
|
||||||
@ -684,10 +684,10 @@
|
|||||||
"message": "Konto on loodud! Võid nüüd sisse logida."
|
"message": "Konto on loodud! Võid nüüd sisse logida."
|
||||||
},
|
},
|
||||||
"newAccountCreated2": {
|
"newAccountCreated2": {
|
||||||
"message": "Your new account has been created!"
|
"message": "Uus konto loodud!"
|
||||||
},
|
},
|
||||||
"youHaveBeenLoggedIn": {
|
"youHaveBeenLoggedIn": {
|
||||||
"message": "You have been logged in!"
|
"message": "Olete sisse logitud!"
|
||||||
},
|
},
|
||||||
"youSuccessfullyLoggedIn": {
|
"youSuccessfullyLoggedIn": {
|
||||||
"message": "Sisselogimine õnnestus"
|
"message": "Sisselogimine õnnestus"
|
||||||
@ -702,7 +702,7 @@
|
|||||||
"message": "Nõutav on kinnituskood."
|
"message": "Nõutav on kinnituskood."
|
||||||
},
|
},
|
||||||
"webauthnCancelOrTimeout": {
|
"webauthnCancelOrTimeout": {
|
||||||
"message": "The authentication was cancelled or took too long. Please try again."
|
"message": "Autentimine tühistati või kestis liiga kaua aega. Palun proovi uuesti."
|
||||||
},
|
},
|
||||||
"invalidVerificationCode": {
|
"invalidVerificationCode": {
|
||||||
"message": "Vale kinnituskood"
|
"message": "Vale kinnituskood"
|
||||||
@ -724,25 +724,25 @@
|
|||||||
"message": "Ei õnnestunud skännida sellelt lehelt QR-kood"
|
"message": "Ei õnnestunud skännida sellelt lehelt QR-kood"
|
||||||
},
|
},
|
||||||
"totpCaptureSuccess": {
|
"totpCaptureSuccess": {
|
||||||
"message": "Authenticator key added"
|
"message": "Autentimise võti on lisatud"
|
||||||
},
|
},
|
||||||
"totpCapture": {
|
"totpCapture": {
|
||||||
"message": "Scan authenticator QR code from current webpage"
|
"message": "Skänneeri see QR-kood läbi autentikaatori"
|
||||||
},
|
},
|
||||||
"totpHelperTitle": {
|
"totpHelperTitle": {
|
||||||
"message": "Make 2-step verification seamless"
|
"message": "Muuda 2-astmeline kinnitamine sujuvaks"
|
||||||
},
|
},
|
||||||
"totpHelper": {
|
"totpHelper": {
|
||||||
"message": "Bitwarden can store and fill 2-step verification codes. Copy and paste the key into this field."
|
"message": "Bitwarden saab hoiustada ja täita 2-astmelise kinnitamise koode. Kopeeri ja kleebi võti siia."
|
||||||
},
|
},
|
||||||
"totpHelperWithCapture": {
|
"totpHelperWithCapture": {
|
||||||
"message": "Bitwarden can store and fill 2-step verification codes. Select the camera icon to take a screenshot of this website's authenticator QR code, or copy and paste the key into this field."
|
"message": "Bitwarden saab hoiustada ja täita 2-astmelise kinnitamise koode. Vajuta kaamera ikoonile, et teha ekraanipilt autentiteerimise QR koodist või kopeeri ja kleebi võti siia."
|
||||||
},
|
},
|
||||||
"learnMoreAboutAuthenticators": {
|
"learnMoreAboutAuthenticators": {
|
||||||
"message": "Learn more about authenticators"
|
"message": "Uuri lähemalt autentikaatorite kohta"
|
||||||
},
|
},
|
||||||
"copyTOTP": {
|
"copyTOTP": {
|
||||||
"message": "Copy Authenticator key (TOTP)"
|
"message": "Kopeeri autentiteerimise võti (TOTP)"
|
||||||
},
|
},
|
||||||
"loggedOut": {
|
"loggedOut": {
|
||||||
"message": "Välja logitud"
|
"message": "Välja logitud"
|
||||||
@ -754,16 +754,16 @@
|
|||||||
"message": "Sessioon on aegunud."
|
"message": "Sessioon on aegunud."
|
||||||
},
|
},
|
||||||
"logIn": {
|
"logIn": {
|
||||||
"message": "Log in"
|
"message": "Logi sisse"
|
||||||
},
|
},
|
||||||
"restartRegistration": {
|
"restartRegistration": {
|
||||||
"message": "Restart registration"
|
"message": "Alusta registreerimist uuesti"
|
||||||
},
|
},
|
||||||
"expiredLink": {
|
"expiredLink": {
|
||||||
"message": "Expired link"
|
"message": "Aegunud link"
|
||||||
},
|
},
|
||||||
"pleaseRestartRegistrationOrTryLoggingIn": {
|
"pleaseRestartRegistrationOrTryLoggingIn": {
|
||||||
"message": "Please restart registration or try logging in."
|
"message": "Palun alusta registreerimist uuesti või proovi sisse logida."
|
||||||
},
|
},
|
||||||
"youMayAlreadyHaveAnAccount": {
|
"youMayAlreadyHaveAnAccount": {
|
||||||
"message": "You may already have an account"
|
"message": "You may already have an account"
|
||||||
@ -1469,7 +1469,7 @@
|
|||||||
"message": "Boolean"
|
"message": "Boolean"
|
||||||
},
|
},
|
||||||
"cfTypeCheckbox": {
|
"cfTypeCheckbox": {
|
||||||
"message": "Checkbox"
|
"message": "Märkeruut"
|
||||||
},
|
},
|
||||||
"cfTypeLinked": {
|
"cfTypeLinked": {
|
||||||
"message": "Ühenduses",
|
"message": "Ühenduses",
|
||||||
@ -1492,7 +1492,7 @@
|
|||||||
"message": "Kuvab iga kirje kõrval lehekülje ikooni."
|
"message": "Kuvab iga kirje kõrval lehekülje ikooni."
|
||||||
},
|
},
|
||||||
"faviconDescAlt": {
|
"faviconDescAlt": {
|
||||||
"message": "Show a recognizable image next to each login. Applies to all logged in accounts."
|
"message": "Näita väikest tuttavat ikooni iga kirje kõrval. Kehtib ka sisselogitud kontodele."
|
||||||
},
|
},
|
||||||
"enableBadgeCounter": {
|
"enableBadgeCounter": {
|
||||||
"message": "Kuva kirjete arvu"
|
"message": "Kuva kirjete arvu"
|
||||||
@ -1654,7 +1654,7 @@
|
|||||||
"message": "Identiteet"
|
"message": "Identiteet"
|
||||||
},
|
},
|
||||||
"newItemHeader": {
|
"newItemHeader": {
|
||||||
"message": "New $TYPE$",
|
"message": "Uus $TYPE$",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"type": {
|
"type": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@ -1690,7 +1690,7 @@
|
|||||||
"message": "Kogumikud"
|
"message": "Kogumikud"
|
||||||
},
|
},
|
||||||
"nCollections": {
|
"nCollections": {
|
||||||
"message": "$COUNT$ collections",
|
"message": "$COUNT$ kogumikku",
|
||||||
"placeholders": {
|
"placeholders": {
|
||||||
"count": {
|
"count": {
|
||||||
"content": "$1",
|
"content": "$1",
|
||||||
@ -1743,7 +1743,7 @@
|
|||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"baseDomainOptionRecommended": {
|
"baseDomainOptionRecommended": {
|
||||||
"message": "Base domain (recommended)",
|
"message": "Serveri nimi [base domain] (soovitatav)",
|
||||||
"description": "Domain name. Ex. website.com"
|
"description": "Domain name. Ex. website.com"
|
||||||
},
|
},
|
||||||
"domainName": {
|
"domainName": {
|
||||||
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Puuduvad paroolid, mida kuvada."
|
"message": "Puuduvad paroolid, mida kuvada."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Eemalda"
|
"message": "Eemalda"
|
||||||
},
|
},
|
||||||
@ -1864,7 +1873,7 @@
|
|||||||
"message": "Vale PIN kood."
|
"message": "Vale PIN kood."
|
||||||
},
|
},
|
||||||
"tooManyInvalidPinEntryAttemptsLoggingOut": {
|
"tooManyInvalidPinEntryAttemptsLoggingOut": {
|
||||||
"message": "Too many invalid PIN entry attempts. Logging out."
|
"message": "Liiga palju ebaõnnestunud katseid. Login välja."
|
||||||
},
|
},
|
||||||
"unlockWithBiometrics": {
|
"unlockWithBiometrics": {
|
||||||
"message": "Ava biomeetriaga"
|
"message": "Ava biomeetriaga"
|
||||||
@ -1891,26 +1900,26 @@
|
|||||||
"message": "Organisatsiooni seaded mõjutavad parooli genereerija sätteid."
|
"message": "Organisatsiooni seaded mõjutavad parooli genereerija sätteid."
|
||||||
},
|
},
|
||||||
"passwordGenerator": {
|
"passwordGenerator": {
|
||||||
"message": "Password generator"
|
"message": "Parooli genereerija"
|
||||||
},
|
},
|
||||||
"usernameGenerator": {
|
"usernameGenerator": {
|
||||||
"message": "Username generator"
|
"message": "Kasutajanime genereerija"
|
||||||
},
|
},
|
||||||
"useThisPassword": {
|
"useThisPassword": {
|
||||||
"message": "Use this password"
|
"message": "Kasuta seda parooli"
|
||||||
},
|
},
|
||||||
"useThisUsername": {
|
"useThisUsername": {
|
||||||
"message": "Use this username"
|
"message": "Kasuta seda kasutajanime"
|
||||||
},
|
},
|
||||||
"securePasswordGenerated": {
|
"securePasswordGenerated": {
|
||||||
"message": "Secure password generated! Don't forget to also update your password on the website."
|
"message": "Turvaline parool loodud! Ära unusta uuendata seda ka veebisaidil."
|
||||||
},
|
},
|
||||||
"useGeneratorHelpTextPartOne": {
|
"useGeneratorHelpTextPartOne": {
|
||||||
"message": "Use the generator",
|
"message": "Kasuta generaatorit",
|
||||||
"description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'"
|
"description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'"
|
||||||
},
|
},
|
||||||
"useGeneratorHelpTextPartTwo": {
|
"useGeneratorHelpTextPartTwo": {
|
||||||
"message": "to create a strong unique password",
|
"message": "et luua tugev ja ainulaadne parool",
|
||||||
"description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'"
|
"description": "This will be used as part of a larger sentence, broken up to include the generator icon. The full sentence will read 'Use the generator [GENERATOR_ICON] to create a strong unique password'"
|
||||||
},
|
},
|
||||||
"vaultTimeoutAction": {
|
"vaultTimeoutAction": {
|
||||||
@ -1943,7 +1952,7 @@
|
|||||||
"message": "Kirje on taastatud"
|
"message": "Kirje on taastatud"
|
||||||
},
|
},
|
||||||
"alreadyHaveAccount": {
|
"alreadyHaveAccount": {
|
||||||
"message": "Already have an account?"
|
"message": "On juba konto?"
|
||||||
},
|
},
|
||||||
"vaultTimeoutLogOutConfirmation": {
|
"vaultTimeoutLogOutConfirmation": {
|
||||||
"message": "Väljalogimine eemaldab hoidlale ligipääsu ning nõuab pärast ajalõpu perioodi uuesti autentimist. Oled kindel, et soovid seda valikut kasutada?"
|
"message": "Väljalogimine eemaldab hoidlale ligipääsu ning nõuab pärast ajalõpu perioodi uuesti autentimist. Oled kindel, et soovid seda valikut kasutada?"
|
||||||
@ -1955,7 +1964,7 @@
|
|||||||
"message": "Täida ja salvesta"
|
"message": "Täida ja salvesta"
|
||||||
},
|
},
|
||||||
"fillAndSave": {
|
"fillAndSave": {
|
||||||
"message": "Fill and save"
|
"message": "Täida ja salvesta"
|
||||||
},
|
},
|
||||||
"autoFillSuccessAndSavedUri": {
|
"autoFillSuccessAndSavedUri": {
|
||||||
"message": "Kirje täideti ja URI salvestati"
|
"message": "Kirje täideti ja URI salvestati"
|
||||||
@ -2036,19 +2045,19 @@
|
|||||||
"message": "Uus ülemparool ei vasta eeskirjades väljatoodud tingimustele."
|
"message": "Uus ülemparool ei vasta eeskirjades väljatoodud tingimustele."
|
||||||
},
|
},
|
||||||
"receiveMarketingEmailsV2": {
|
"receiveMarketingEmailsV2": {
|
||||||
"message": "Get advice, announcements, and research opportunities from Bitwarden in your inbox."
|
"message": "Soovin saada nõuandeid, uudiseid ja pakkumisi Bitwardenilt oma postkasti."
|
||||||
},
|
},
|
||||||
"unsubscribe": {
|
"unsubscribe": {
|
||||||
"message": "Unsubscribe"
|
"message": "Lõpeta tellimus"
|
||||||
},
|
},
|
||||||
"atAnyTime": {
|
"atAnyTime": {
|
||||||
"message": "at any time."
|
"message": "iga hetk."
|
||||||
},
|
},
|
||||||
"byContinuingYouAgreeToThe": {
|
"byContinuingYouAgreeToThe": {
|
||||||
"message": "By continuing, you agree to the"
|
"message": "Jätkates nõustud sa"
|
||||||
},
|
},
|
||||||
"and": {
|
"and": {
|
||||||
"message": "and"
|
"message": "ja"
|
||||||
},
|
},
|
||||||
"acceptPolicies": {
|
"acceptPolicies": {
|
||||||
"message": "Märkeruudu markeerimisel nõustud järgnevaga:"
|
"message": "Märkeruudu markeerimisel nõustud järgnevaga:"
|
||||||
@ -2069,10 +2078,10 @@
|
|||||||
"message": "Ok"
|
"message": "Ok"
|
||||||
},
|
},
|
||||||
"errorRefreshingAccessToken": {
|
"errorRefreshingAccessToken": {
|
||||||
"message": "Access Token Refresh Error"
|
"message": "Juurdepääsukoodi Värskendamine Ebaõnnestus"
|
||||||
},
|
},
|
||||||
"errorRefreshingAccessTokenDesc": {
|
"errorRefreshingAccessTokenDesc": {
|
||||||
"message": "No refresh token or API keys found. Please try logging out and logging back in."
|
"message": "Ei leidnud värskendamise koodi või API võtit. Palun proovi logida välja ja uuesti sisse."
|
||||||
},
|
},
|
||||||
"desktopSyncVerificationTitle": {
|
"desktopSyncVerificationTitle": {
|
||||||
"message": "Töölaua sünkroonimise kinnitamine"
|
"message": "Töölaua sünkroonimise kinnitamine"
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Ez dago erakusteko pasahitzik."
|
"message": "Ez dago erakusteko pasahitzik."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Ezabatu"
|
"message": "Ezabatu"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "هیچ کلمه عبوری برای فهرست کردن وجود ندارد."
|
"message": "هیچ کلمه عبوری برای فهرست کردن وجود ندارد."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "حذف"
|
"message": "حذف"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Ei näytettäviä salasanoja."
|
"message": "Ei näytettäviä salasanoja."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Poista"
|
"message": "Poista"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Yrityskäytännön vaatimuksia on sovellettu tähän asetukseen"
|
"message": "Yrityskäytännön vaatimuksia on sovellettu tähän asetukseen"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Lisää sisältöä on saatavilla"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Roskakorin kohteet"
|
"message": "Roskakorin kohteet"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Walang mga password na i-list."
|
"message": "Walang mga password na i-list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Alisin"
|
"message": "Alisin"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Aucun mot de passe à afficher."
|
"message": "Aucun mot de passe à afficher."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Supprimer"
|
"message": "Supprimer"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Les exigences de la politique d'entreprise ont été appliquées à ce paramètre"
|
"message": "Les exigences de la politique d'entreprise ont été appliquées à ce paramètre"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Du contenu supplémentaire est disponible"
|
"message": "Afficher le nombre de caractères"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Cacher le nombre de caractères"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Éléments dans la corbeille"
|
"message": "Éléments dans la corbeille"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Non hai contrasinais que listar."
|
"message": "Non hai contrasinais que listar."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Eliminar"
|
"message": "Eliminar"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "אין סיסמאות להצגה ברשימה."
|
"message": "אין סיסמאות להצגה ברשימה."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "הסר"
|
"message": "הסר"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "सूची के लिए कोई पासवर्ड नहीं हैं।"
|
"message": "सूची के लिए कोई पासवर्ड नहीं हैं।"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "हटाएं"
|
"message": "हटाएं"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "इस सेटिंग पर एंटरप्राइज़ नीति आवश्यकताएँ लागू की गई हैं"
|
"message": "इस सेटिंग पर एंटरप्राइज़ नीति आवश्यकताएँ लागू की गई हैं"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Nema lozinki na popisu."
|
"message": "Nema lozinki na popisu."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Ukloni"
|
"message": "Ukloni"
|
||||||
},
|
},
|
||||||
@ -3478,7 +3487,7 @@
|
|||||||
"message": "Ishodišna stranica zahtijeva verifikaciju. Ova značajka još nije implementirana za račune bez glavne lozinke."
|
"message": "Ishodišna stranica zahtijeva verifikaciju. Ova značajka još nije implementirana za račune bez glavne lozinke."
|
||||||
},
|
},
|
||||||
"logInWithPasskeyQuestion": {
|
"logInWithPasskeyQuestion": {
|
||||||
"message": "Log in with passkey?"
|
"message": "Prijava pristupnim ključem?"
|
||||||
},
|
},
|
||||||
"passkeyAlreadyExists": {
|
"passkeyAlreadyExists": {
|
||||||
"message": "Za ovu aplikaciju već postoji pristupni ključ."
|
"message": "Za ovu aplikaciju već postoji pristupni ključ."
|
||||||
@ -3490,7 +3499,7 @@
|
|||||||
"message": "Nema odgovarajuće prijavu za ovu stranicu."
|
"message": "Nema odgovarajuće prijavu za ovu stranicu."
|
||||||
},
|
},
|
||||||
"noMatchingLoginsForSite": {
|
"noMatchingLoginsForSite": {
|
||||||
"message": "No matching logins for this site"
|
"message": "Nema prijava za ovu web stranicu"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Autoriziraj"
|
"message": "Autoriziraj"
|
||||||
@ -3502,10 +3511,10 @@
|
|||||||
"message": "Spremi pristupni ključ kao novu prijavu"
|
"message": "Spremi pristupni ključ kao novu prijavu"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeySave": {
|
"chooseCipherForPasskeySave": {
|
||||||
"message": "Choose a login to save this passkey to"
|
"message": "Odaberi za koju prijavu želiš spremiti ovaj pristupni ključ"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeyAuth": {
|
"chooseCipherForPasskeyAuth": {
|
||||||
"message": "Choose a passkey to log in with"
|
"message": "Odaberi pristupni ključ za prijavu"
|
||||||
},
|
},
|
||||||
"passkeyItem": {
|
"passkeyItem": {
|
||||||
"message": "Stavka pristupnog ključa"
|
"message": "Stavka pristupnog ključa"
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Pravila tvrtke primijenjena su na ovu postavku"
|
"message": "Pravila tvrtke primijenjena su na ovu postavku"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Dostupan je dodatni sadržaj"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Stavke u smeću"
|
"message": "Stavke u smeću"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Nincsenek listázható jelszavak."
|
"message": "Nincsenek listázható jelszavak."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Előzmények törlése"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "Nincsenek megjeleníthető jelszavak."
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "Mostanában nem lett jelszó generálva."
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Eltávolítás"
|
"message": "Eltávolítás"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Erre a beállításra a vállalkozás rendszabály követelmények lettek alkalmazva."
|
"message": "Erre a beállításra a vállalkozás rendszabály követelmények lettek alkalmazva."
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Karakterszámláló megjelenítése"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Karakterszámláló elrejtése"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "elem van a lomtárban."
|
"message": "elem van a lomtárban."
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Tidak ada sandi yang dapat dicantumkan."
|
"message": "Tidak ada sandi yang dapat dicantumkan."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Hapus"
|
"message": "Hapus"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Non ci sono password da mostrare."
|
"message": "Non ci sono password da mostrare."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Rimuovi"
|
"message": "Rimuovi"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "I requisiti della policy aziendale sono stati applicati a questa impostazione"
|
"message": "I requisiti della policy aziendale sono stati applicati a questa impostazione"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Sono disponibili ulteriori contenuti"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Elementi nel cestino"
|
"message": "Elementi nel cestino"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "表示するパスワードがありません"
|
"message": "表示するパスワードがありません"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "削除"
|
"message": "削除"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "エンタープライズポリシー要件がこの設定に適用されました"
|
"message": "エンタープライズポリシー要件がこの設定に適用されました"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "追加コンテンツが利用可能です"
|
"message": "文字数を表示"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "文字数を隠す"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "ゴミ箱にあるアイテム"
|
"message": "ゴミ箱にあるアイテム"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "ಪಟ್ಟಿ ಮಾಡಲು ಯಾವುದೇ ಪಾಸ್ವರ್ಡ್ಗಳು ಇಲ್ಲ."
|
"message": "ಪಟ್ಟಿ ಮಾಡಲು ಯಾವುದೇ ಪಾಸ್ವರ್ಡ್ಗಳು ಇಲ್ಲ."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "ತೆಗೆ"
|
"message": "ತೆಗೆ"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "비밀번호가 없습니다."
|
"message": "비밀번호가 없습니다."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "제거"
|
"message": "제거"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Slaptažodžių sąraše nėra."
|
"message": "Slaptažodžių sąraše nėra."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Pašalinti"
|
"message": "Pašalinti"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Nav paroļu, ko parādīt."
|
"message": "Nav paroļu, ko parādīt."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Noņemt"
|
"message": "Noņemt"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Šim iestatījumam tika piemērotas uzņēmējdarbības nosacījumu prasības"
|
"message": "Šim iestatījumam tika piemērotas uzņēmējdarbības nosacījumu prasības"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Ir pieejams papildu saturs"
|
"message": "Rādīt rakstzīmju skaitu"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Paslēpt rakstzīmju skaitu"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Vienumi atkritnē"
|
"message": "Vienumi atkritnē"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "പ്രദർശിപ്പിക്കാൻ പാസ്സ്വേഡുകൾ ഒന്നും ഇല്ല."
|
"message": "പ്രദർശിപ്പിക്കാൻ പാസ്സ്വേഡുകൾ ഒന്നും ഇല്ല."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "നീക്കുക"
|
"message": "നീക്കുക"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Det er ingen passord å liste opp."
|
"message": "Det er ingen passord å liste opp."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Fjern"
|
"message": "Fjern"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Er zijn geen wachtwoorden om weer te geven."
|
"message": "Er zijn geen wachtwoorden om weer te geven."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Verwijderen"
|
"message": "Verwijderen"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Bedrijfsbeleidseisen zijn op deze instelling toegepast"
|
"message": "Bedrijfsbeleidseisen zijn op deze instelling toegepast"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Extra inhoud beschikbaar"
|
"message": "Aantal tekens weergeven"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Aantal tekens verbergen"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in prullenbak"
|
"message": "Items in prullenbak"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Brak haseł."
|
"message": "Brak haseł."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Usuń"
|
"message": "Usuń"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -400,11 +400,11 @@
|
|||||||
"description": "deprecated. Use specialCharactersLabel instead."
|
"description": "deprecated. Use specialCharactersLabel instead."
|
||||||
},
|
},
|
||||||
"include": {
|
"include": {
|
||||||
"message": "Include",
|
"message": "Incluir",
|
||||||
"description": "Card header for password generator include block"
|
"description": "Card header for password generator include block"
|
||||||
},
|
},
|
||||||
"uppercaseDescription": {
|
"uppercaseDescription": {
|
||||||
"message": "Include uppercase characters",
|
"message": "Incluir caracteres maiúsculos",
|
||||||
"description": "Tooltip for the password generator uppercase character checkbox"
|
"description": "Tooltip for the password generator uppercase character checkbox"
|
||||||
},
|
},
|
||||||
"uppercaseLabel": {
|
"uppercaseLabel": {
|
||||||
@ -412,7 +412,7 @@
|
|||||||
"description": "Label for the password generator uppercase character checkbox"
|
"description": "Label for the password generator uppercase character checkbox"
|
||||||
},
|
},
|
||||||
"lowercaseDescription": {
|
"lowercaseDescription": {
|
||||||
"message": "Include lowercase characters",
|
"message": "Incluir caracteres minúsculos",
|
||||||
"description": "Full description for the password generator lowercase character checkbox"
|
"description": "Full description for the password generator lowercase character checkbox"
|
||||||
},
|
},
|
||||||
"lowercaseLabel": {
|
"lowercaseLabel": {
|
||||||
@ -420,15 +420,15 @@
|
|||||||
"description": "Label for the password generator lowercase character checkbox"
|
"description": "Label for the password generator lowercase character checkbox"
|
||||||
},
|
},
|
||||||
"numbersDescription": {
|
"numbersDescription": {
|
||||||
"message": "Include numbers",
|
"message": "Incluir números",
|
||||||
"description": "Full description for the password generator numbers checkbox"
|
"description": "Full description for the password generator numbers checkbox"
|
||||||
},
|
},
|
||||||
"numbersLabel": {
|
"numbersLabel": {
|
||||||
"message": "0-9",
|
"message": "0 – 9",
|
||||||
"description": "Label for the password generator numbers checkbox"
|
"description": "Label for the password generator numbers checkbox"
|
||||||
},
|
},
|
||||||
"specialCharactersDescription": {
|
"specialCharactersDescription": {
|
||||||
"message": "Include special characters",
|
"message": "Incluir caracteres especiais",
|
||||||
"description": "Full description for the password generator special characters checkbox"
|
"description": "Full description for the password generator special characters checkbox"
|
||||||
},
|
},
|
||||||
"specialCharactersLabel": {
|
"specialCharactersLabel": {
|
||||||
@ -459,7 +459,7 @@
|
|||||||
"description": "deprecated. Use avoidAmbiguous instead."
|
"description": "deprecated. Use avoidAmbiguous instead."
|
||||||
},
|
},
|
||||||
"avoidAmbiguous": {
|
"avoidAmbiguous": {
|
||||||
"message": "Avoid ambiguous characters",
|
"message": "Evitar Caracteres Ambíguos",
|
||||||
"description": "Label for the avoid ambiguous characters checkbox."
|
"description": "Label for the avoid ambiguous characters checkbox."
|
||||||
},
|
},
|
||||||
"searchVault": {
|
"searchVault": {
|
||||||
@ -684,10 +684,10 @@
|
|||||||
"message": "A sua nova conta foi criada! Agora você pode iniciar a sessão."
|
"message": "A sua nova conta foi criada! Agora você pode iniciar a sessão."
|
||||||
},
|
},
|
||||||
"newAccountCreated2": {
|
"newAccountCreated2": {
|
||||||
"message": "Your new account has been created!"
|
"message": "Sua nova conta foi criada!"
|
||||||
},
|
},
|
||||||
"youHaveBeenLoggedIn": {
|
"youHaveBeenLoggedIn": {
|
||||||
"message": "You have been logged in!"
|
"message": "Você está conectado!"
|
||||||
},
|
},
|
||||||
"youSuccessfullyLoggedIn": {
|
"youSuccessfullyLoggedIn": {
|
||||||
"message": "Você logou na sua conta com sucesso"
|
"message": "Você logou na sua conta com sucesso"
|
||||||
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Não existem senhas para listar."
|
"message": "Não existem senhas para listar."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remover"
|
"message": "Remover"
|
||||||
},
|
},
|
||||||
@ -3478,7 +3487,7 @@
|
|||||||
"message": "Verificação requerida pelo site que a iniciou. Esse recurso ainda não está implementado para contas sem senha mestra."
|
"message": "Verificação requerida pelo site que a iniciou. Esse recurso ainda não está implementado para contas sem senha mestra."
|
||||||
},
|
},
|
||||||
"logInWithPasskeyQuestion": {
|
"logInWithPasskeyQuestion": {
|
||||||
"message": "Log in with passkey?"
|
"message": "Fazer ‘login’ com chave de acesso?"
|
||||||
},
|
},
|
||||||
"passkeyAlreadyExists": {
|
"passkeyAlreadyExists": {
|
||||||
"message": "Uma chave de acesso já existe para este aplicativo."
|
"message": "Uma chave de acesso já existe para este aplicativo."
|
||||||
@ -3490,7 +3499,7 @@
|
|||||||
"message": "Você não tem um login correspondente para este site."
|
"message": "Você não tem um login correspondente para este site."
|
||||||
},
|
},
|
||||||
"noMatchingLoginsForSite": {
|
"noMatchingLoginsForSite": {
|
||||||
"message": "No matching logins for this site"
|
"message": "Sem credenciais correspondentes para este site"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Confirmar"
|
"message": "Confirmar"
|
||||||
@ -3502,10 +3511,10 @@
|
|||||||
"message": "Salvar chave de acesso como um novo login"
|
"message": "Salvar chave de acesso como um novo login"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeySave": {
|
"chooseCipherForPasskeySave": {
|
||||||
"message": "Choose a login to save this passkey to"
|
"message": "Escolha um ‘login’ para salvar com essa chave de acesso"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeyAuth": {
|
"chooseCipherForPasskeyAuth": {
|
||||||
"message": "Choose a passkey to log in with"
|
"message": "Escolha uma senha para iniciar sessão"
|
||||||
},
|
},
|
||||||
"passkeyItem": {
|
"passkeyItem": {
|
||||||
"message": "Item de chave de acesso"
|
"message": "Item de chave de acesso"
|
||||||
@ -3703,7 +3712,7 @@
|
|||||||
"description": "Notification message for when saving credentials has succeeded."
|
"description": "Notification message for when saving credentials has succeeded."
|
||||||
},
|
},
|
||||||
"passwordSaved": {
|
"passwordSaved": {
|
||||||
"message": "Password saved!",
|
"message": "Senha salva!",
|
||||||
"description": "Notification message for when saving credentials has succeeded."
|
"description": "Notification message for when saving credentials has succeeded."
|
||||||
},
|
},
|
||||||
"updateCipherAttemptSuccess": {
|
"updateCipherAttemptSuccess": {
|
||||||
@ -3711,7 +3720,7 @@
|
|||||||
"description": "Notification message for when updating credentials has succeeded."
|
"description": "Notification message for when updating credentials has succeeded."
|
||||||
},
|
},
|
||||||
"passwordUpdated": {
|
"passwordUpdated": {
|
||||||
"message": "Password updated!",
|
"message": "Senha atualizada!",
|
||||||
"description": "Notification message for when updating credentials has succeeded."
|
"description": "Notification message for when updating credentials has succeeded."
|
||||||
},
|
},
|
||||||
"saveCipherAttemptFailed": {
|
"saveCipherAttemptFailed": {
|
||||||
@ -4300,28 +4309,31 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Os requisitos de política empresarial foram aplicados nesta configuração"
|
"message": "Os requisitos de política empresarial foram aplicados nesta configuração"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Mostrar contagem de caracteres"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Esconder contagem de caracteres"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Itens na lixeira"
|
||||||
},
|
},
|
||||||
"noItemsInTrash": {
|
"noItemsInTrash": {
|
||||||
"message": "No items in trash"
|
"message": "Nenhum item na lixeira"
|
||||||
},
|
},
|
||||||
"noItemsInTrashDesc": {
|
"noItemsInTrashDesc": {
|
||||||
"message": "Items you delete will appear here and be permanently deleted after 30 days"
|
"message": "Os itens que você excluir aparecerão aqui e serão excluídos permanentemente após 30 dias"
|
||||||
},
|
},
|
||||||
"trashWarning": {
|
"trashWarning": {
|
||||||
"message": "Items that have been in trash more than 30 days will automatically be deleted"
|
"message": "Os itens que ficarem na lixeira por mais de 30 dias serão excluídos automaticamente"
|
||||||
},
|
},
|
||||||
"restore": {
|
"restore": {
|
||||||
"message": "Restore"
|
"message": "Restaurar"
|
||||||
},
|
},
|
||||||
"deleteForever": {
|
"deleteForever": {
|
||||||
"message": "Delete forever"
|
"message": "Apagar permanentemente"
|
||||||
},
|
},
|
||||||
"noEditPermissions": {
|
"noEditPermissions": {
|
||||||
"message": "You don't have permission to edit this item"
|
"message": "Você não tem permissão para editar este arquivo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Não existem palavras-passe para listar."
|
"message": "Não existem palavras-passe para listar."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remover"
|
"message": "Remover"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Os requisitos da política empresarial foram aplicados a esta definição"
|
"message": "Os requisitos da política empresarial foram aplicados a esta definição"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Estão disponíveis conteúdos adicionais"
|
"message": "Mostrar contagem de caracteres"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Ocultar contagem de caracteres"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Itens no lixo"
|
"message": "Itens no lixo"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Nicio parolă de afișat."
|
"message": "Nicio parolă de afișat."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Ștergere"
|
"message": "Ștergere"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Нет паролей для отображения."
|
"message": "Нет паролей для отображения."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Очистить историю"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "Нет паролей для отображения"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "Нет недавно сгенерированных паролей"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Удалить"
|
"message": "Удалить"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "К этой настройке были применены требования корпоративной политики"
|
"message": "К этой настройке были применены требования корпоративной политики"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Дополнительный контент доступен"
|
"message": "Показать количество символов"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Скрыть количество символов"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Элементы в корзине"
|
"message": "Элементы в корзине"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "ලැයිස්තු ගත කිරීමට මුරපද නොමැත."
|
"message": "ලැයිස්තු ගත කිරීමට මුරපද නොමැත."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "ඉවත් කරන්න"
|
"message": "ඉවත් කරන්න"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Neboli nájdené žiadne heslá."
|
"message": "Neboli nájdené žiadne heslá."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Odstrániť"
|
"message": "Odstrániť"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Na toto nastavenie boli uplatnené požiadavky pravidiel spoločnosti"
|
"message": "Na toto nastavenie boli uplatnené požiadavky pravidiel spoločnosti"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "K dispozícii je ďalší obsah"
|
"message": "Zobraziť počítadlo znakov"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Skryť počítadlo znakov"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Položky v koši"
|
"message": "Položky v koši"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Ni takšnih gesel."
|
"message": "Ni takšnih gesel."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Odstrani"
|
"message": "Odstrani"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Нема лозинки у листи."
|
"message": "Нема лозинки у листи."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Уклони"
|
"message": "Уклони"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Захтеви политике предузећа су примењени на ово подешавање"
|
"message": "Захтеви политике предузећа су примењени на ово подешавање"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Додатни садржај је доступан"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Ставке у смећу"
|
"message": "Ставке у смећу"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Det finns inga lösenord att lista."
|
"message": "Det finns inga lösenord att lista."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Ta bort"
|
"message": "Ta bort"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Visa antal tecken"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Dölj antal tecken"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "There are no passwords to list."
|
"message": "There are no passwords to list."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Remove"
|
"message": "Remove"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "ไม่มีรหัสผ่านที่จะแสดง"
|
"message": "ไม่มีรหัสผ่านที่จะแสดง"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "ลบ"
|
"message": "ลบ"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Listelenecek parola yok."
|
"message": "Listelenecek parola yok."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Kaldır"
|
"message": "Kaldır"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Bu ayara kurumsal ilke gereksinimleri uygulandı"
|
"message": "Bu ayara kurumsal ilke gereksinimleri uygulandı"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Ek içerikler mevcut"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Çöp kutusundaki kayıtlar"
|
"message": "Çöp kutusundaki kayıtlar"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Немає паролів."
|
"message": "Немає паролів."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Вилучити"
|
"message": "Вилучити"
|
||||||
},
|
},
|
||||||
@ -3478,7 +3487,7 @@
|
|||||||
"message": "Сайт ініціює обов'язкову верифікацію. Ця функція ще не реалізована для облікових записів без головного пароля."
|
"message": "Сайт ініціює обов'язкову верифікацію. Ця функція ще не реалізована для облікових записів без головного пароля."
|
||||||
},
|
},
|
||||||
"logInWithPasskeyQuestion": {
|
"logInWithPasskeyQuestion": {
|
||||||
"message": "Log in with passkey?"
|
"message": "Увійти з ключем доступу?"
|
||||||
},
|
},
|
||||||
"passkeyAlreadyExists": {
|
"passkeyAlreadyExists": {
|
||||||
"message": "Ключ доступу для цієї програми вже існує."
|
"message": "Ключ доступу для цієї програми вже існує."
|
||||||
@ -3490,7 +3499,7 @@
|
|||||||
"message": "У вас немає відповідних записів для цього сайту."
|
"message": "У вас немає відповідних записів для цього сайту."
|
||||||
},
|
},
|
||||||
"noMatchingLoginsForSite": {
|
"noMatchingLoginsForSite": {
|
||||||
"message": "No matching logins for this site"
|
"message": "Немає відповідних записів для цього сайту"
|
||||||
},
|
},
|
||||||
"confirm": {
|
"confirm": {
|
||||||
"message": "Підтвердити"
|
"message": "Підтвердити"
|
||||||
@ -3502,10 +3511,10 @@
|
|||||||
"message": "Зберегти ключ доступу як новий запис"
|
"message": "Зберегти ключ доступу як новий запис"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeySave": {
|
"chooseCipherForPasskeySave": {
|
||||||
"message": "Choose a login to save this passkey to"
|
"message": "Виберіть запис для збереження цього ключа доступу"
|
||||||
},
|
},
|
||||||
"chooseCipherForPasskeyAuth": {
|
"chooseCipherForPasskeyAuth": {
|
||||||
"message": "Choose a passkey to log in with"
|
"message": "Виберіть ключ доступу для входу"
|
||||||
},
|
},
|
||||||
"passkeyItem": {
|
"passkeyItem": {
|
||||||
"message": "Ключ доступу"
|
"message": "Ключ доступу"
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "До цього налаштування застосовано вимоги політики компанії"
|
"message": "До цього налаштування застосовано вимоги політики компанії"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Доступний додатковий вміст"
|
"message": "Показати кількість символів"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Приховати кількість символів"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Записи в смітнику"
|
"message": "Записи в смітнику"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "Không có mật khẩu để liệt kê."
|
"message": "Không có mật khẩu để liệt kê."
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "Xoá"
|
"message": "Xoá"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "没有可列出的密码。"
|
"message": "没有可列出的密码。"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "移除"
|
"message": "移除"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "企业策略要求已应用于此设置"
|
"message": "企业策略要求已应用于此设置"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "其他内容可用"
|
"message": "显示字符计数"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "隐藏字符计数"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "回收站中的项目"
|
"message": "回收站中的项目"
|
||||||
|
@ -1796,6 +1796,15 @@
|
|||||||
"noPasswordsInList": {
|
"noPasswordsInList": {
|
||||||
"message": "沒有可列出的密碼。"
|
"message": "沒有可列出的密碼。"
|
||||||
},
|
},
|
||||||
|
"clearHistory": {
|
||||||
|
"message": "Clear history"
|
||||||
|
},
|
||||||
|
"noPasswordsToShow": {
|
||||||
|
"message": "No passwords to show"
|
||||||
|
},
|
||||||
|
"noRecentlyGeneratedPassword": {
|
||||||
|
"message": "You haven't generated a password recently"
|
||||||
|
},
|
||||||
"remove": {
|
"remove": {
|
||||||
"message": "移除"
|
"message": "移除"
|
||||||
},
|
},
|
||||||
@ -4300,8 +4309,11 @@
|
|||||||
"enterprisePolicyRequirementsApplied": {
|
"enterprisePolicyRequirementsApplied": {
|
||||||
"message": "Enterprise policy requirements have been applied to this setting"
|
"message": "Enterprise policy requirements have been applied to this setting"
|
||||||
},
|
},
|
||||||
"additionalContentAvailable": {
|
"showCharacterCount": {
|
||||||
"message": "Additional content is available"
|
"message": "Show character count"
|
||||||
|
},
|
||||||
|
"hideCharacterCount": {
|
||||||
|
"message": "Hide character count"
|
||||||
},
|
},
|
||||||
"itemsInTrash": {
|
"itemsInTrash": {
|
||||||
"message": "Items in trash"
|
"message": "Items in trash"
|
||||||
|
@ -217,6 +217,7 @@ export type OverlayBackgroundExtensionMessageHandlers = {
|
|||||||
addEditCipherSubmitted: () => void;
|
addEditCipherSubmitted: () => void;
|
||||||
editedCipher: () => void;
|
editedCipher: () => void;
|
||||||
deletedCipher: () => void;
|
deletedCipher: () => void;
|
||||||
|
fido2AbortRequest: ({ message, sender }: BackgroundOnMessageHandlerParams) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PortMessageParam = {
|
export type PortMessageParam = {
|
||||||
|
@ -18,12 +18,12 @@ import {
|
|||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
Region,
|
Region,
|
||||||
} from "@bitwarden/common/platform/abstractions/environment.service";
|
} from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { Fido2ClientService } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { ThemeType } from "@bitwarden/common/platform/enums";
|
import { ThemeType } from "@bitwarden/common/platform/enums";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { CloudEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
import { CloudEnvironment } from "@bitwarden/common/platform/services/default-environment.service";
|
||||||
|
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/services/fido2/fido2-active-request-manager";
|
||||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||||
import {
|
import {
|
||||||
FakeAccountService,
|
FakeAccountService,
|
||||||
@ -32,6 +32,7 @@ import {
|
|||||||
} from "@bitwarden/common/spec";
|
} from "@bitwarden/common/spec";
|
||||||
import { UserId } from "@bitwarden/common/types/guid";
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||||
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||||
import { Fido2CredentialView } from "@bitwarden/common/vault/models/view/fido2-credential.view";
|
import { Fido2CredentialView } from "@bitwarden/common/vault/models/view/fido2-credential.view";
|
||||||
@ -89,8 +90,9 @@ describe("OverlayBackground", () => {
|
|||||||
let autofillSettingsService: MockProxy<AutofillSettingsService>;
|
let autofillSettingsService: MockProxy<AutofillSettingsService>;
|
||||||
let i18nService: MockProxy<I18nService>;
|
let i18nService: MockProxy<I18nService>;
|
||||||
let platformUtilsService: MockProxy<BrowserPlatformUtilsService>;
|
let platformUtilsService: MockProxy<BrowserPlatformUtilsService>;
|
||||||
let availableAutofillCredentialsMock$: BehaviorSubject<Fido2CredentialView[]>;
|
let enablePasskeysMock$: BehaviorSubject<boolean>;
|
||||||
let fido2ClientService: MockProxy<Fido2ClientService>;
|
let vaultSettingsServiceMock: MockProxy<VaultSettingsService>;
|
||||||
|
let fido2ActiveRequestManager: Fido2ActiveRequestManager;
|
||||||
let selectedThemeMock$: BehaviorSubject<ThemeType>;
|
let selectedThemeMock$: BehaviorSubject<ThemeType>;
|
||||||
let themeStateService: MockProxy<ThemeStateService>;
|
let themeStateService: MockProxy<ThemeStateService>;
|
||||||
let overlayBackground: OverlayBackground;
|
let overlayBackground: OverlayBackground;
|
||||||
@ -159,10 +161,10 @@ describe("OverlayBackground", () => {
|
|||||||
autofillSettingsService.inlineMenuVisibility$ = inlineMenuVisibilityMock$;
|
autofillSettingsService.inlineMenuVisibility$ = inlineMenuVisibilityMock$;
|
||||||
i18nService = mock<I18nService>();
|
i18nService = mock<I18nService>();
|
||||||
platformUtilsService = mock<BrowserPlatformUtilsService>();
|
platformUtilsService = mock<BrowserPlatformUtilsService>();
|
||||||
availableAutofillCredentialsMock$ = new BehaviorSubject([]);
|
enablePasskeysMock$ = new BehaviorSubject(true);
|
||||||
fido2ClientService = mock<Fido2ClientService>({
|
vaultSettingsServiceMock = mock<VaultSettingsService>();
|
||||||
availableAutofillCredentials$: (_tabId) => availableAutofillCredentialsMock$,
|
vaultSettingsServiceMock.enablePasskeys$ = enablePasskeysMock$;
|
||||||
});
|
fido2ActiveRequestManager = new Fido2ActiveRequestManager();
|
||||||
selectedThemeMock$ = new BehaviorSubject(ThemeType.Light);
|
selectedThemeMock$ = new BehaviorSubject(ThemeType.Light);
|
||||||
themeStateService = mock<ThemeStateService>();
|
themeStateService = mock<ThemeStateService>();
|
||||||
themeStateService.selectedTheme$ = selectedThemeMock$;
|
themeStateService.selectedTheme$ = selectedThemeMock$;
|
||||||
@ -176,7 +178,8 @@ describe("OverlayBackground", () => {
|
|||||||
autofillSettingsService,
|
autofillSettingsService,
|
||||||
i18nService,
|
i18nService,
|
||||||
platformUtilsService,
|
platformUtilsService,
|
||||||
fido2ClientService,
|
vaultSettingsServiceMock,
|
||||||
|
fido2ActiveRequestManager,
|
||||||
themeStateService,
|
themeStateService,
|
||||||
);
|
);
|
||||||
portKeyForTabSpy = overlayBackground["portKeyForTab"];
|
portKeyForTabSpy = overlayBackground["portKeyForTab"];
|
||||||
@ -779,6 +782,15 @@ describe("OverlayBackground", () => {
|
|||||||
expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled();
|
expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("skips updating the inline menu ciphers if the current tab url has non-http protocol", async () => {
|
||||||
|
const nonHttpTab = createChromeTabMock({ url: "chrome-extension://id/route" });
|
||||||
|
getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(nonHttpTab);
|
||||||
|
|
||||||
|
await overlayBackground.updateOverlayCiphers();
|
||||||
|
|
||||||
|
expect(cipherService.getAllDecryptedForUrl).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it("closes the inline menu on the focused field's tab if the user's auth status is not unlocked", async () => {
|
it("closes the inline menu on the focused field's tab if the user's auth status is not unlocked", async () => {
|
||||||
activeAccountStatusMock$.next(AuthenticationStatus.Locked);
|
activeAccountStatusMock$.next(AuthenticationStatus.Locked);
|
||||||
const previousTab = mock<chrome.tabs.Tab>({ id: 1 });
|
const previousTab = mock<chrome.tabs.Tab>({ id: 1 });
|
||||||
@ -1113,7 +1125,11 @@ describe("OverlayBackground", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("adds available passkey ciphers to the inline menu", async () => {
|
it("adds available passkey ciphers to the inline menu", async () => {
|
||||||
availableAutofillCredentialsMock$.next(passkeyCipher.login.fido2Credentials);
|
void fido2ActiveRequestManager.newActiveRequest(
|
||||||
|
tab.id,
|
||||||
|
passkeyCipher.login.fido2Credentials,
|
||||||
|
new AbortController(),
|
||||||
|
);
|
||||||
overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({
|
overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({
|
||||||
tabId: tab.id,
|
tabId: tab.id,
|
||||||
filledByCipherType: CipherType.Login,
|
filledByCipherType: CipherType.Login,
|
||||||
@ -1192,10 +1208,15 @@ describe("OverlayBackground", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("does not add a passkey to the inline menu when its rpId is part of the neverDomains exclusion list", async () => {
|
it("does not add a passkey to the inline menu when its rpId is part of the neverDomains exclusion list", async () => {
|
||||||
availableAutofillCredentialsMock$.next(passkeyCipher.login.fido2Credentials);
|
void fido2ActiveRequestManager.newActiveRequest(
|
||||||
|
tab.id,
|
||||||
|
passkeyCipher.login.fido2Credentials,
|
||||||
|
new AbortController(),
|
||||||
|
);
|
||||||
overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({
|
overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({
|
||||||
tabId: tab.id,
|
tabId: tab.id,
|
||||||
filledByCipherType: CipherType.Login,
|
filledByCipherType: CipherType.Login,
|
||||||
|
showPasskeys: true,
|
||||||
});
|
});
|
||||||
cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1, passkeyCipher]);
|
cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1, passkeyCipher]);
|
||||||
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
|
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
|
||||||
@ -1248,6 +1269,69 @@ describe("OverlayBackground", () => {
|
|||||||
showPasskeysLabels: false,
|
showPasskeysLabels: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not add passkeys to the inline menu if the passkey setting is disabled", async () => {
|
||||||
|
enablePasskeysMock$.next(false);
|
||||||
|
void fido2ActiveRequestManager.newActiveRequest(
|
||||||
|
tab.id,
|
||||||
|
passkeyCipher.login.fido2Credentials,
|
||||||
|
new AbortController(),
|
||||||
|
);
|
||||||
|
overlayBackground["focusedFieldData"] = createFocusedFieldDataMock({
|
||||||
|
tabId: tab.id,
|
||||||
|
filledByCipherType: CipherType.Login,
|
||||||
|
showPasskeys: true,
|
||||||
|
});
|
||||||
|
cipherService.getAllDecryptedForUrl.mockResolvedValue([loginCipher1, passkeyCipher]);
|
||||||
|
cipherService.sortCiphersByLastUsedThenName.mockReturnValue(-1);
|
||||||
|
getTabFromCurrentWindowIdSpy.mockResolvedValueOnce(tab);
|
||||||
|
|
||||||
|
await overlayBackground.updateOverlayCiphers();
|
||||||
|
|
||||||
|
expect(listPortSpy.postMessage).toHaveBeenCalledWith({
|
||||||
|
command: "updateAutofillInlineMenuListCiphers",
|
||||||
|
ciphers: [
|
||||||
|
{
|
||||||
|
id: "inline-menu-cipher-0",
|
||||||
|
name: passkeyCipher.name,
|
||||||
|
type: CipherType.Login,
|
||||||
|
reprompt: passkeyCipher.reprompt,
|
||||||
|
favorite: passkeyCipher.favorite,
|
||||||
|
icon: {
|
||||||
|
fallbackImage: "images/bwi-globe.png",
|
||||||
|
icon: "bwi-globe",
|
||||||
|
image: "https://icons.bitwarden.com//jest-testing-website.com/icon.png",
|
||||||
|
imageEnabled: true,
|
||||||
|
},
|
||||||
|
accountCreationFieldType: undefined,
|
||||||
|
login: {
|
||||||
|
username: passkeyCipher.login.username,
|
||||||
|
passkey: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "inline-menu-cipher-1",
|
||||||
|
name: loginCipher1.name,
|
||||||
|
type: CipherType.Login,
|
||||||
|
reprompt: loginCipher1.reprompt,
|
||||||
|
favorite: loginCipher1.favorite,
|
||||||
|
icon: {
|
||||||
|
fallbackImage: "images/bwi-globe.png",
|
||||||
|
icon: "bwi-globe",
|
||||||
|
image: "https://icons.bitwarden.com//jest-testing-website.com/icon.png",
|
||||||
|
imageEnabled: true,
|
||||||
|
},
|
||||||
|
accountCreationFieldType: undefined,
|
||||||
|
login: {
|
||||||
|
username: loginCipher1.login.username,
|
||||||
|
passkey: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
showInlineMenuAccountCreation: false,
|
||||||
|
showPasskeysLabels: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("extension message handlers", () => {
|
describe("extension message handlers", () => {
|
||||||
@ -2537,6 +2621,25 @@ describe("OverlayBackground", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("fido2AbortRequest", () => {
|
||||||
|
const sender = mock<chrome.runtime.MessageSender>({ tab: { id: 1 } });
|
||||||
|
it("removes an active request associated with the sender tab", () => {
|
||||||
|
const removeActiveRequestSpy = jest.spyOn(fido2ActiveRequestManager, "removeActiveRequest");
|
||||||
|
|
||||||
|
sendMockExtensionMessage({ command: "fido2AbortRequest" }, sender);
|
||||||
|
|
||||||
|
expect(removeActiveRequestSpy).toHaveBeenCalledWith(sender.tab.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("updates the overlay ciphers after removing the active request", () => {
|
||||||
|
const updateOverlayCiphersSpy = jest.spyOn(overlayBackground, "updateOverlayCiphers");
|
||||||
|
|
||||||
|
sendMockExtensionMessage({ command: "fido2AbortRequest" }, sender);
|
||||||
|
|
||||||
|
expect(updateOverlayCiphersSpy).toHaveBeenCalledWith(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("handle extension onMessage", () => {
|
describe("handle extension onMessage", () => {
|
||||||
@ -2920,6 +3023,7 @@ describe("OverlayBackground", () => {
|
|||||||
[sender.frameId, pageDetailsForTab],
|
[sender.frameId, pageDetailsForTab],
|
||||||
]);
|
]);
|
||||||
autofillService.isPasswordRepromptRequired.mockResolvedValue(false);
|
autofillService.isPasswordRepromptRequired.mockResolvedValue(false);
|
||||||
|
jest.spyOn(fido2ActiveRequestManager, "getActiveRequest");
|
||||||
|
|
||||||
sendPortMessage(listMessageConnectorSpy, {
|
sendPortMessage(listMessageConnectorSpy, {
|
||||||
command: "fillAutofillInlineMenuCipher",
|
command: "fillAutofillInlineMenuCipher",
|
||||||
@ -2929,10 +3033,7 @@ describe("OverlayBackground", () => {
|
|||||||
});
|
});
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
||||||
expect(fido2ClientService.autofillCredential).toHaveBeenCalledWith(
|
expect(fido2ActiveRequestManager.getActiveRequest).toHaveBeenCalledWith(sender.tab.id);
|
||||||
sender.tab.id,
|
|
||||||
fido2Credential.credentialId,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import {
|
|||||||
throttleTime,
|
throttleTime,
|
||||||
switchMap,
|
switchMap,
|
||||||
debounceTime,
|
debounceTime,
|
||||||
|
Observable,
|
||||||
|
map,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { parse } from "tldts";
|
import { parse } from "tldts";
|
||||||
|
|
||||||
@ -20,13 +22,17 @@ import { DomainSettingsService } from "@bitwarden/common/autofill/services/domai
|
|||||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||||
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
||||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
import { Fido2ClientService } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
import {
|
||||||
|
Fido2ActiveRequestEvents,
|
||||||
|
Fido2ActiveRequestManager,
|
||||||
|
} from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { buildCipherIcon } from "@bitwarden/common/vault/icon/build-cipher-icon";
|
import { buildCipherIcon } from "@bitwarden/common/vault/icon/build-cipher-icon";
|
||||||
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
|
import { CardView } from "@bitwarden/common/vault/models/view/card.view";
|
||||||
@ -144,6 +150,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
addEditCipherSubmitted: () => this.updateOverlayCiphers(),
|
addEditCipherSubmitted: () => this.updateOverlayCiphers(),
|
||||||
editedCipher: () => this.updateOverlayCiphers(),
|
editedCipher: () => this.updateOverlayCiphers(),
|
||||||
deletedCipher: () => this.updateOverlayCiphers(),
|
deletedCipher: () => this.updateOverlayCiphers(),
|
||||||
|
fido2AbortRequest: ({ sender }) => this.abortFido2ActiveRequest(sender),
|
||||||
};
|
};
|
||||||
private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = {
|
private readonly inlineMenuButtonPortMessageHandlers: InlineMenuButtonPortMessageHandlers = {
|
||||||
triggerDelayedAutofillInlineMenuClosure: () => this.triggerDelayedInlineMenuClosure(),
|
triggerDelayedAutofillInlineMenuClosure: () => this.triggerDelayedInlineMenuClosure(),
|
||||||
@ -175,7 +182,8 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
private autofillSettingsService: AutofillSettingsServiceAbstraction,
|
||||||
private i18nService: I18nService,
|
private i18nService: I18nService,
|
||||||
private platformUtilsService: PlatformUtilsService,
|
private platformUtilsService: PlatformUtilsService,
|
||||||
private fido2ClientService: Fido2ClientService,
|
private vaultSettingsService: VaultSettingsService,
|
||||||
|
private fido2ActiveRequestManager: Fido2ActiveRequestManager,
|
||||||
private themeStateService: ThemeStateService,
|
private themeStateService: ThemeStateService,
|
||||||
) {
|
) {
|
||||||
this.initOverlayEventObservables();
|
this.initOverlayEventObservables();
|
||||||
@ -196,7 +204,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
*/
|
*/
|
||||||
private initOverlayEventObservables() {
|
private initOverlayEventObservables() {
|
||||||
this.storeInlineMenuFido2CredentialsSubject
|
this.storeInlineMenuFido2CredentialsSubject
|
||||||
.pipe(switchMap((tabId) => this.fido2ClientService.availableAutofillCredentials$(tabId)))
|
.pipe(switchMap((tabId) => this.availablePasskeyAuthCredentials$(tabId)))
|
||||||
.subscribe((credentials) => this.storeInlineMenuFido2Credentials(credentials));
|
.subscribe((credentials) => this.storeInlineMenuFido2Credentials(credentials));
|
||||||
this.repositionInlineMenuSubject
|
this.repositionInlineMenuSubject
|
||||||
.pipe(
|
.pipe(
|
||||||
@ -279,6 +287,11 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const request = this.fido2ActiveRequestManager.getActiveRequest(currentTab.id);
|
||||||
|
if (request) {
|
||||||
|
request.subject.next({ type: Fido2ActiveRequestEvents.Refresh });
|
||||||
|
}
|
||||||
|
|
||||||
this.inlineMenuFido2Credentials.clear();
|
this.inlineMenuFido2Credentials.clear();
|
||||||
this.storeInlineMenuFido2CredentialsSubject.next(currentTab.id);
|
this.storeInlineMenuFido2CredentialsSubject.next(currentTab.id);
|
||||||
|
|
||||||
@ -452,6 +465,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
if (domainExclusions) {
|
if (domainExclusions) {
|
||||||
domainExclusionsSet = new Set(Object.keys(await this.getExcludedDomains()));
|
domainExclusionsSet = new Set(Object.keys(await this.getExcludedDomains()));
|
||||||
}
|
}
|
||||||
|
const passkeysEnabled = await firstValueFrom(this.vaultSettingsService.enablePasskeys$);
|
||||||
|
|
||||||
for (let cipherIndex = 0; cipherIndex < inlineMenuCiphersArray.length; cipherIndex++) {
|
for (let cipherIndex = 0; cipherIndex < inlineMenuCiphersArray.length; cipherIndex++) {
|
||||||
const [inlineMenuCipherId, cipher] = inlineMenuCiphersArray[cipherIndex];
|
const [inlineMenuCipherId, cipher] = inlineMenuCiphersArray[cipherIndex];
|
||||||
@ -459,7 +473,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.showCipherAsPasskey(cipher, domainExclusionsSet)) {
|
if (!passkeysEnabled || !(await this.showCipherAsPasskey(cipher, domainExclusionsSet))) {
|
||||||
inlineMenuCipherData.push(
|
inlineMenuCipherData.push(
|
||||||
this.buildCipherData({ inlineMenuCipherId, cipher, showFavicons }),
|
this.buildCipherData({ inlineMenuCipherId, cipher, showFavicons }),
|
||||||
);
|
);
|
||||||
@ -497,7 +511,10 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param cipher - The cipher to check
|
* @param cipher - The cipher to check
|
||||||
* @param domainExclusions - The domain exclusions to check against
|
* @param domainExclusions - The domain exclusions to check against
|
||||||
*/
|
*/
|
||||||
private showCipherAsPasskey(cipher: CipherView, domainExclusions: Set<string> | null): boolean {
|
private async showCipherAsPasskey(
|
||||||
|
cipher: CipherView,
|
||||||
|
domainExclusions: Set<string> | null,
|
||||||
|
): Promise<boolean> {
|
||||||
if (cipher.type !== CipherType.Login || !this.focusedFieldData?.showPasskeys) {
|
if (cipher.type !== CipherType.Login || !this.focusedFieldData?.showPasskeys) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -514,10 +531,7 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return this.inlineMenuFido2Credentials.has(credentialId);
|
||||||
this.inlineMenuFido2Credentials.size === 0 ||
|
|
||||||
this.inlineMenuFido2Credentials.has(credentialId)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -635,12 +649,35 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
* @param credentials - The FIDO2 credentials to store
|
* @param credentials - The FIDO2 credentials to store
|
||||||
*/
|
*/
|
||||||
private storeInlineMenuFido2Credentials(credentials: Fido2CredentialView[]) {
|
private storeInlineMenuFido2Credentials(credentials: Fido2CredentialView[]) {
|
||||||
|
this.inlineMenuFido2Credentials.clear();
|
||||||
|
|
||||||
credentials.forEach(
|
credentials.forEach(
|
||||||
(credential) =>
|
(credential) =>
|
||||||
credential?.credentialId && this.inlineMenuFido2Credentials.add(credential.credentialId),
|
credential?.credentialId && this.inlineMenuFido2Credentials.add(credential.credentialId),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the passkey credentials available from an active FIDO2 request for a given tab.
|
||||||
|
*
|
||||||
|
* @param tabId - The tab id to get the active request for.
|
||||||
|
*/
|
||||||
|
private availablePasskeyAuthCredentials$(tabId: number): Observable<Fido2CredentialView[]> {
|
||||||
|
return this.fido2ActiveRequestManager
|
||||||
|
.getActiveRequest$(tabId)
|
||||||
|
.pipe(map((request) => request?.credentials ?? []));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts an active FIDO2 request for a given tab and updates the inline menu ciphers.
|
||||||
|
*
|
||||||
|
* @param sender - The sender of the message
|
||||||
|
*/
|
||||||
|
private async abortFido2ActiveRequest(sender: chrome.runtime.MessageSender) {
|
||||||
|
this.fido2ActiveRequestManager.removeActiveRequest(sender.tab.id);
|
||||||
|
await this.updateOverlayCiphers(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the neverDomains setting from the domain settings service.
|
* Gets the neverDomains setting from the domain settings service.
|
||||||
*/
|
*/
|
||||||
@ -900,11 +937,12 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);
|
const cipher = this.inlineMenuCiphers.get(inlineMenuCipherId);
|
||||||
|
|
||||||
if (usePasskey && cipher.login?.hasFido2Credentials) {
|
if (usePasskey && cipher.login?.hasFido2Credentials) {
|
||||||
await this.fido2ClientService.autofillCredential(
|
await this.authenticatePasskeyCredential(
|
||||||
sender.tab.id,
|
sender.tab.id,
|
||||||
cipher.login.fido2Credentials[0].credentialId,
|
cipher.login.fido2Credentials[0].credentialId,
|
||||||
);
|
);
|
||||||
this.updateLastUsedInlineMenuCipher(inlineMenuCipherId, cipher);
|
this.updateLastUsedInlineMenuCipher(inlineMenuCipherId, cipher);
|
||||||
|
this.closeInlineMenu(sender, { forceCloseInlineMenu: true });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -927,6 +965,24 @@ export class OverlayBackground implements OverlayBackgroundInterface {
|
|||||||
this.updateLastUsedInlineMenuCipher(inlineMenuCipherId, cipher);
|
this.updateLastUsedInlineMenuCipher(inlineMenuCipherId, cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a FIDO2 authentication from the inline menu using the passed credential ID.
|
||||||
|
*
|
||||||
|
* @param tabId - The tab ID to trigger the authentication for
|
||||||
|
* @param credentialId - The credential ID to authenticate
|
||||||
|
*/
|
||||||
|
async authenticatePasskeyCredential(tabId: number, credentialId: string) {
|
||||||
|
const request = this.fido2ActiveRequestManager.getActiveRequest(tabId);
|
||||||
|
if (!request) {
|
||||||
|
this.logService.error(
|
||||||
|
"Could not complete passkey autofill due to missing active Fido2 request",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request.subject.next({ type: Fido2ActiveRequestEvents.Continue, credentialId });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the most recently used cipher at the top of the list of ciphers.
|
* Sets the most recently used cipher at the top of the list of ciphers.
|
||||||
*
|
*
|
||||||
|
@ -2,6 +2,7 @@ import { mock, MockProxy } from "jest-mock-extended";
|
|||||||
import { BehaviorSubject } from "rxjs";
|
import { BehaviorSubject } from "rxjs";
|
||||||
|
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||||
import {
|
import {
|
||||||
AssertCredentialParams,
|
AssertCredentialParams,
|
||||||
CreateCredentialParams,
|
CreateCredentialParams,
|
||||||
@ -52,6 +53,7 @@ describe("Fido2Background", () => {
|
|||||||
let tabMock!: MockProxy<chrome.tabs.Tab>;
|
let tabMock!: MockProxy<chrome.tabs.Tab>;
|
||||||
let senderMock!: MockProxy<chrome.runtime.MessageSender>;
|
let senderMock!: MockProxy<chrome.runtime.MessageSender>;
|
||||||
let logService!: MockProxy<LogService>;
|
let logService!: MockProxy<LogService>;
|
||||||
|
let fido2ActiveRequestManager: MockProxy<Fido2ActiveRequestManager>;
|
||||||
let fido2ClientService!: MockProxy<Fido2ClientService>;
|
let fido2ClientService!: MockProxy<Fido2ClientService>;
|
||||||
let vaultSettingsService!: MockProxy<VaultSettingsService>;
|
let vaultSettingsService!: MockProxy<VaultSettingsService>;
|
||||||
let scriptInjectorServiceMock!: MockProxy<BrowserScriptInjectorService>;
|
let scriptInjectorServiceMock!: MockProxy<BrowserScriptInjectorService>;
|
||||||
@ -77,9 +79,11 @@ describe("Fido2Background", () => {
|
|||||||
|
|
||||||
enablePasskeysMock$ = new BehaviorSubject(true);
|
enablePasskeysMock$ = new BehaviorSubject(true);
|
||||||
vaultSettingsService.enablePasskeys$ = enablePasskeysMock$;
|
vaultSettingsService.enablePasskeys$ = enablePasskeysMock$;
|
||||||
|
fido2ActiveRequestManager = mock<Fido2ActiveRequestManager>();
|
||||||
fido2ClientService.isFido2FeatureEnabled.mockResolvedValue(true);
|
fido2ClientService.isFido2FeatureEnabled.mockResolvedValue(true);
|
||||||
fido2Background = new Fido2Background(
|
fido2Background = new Fido2Background(
|
||||||
logService,
|
logService,
|
||||||
|
fido2ActiveRequestManager,
|
||||||
fido2ClientService,
|
fido2ClientService,
|
||||||
vaultSettingsService,
|
vaultSettingsService,
|
||||||
scriptInjectorServiceMock,
|
scriptInjectorServiceMock,
|
||||||
|
@ -3,6 +3,7 @@ import { pairwise } from "rxjs/operators";
|
|||||||
|
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
import { Fido2ActiveRequestManager } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||||
import {
|
import {
|
||||||
AssertCredentialParams,
|
AssertCredentialParams,
|
||||||
AssertCredentialResult,
|
AssertCredentialResult,
|
||||||
@ -49,6 +50,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private logService: LogService,
|
private logService: LogService,
|
||||||
|
private fido2ActiveRequestManager: Fido2ActiveRequestManager,
|
||||||
private fido2ClientService: Fido2ClientService,
|
private fido2ClientService: Fido2ClientService,
|
||||||
private vaultSettingsService: VaultSettingsService,
|
private vaultSettingsService: VaultSettingsService,
|
||||||
private scriptInjectorService: ScriptInjectorService,
|
private scriptInjectorService: ScriptInjectorService,
|
||||||
@ -96,6 +98,7 @@ export class Fido2Background implements Fido2BackgroundInterface {
|
|||||||
previousEnablePasskeysSetting: boolean,
|
previousEnablePasskeysSetting: boolean,
|
||||||
enablePasskeys: boolean,
|
enablePasskeys: boolean,
|
||||||
) {
|
) {
|
||||||
|
this.fido2ActiveRequestManager.removeAllActiveRequests();
|
||||||
await this.updateContentScriptRegistration();
|
await this.updateContentScriptRegistration();
|
||||||
|
|
||||||
if (previousEnablePasskeysSetting === undefined) {
|
if (previousEnablePasskeysSetting === undefined) {
|
||||||
|
@ -60,6 +60,10 @@ import { MessageWithMetadata, Messenger } from "./messaging/messenger";
|
|||||||
message.data as InsecureAssertCredentialParams,
|
message.data as InsecureAssertCredentialParams,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.type === MessageType.AbortRequest) {
|
||||||
|
return sendExtensionMessage("fido2AbortRequest", { abortedRequestId: requestId });
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
abortController.signal.removeEventListener("abort", abortHandler);
|
abortController.signal.removeEventListener("abort", abortHandler);
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,12 @@ import { Messenger } from "./messaging/messenger";
|
|||||||
const internalAbortControllers = [new AbortController(), new AbortController()];
|
const internalAbortControllers = [new AbortController(), new AbortController()];
|
||||||
const bitwardenResponse = async (internalAbortController: AbortController) => {
|
const bitwardenResponse = async (internalAbortController: AbortController) => {
|
||||||
try {
|
try {
|
||||||
|
const abortListener = () =>
|
||||||
|
messenger.request({
|
||||||
|
type: MessageType.AbortRequest,
|
||||||
|
abortedRequestId: abortSignal.toString(),
|
||||||
|
});
|
||||||
|
internalAbortController.signal.addEventListener("abort", abortListener);
|
||||||
const response = await messenger.request(
|
const response = await messenger.request(
|
||||||
{
|
{
|
||||||
type: MessageType.CredentialGetRequest,
|
type: MessageType.CredentialGetRequest,
|
||||||
@ -138,6 +144,7 @@ import { Messenger } from "./messaging/messenger";
|
|||||||
},
|
},
|
||||||
internalAbortController.signal,
|
internalAbortController.signal,
|
||||||
);
|
);
|
||||||
|
internalAbortController.signal.removeEventListener("abort", abortListener);
|
||||||
if (response.type !== MessageType.CredentialGetResponse) {
|
if (response.type !== MessageType.CredentialGetResponse) {
|
||||||
throw new Error("Something went wrong.");
|
throw new Error("Something went wrong.");
|
||||||
}
|
}
|
||||||
|
@ -242,12 +242,13 @@ export class BrowserFido2UserInterfaceSession implements Fido2UserInterfaceSessi
|
|||||||
cipherIds,
|
cipherIds,
|
||||||
userVerification,
|
userVerification,
|
||||||
assumeUserPresence,
|
assumeUserPresence,
|
||||||
|
masterPasswordRepromptRequired,
|
||||||
}: PickCredentialParams): Promise<{ cipherId: string; userVerified: boolean }> {
|
}: PickCredentialParams): Promise<{ cipherId: string; userVerified: boolean }> {
|
||||||
// NOTE: For now, we are defaulting to a userVerified status of `true` when the request
|
// NOTE: For now, we are defaulting to a userVerified status of `true` when the request
|
||||||
// is for a conditionally mediated authentication. This will allow for mediated conditional
|
// is for a conditionally mediated authentication. This will allow for mediated conditional
|
||||||
// authentication to function without requiring user interaction. This is a product
|
// authentication to function without requiring user interaction. This is a product
|
||||||
// decision, rather than a decision based on the expected technical specifications.
|
// decision, rather than a decision based on the expected technical specifications.
|
||||||
if (assumeUserPresence && cipherIds.length === 1) {
|
if (assumeUserPresence && cipherIds.length === 1 && !masterPasswordRepromptRequired) {
|
||||||
return { cipherId: cipherIds[0], userVerified: userVerification };
|
return { cipherId: cipherIds[0], userVerified: userVerification };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
|||||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||||
|
import { Fido2ActiveRequestManager as Fido2ActiveRequestManagerAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-active-request-manager.abstraction";
|
||||||
import { Fido2AuthenticatorService as Fido2AuthenticatorServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-authenticator.service.abstraction";
|
import { Fido2AuthenticatorService as Fido2AuthenticatorServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-authenticator.service.abstraction";
|
||||||
import { Fido2ClientService as Fido2ClientServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
import { Fido2ClientService as Fido2ClientServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||||
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-user-interface.service.abstraction";
|
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||||
@ -324,6 +325,7 @@ export default class MainBackground {
|
|||||||
userVerificationApiService: UserVerificationApiServiceAbstraction;
|
userVerificationApiService: UserVerificationApiServiceAbstraction;
|
||||||
fido2UserInterfaceService: Fido2UserInterfaceServiceAbstraction;
|
fido2UserInterfaceService: Fido2UserInterfaceServiceAbstraction;
|
||||||
fido2AuthenticatorService: Fido2AuthenticatorServiceAbstraction;
|
fido2AuthenticatorService: Fido2AuthenticatorServiceAbstraction;
|
||||||
|
fido2ActiveRequestManager: Fido2ActiveRequestManagerAbstraction;
|
||||||
fido2ClientService: Fido2ClientServiceAbstraction;
|
fido2ClientService: Fido2ClientServiceAbstraction;
|
||||||
avatarService: AvatarServiceAbstraction;
|
avatarService: AvatarServiceAbstraction;
|
||||||
mainContextMenuHandler: MainContextMenuHandler;
|
mainContextMenuHandler: MainContextMenuHandler;
|
||||||
@ -1021,7 +1023,7 @@ export default class MainBackground {
|
|||||||
this.accountService,
|
this.accountService,
|
||||||
this.logService,
|
this.logService,
|
||||||
);
|
);
|
||||||
const fido2ActiveRequestManager = new Fido2ActiveRequestManager();
|
this.fido2ActiveRequestManager = new Fido2ActiveRequestManager();
|
||||||
this.fido2ClientService = new Fido2ClientService(
|
this.fido2ClientService = new Fido2ClientService(
|
||||||
this.fido2AuthenticatorService,
|
this.fido2AuthenticatorService,
|
||||||
this.configService,
|
this.configService,
|
||||||
@ -1029,7 +1031,7 @@ export default class MainBackground {
|
|||||||
this.vaultSettingsService,
|
this.vaultSettingsService,
|
||||||
this.domainSettingsService,
|
this.domainSettingsService,
|
||||||
this.taskSchedulerService,
|
this.taskSchedulerService,
|
||||||
fido2ActiveRequestManager,
|
this.fido2ActiveRequestManager,
|
||||||
this.logService,
|
this.logService,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -1057,6 +1059,7 @@ export default class MainBackground {
|
|||||||
if (!this.popupOnlyContext) {
|
if (!this.popupOnlyContext) {
|
||||||
this.fido2Background = new Fido2Background(
|
this.fido2Background = new Fido2Background(
|
||||||
this.logService,
|
this.logService,
|
||||||
|
this.fido2ActiveRequestManager,
|
||||||
this.fido2ClientService,
|
this.fido2ClientService,
|
||||||
this.vaultSettingsService,
|
this.vaultSettingsService,
|
||||||
this.scriptInjectorService,
|
this.scriptInjectorService,
|
||||||
@ -1605,7 +1608,8 @@ export default class MainBackground {
|
|||||||
this.autofillSettingsService,
|
this.autofillSettingsService,
|
||||||
this.i18nService,
|
this.i18nService,
|
||||||
this.platformUtilsService,
|
this.platformUtilsService,
|
||||||
this.fido2ClientService,
|
this.vaultSettingsService,
|
||||||
|
this.fido2ActiveRequestManager,
|
||||||
this.themeStateService,
|
this.themeStateService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "__MSG_extName__",
|
"name": "__MSG_extName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "2024.8.2",
|
"version": "2024.9.0",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Bitwarden Inc.",
|
"author": "Bitwarden Inc.",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"minimum_chrome_version": "102.0",
|
"minimum_chrome_version": "102.0",
|
||||||
"name": "__MSG_extName__",
|
"name": "__MSG_extName__",
|
||||||
"short_name": "__MSG_appName__",
|
"short_name": "__MSG_appName__",
|
||||||
"version": "2024.8.2",
|
"version": "2024.9.0",
|
||||||
"description": "__MSG_extDesc__",
|
"description": "__MSG_extDesc__",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"author": "Bitwarden Inc.",
|
"author": "Bitwarden Inc.",
|
||||||
|
@ -57,6 +57,7 @@ import { PremiumV2Component } from "../billing/popup/settings/premium-v2.compone
|
|||||||
import { PremiumComponent } from "../billing/popup/settings/premium.component";
|
import { PremiumComponent } from "../billing/popup/settings/premium.component";
|
||||||
import BrowserPopupUtils from "../platform/popup/browser-popup-utils";
|
import BrowserPopupUtils from "../platform/popup/browser-popup-utils";
|
||||||
import { popupRouterCacheGuard } from "../platform/popup/view-cache/popup-router-cache.service";
|
import { popupRouterCacheGuard } from "../platform/popup/view-cache/popup-router-cache.service";
|
||||||
|
import { CredentialGeneratorHistoryComponent } from "../tools/popup/generator/credential-generator-history.component";
|
||||||
import { CredentialGeneratorComponent } from "../tools/popup/generator/credential-generator.component";
|
import { CredentialGeneratorComponent } from "../tools/popup/generator/credential-generator.component";
|
||||||
import { GeneratorComponent } from "../tools/popup/generator/generator.component";
|
import { GeneratorComponent } from "../tools/popup/generator/generator.component";
|
||||||
import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component";
|
import { PasswordGeneratorHistoryComponent } from "../tools/popup/generator/password-generator-history.component";
|
||||||
@ -274,12 +275,11 @@ const routes: Routes = [
|
|||||||
canActivate: [authGuard],
|
canActivate: [authGuard],
|
||||||
data: { state: "generator" },
|
data: { state: "generator" },
|
||||||
},
|
},
|
||||||
{
|
...extensionRefreshSwap(PasswordGeneratorHistoryComponent, CredentialGeneratorHistoryComponent, {
|
||||||
path: "generator-history",
|
path: "generator-history",
|
||||||
component: PasswordGeneratorHistoryComponent,
|
|
||||||
canActivate: [authGuard],
|
canActivate: [authGuard],
|
||||||
data: { state: "generator-history" },
|
data: { state: "generator-history" },
|
||||||
},
|
}),
|
||||||
...extensionRefreshSwap(ImportBrowserComponent, ImportBrowserV2Component, {
|
...extensionRefreshSwap(ImportBrowserComponent, ImportBrowserV2Component, {
|
||||||
path: "import",
|
path: "import",
|
||||||
canActivate: [authGuard],
|
canActivate: [authGuard],
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
<popup-page>
|
||||||
|
<popup-header slot="header" [pageTitle]="'passwordHistory' | i18n" showBackButton>
|
||||||
|
<ng-container slot="end">
|
||||||
|
<app-pop-out></app-pop-out>
|
||||||
|
</ng-container>
|
||||||
|
</popup-header>
|
||||||
|
<bit-empty-credential-history *ngIf="!(hasHistory$ | async)" style="display: contents" />
|
||||||
|
<bit-credential-generator-history *ngIf="hasHistory$ | async" />
|
||||||
|
<popup-footer slot="footer">
|
||||||
|
<button
|
||||||
|
[disabled]="!(hasHistory$ | async)"
|
||||||
|
bitButton
|
||||||
|
type="submit"
|
||||||
|
buttonType="primary"
|
||||||
|
(click)="clear()"
|
||||||
|
>
|
||||||
|
{{ "clearHistory" | i18n }}
|
||||||
|
</button>
|
||||||
|
</popup-footer>
|
||||||
|
</popup-page>
|
@ -0,0 +1,66 @@
|
|||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { Component } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
|
import { BehaviorSubject, distinctUntilChanged, firstValueFrom, map, switchMap } from "rxjs";
|
||||||
|
|
||||||
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
import { ButtonModule, ContainerComponent } from "@bitwarden/components";
|
||||||
|
import {
|
||||||
|
CredentialGeneratorHistoryComponent as CredentialGeneratorHistoryToolsComponent,
|
||||||
|
EmptyCredentialHistoryComponent,
|
||||||
|
} from "@bitwarden/generator-components";
|
||||||
|
import { GeneratorHistoryService } from "@bitwarden/generator-history";
|
||||||
|
|
||||||
|
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||||
|
import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component";
|
||||||
|
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||||
|
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "app-credential-generator-history",
|
||||||
|
templateUrl: "credential-generator-history.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
ButtonModule,
|
||||||
|
CommonModule,
|
||||||
|
ContainerComponent,
|
||||||
|
JslibModule,
|
||||||
|
PopOutComponent,
|
||||||
|
PopupHeaderComponent,
|
||||||
|
PopupPageComponent,
|
||||||
|
CredentialGeneratorHistoryToolsComponent,
|
||||||
|
EmptyCredentialHistoryComponent,
|
||||||
|
PopupFooterComponent,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class CredentialGeneratorHistoryComponent {
|
||||||
|
protected readonly hasHistory$ = new BehaviorSubject<boolean>(false);
|
||||||
|
protected readonly userId$ = new BehaviorSubject<UserId>(null);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private accountService: AccountService,
|
||||||
|
private history: GeneratorHistoryService,
|
||||||
|
) {
|
||||||
|
this.accountService.activeAccount$
|
||||||
|
.pipe(
|
||||||
|
takeUntilDestroyed(),
|
||||||
|
map(({ id }) => id),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
)
|
||||||
|
.subscribe(this.userId$);
|
||||||
|
|
||||||
|
this.userId$
|
||||||
|
.pipe(
|
||||||
|
takeUntilDestroyed(),
|
||||||
|
switchMap((id) => id && this.history.credentials$(id)),
|
||||||
|
map((credentials) => credentials.length > 0),
|
||||||
|
)
|
||||||
|
.subscribe(this.hasHistory$);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear = async () => {
|
||||||
|
await this.history.clear(await firstValueFrom(this.userId$));
|
||||||
|
};
|
||||||
|
}
|
@ -64,7 +64,7 @@ export class SendGroupingsComponent extends BaseSendComponent implements OnInit,
|
|||||||
dialogService,
|
dialogService,
|
||||||
toastService,
|
toastService,
|
||||||
);
|
);
|
||||||
super.onSuccessfulLoad = async () => {
|
this.onSuccessfulLoad = async () => {
|
||||||
this.selectAll();
|
this.selectAll();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ export class SendTypeComponent extends BaseSendComponent implements OnInit, OnDe
|
|||||||
dialogService,
|
dialogService,
|
||||||
toastService,
|
toastService,
|
||||||
);
|
);
|
||||||
super.onSuccessfulLoad = async () => {
|
this.onSuccessfulLoad = async () => {
|
||||||
this.selectType(this.type);
|
this.selectType(this.type);
|
||||||
};
|
};
|
||||||
this.applySavedState =
|
this.applySavedState =
|
||||||
|
@ -124,48 +124,48 @@
|
|||||||
<value>Kodus, tööl ja teel - Bitwarden hoiustab imelihtsalt kõik su paroolid, pääsuvõtmed ja tundliku info.</value>
|
<value>Kodus, tööl ja teel - Bitwarden hoiustab imelihtsalt kõik su paroolid, pääsuvõtmed ja tundliku info.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Description" xml:space="preserve">
|
<data name="Description" xml:space="preserve">
|
||||||
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
|
<value>Tunnustatud firmade PCMag, WIRED, The Verge, CNET, G2 ja teiste poolt kui parim paroolihaldur!
|
||||||
|
|
||||||
SECURE YOUR DIGITAL LIFE
|
KAITSE ENDA DIGITAALSET MAAILMA
|
||||||
Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access.
|
Lukusta oma digitaalne maailm ja kaitse seda andmelekete vastu luues ja salvestades unikaalsed ja tugevad paroolid iga konto jaoks. Halda kõike täielikult krüpteeritud hoidlas, kuhu pääsed ainult sina ligi.
|
||||||
|
|
||||||
ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE
|
PÄÄSE OMA ANDMETELE LIGI IGALT POOLT, IGAL AJAL, IGAST SEADMEST
|
||||||
Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions.
|
Halda, hoiusta, kaitse ja jaga lõpmatult palju paroole mööda lõpmatult paljusid seadmeid ilma piiranguteta.
|
||||||
|
|
||||||
EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE
|
KÕIGIL PEAKSID OLEMA TÖÖRIISTAD OHUTULT INTERNETIS SEIKLEMISEKS
|
||||||
Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features.
|
Kasuta Bitwardenit tasuta ilma reklaamide või andmete müümisega. Bitwarden usub, et kõigil peaks olema võimalus surfata ohutult internetis. Preemium plaanid pakuvad juurdepääsu veel rohkematele funktsioonidele.
|
||||||
|
|
||||||
EMPOWER YOUR TEAMS WITH BITWARDEN
|
VÕIMENDA OMA TIIME BITWARDENIGA
|
||||||
Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more.
|
Tiimide ja ettevõtete plaanid tulevad koos professionaalsete ärifunktsioonidega. Mõned näited on SSO liides, ise majutamine, arvutikataloogide ühendamine ja SCIM kasutamine, globaalsed seaded, API, sündmuste logid ja veel rohkemgi.
|
||||||
|
|
||||||
Use Bitwarden to secure your workforce and share sensitive information with colleagues.
|
Kasuta Bitwardenit oma töötajate turvamiseks ja tundliku informatsiooni jagamiseks kolleegidega.
|
||||||
|
|
||||||
|
|
||||||
More reasons to choose Bitwarden:
|
Veel Põhjusi Miks Valida Bitwarden:
|
||||||
|
|
||||||
World-Class Encryption
|
Maailmatasemel Krüpteering
|
||||||
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private.
|
Paroolid on kaitstud tipptehnoloogilise täieliku krüpteerimisega (AES-256 bit, salted hashtag ja PBKDF2 SHA-256), nii et sinu andmed püsivad privaatsete ja turvalistena.
|
||||||
|
|
||||||
3rd-party Audits
|
Põhjalikud turvatestid kolmandate firmade poolt
|
||||||
Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications.
|
Bitwarden korraldab regulaarselt põhjalike turvateste tuntud kolmandate firmade poolt. Need igaaastased kontrolltestid sisaldavad kogu koodibaasi ülevaatust ja test-küberrünnakuid Bitwardeni IP-de, serverite ja veebirakenduste vastu.
|
||||||
|
|
||||||
Advanced 2FA
|
Kõrgetasemeline 2-astmeline autentiteerimine (2FA)
|
||||||
Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey.
|
Kaitse oma andmeid kolmanda poole autentitaatoriga, emailile saadetud koodide või FIDO2 WebAuthn süsteemidega, nagu näiteks füüsiline turvavõti või pääsuvõti.
|
||||||
|
|
||||||
Bitwarden Send
|
Bitwarden Send
|
||||||
Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure.
|
Jaga andmeid otse teistega kasutades täieliku krüpteerimist ja vähenda lekke tõenäosust.
|
||||||
|
|
||||||
Built-in Generator
|
Sisse ehitatud Generaator
|
||||||
Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy.
|
Loo igale oma saidile pikkasid, keerulisi ning täiesti kordumatuid paroole ja ainulaadseid kasutajanimesid. Veel paremaks privaatsuseks saad end ühendada ka variemaili (email alias) pakkujatega.
|
||||||
|
|
||||||
Global Translations
|
Paljudes Keeltes
|
||||||
Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin.
|
Bitwardenit on tõlgitud juba 60 erinevasse keelde ja see arv kasvab, tänu meie globaalsele kogukonnale Crowdin platvormil.
|
||||||
|
|
||||||
Cross-Platform Applications
|
Kõigis Sinu Seadmetes
|
||||||
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
|
Kaitse ja jaga oma tundliku informatsiooni Bitwardeni Hoidlas nii brauserist, telefonist, arvutist kui ka mujaltki.
|
||||||
|
|
||||||
Bitwarden secures more than just passwords
|
Bitwarden hoiustab peale paroolide veel muudki
|
||||||
End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev!
|
Täielikult krüpteeritud andmehalduse lahendused Bitwardenilt võimendavad organisatsioone ja hoiustavad kõike, kaasa arvatud arendajate saladusi ja pääsuvõtmeid. Külasta veebilehte bitwarden.com, et uurida lähemalt Bitwarden Secrets Manageri kohta ja vaata lähemalt passwordless.dev!
|
||||||
</value>
|
</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AssetTitle" xml:space="preserve">
|
<data name="AssetTitle" xml:space="preserve">
|
||||||
|
@ -124,49 +124,46 @@
|
|||||||
<value>Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais.</value>
|
<value>Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Description" xml:space="preserve">
|
<data name="Description" xml:space="preserve">
|
||||||
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
|
<value>Reconhecido como o melhor gerenciador de senhas por "PCMag", 'WIRED', 'The Verge', 'CNET', 'G2', entre outros!
|
||||||
|
|
||||||
SECURE YOUR DIGITAL LIFE
|
PROTEJA A SUA VIDA DIGITAL
|
||||||
Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access.
|
Deixe a sua vida digital segura e se proteja contra violações de dados gerando e salvando senhas únicas e fortes para cada conta pessoal. Mantendo tudo isso em um cofre encriptografado de ponta a ponta que apenas você pode acessar.
|
||||||
|
|
||||||
ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE
|
ACESSE OS SEUS DADOS, EM QUALQUER LUGAR, HORA E DISPOSITIVO
|
||||||
Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions.
|
Gerencie, armazene, proteja e compartilhe senhas facilmente entre dispositivos ilimitados e sem restrições.
|
||||||
|
|
||||||
EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE
|
TODOS DEVERIAM TEM FERRAMENTAS PARA SE PROTEGER ONLINE
|
||||||
Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features.
|
Utilize Bitwarden de graça sem anuncios ou venda dos seus dados. A Bitwarden acredita que todos deveriam ter a opção de estar seguro online. Planos Premium oferecem recursos mais avançados.
|
||||||
|
|
||||||
EMPOWER YOUR TEAMS WITH BITWARDEN
|
EMPODERE O SEUS TIMES COM BITWARDEN
|
||||||
Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more.
|
Os Planos para times e empresas vem com recursos profissionais para negócios. Alguns exemplos inculuem integração SSO, Auto-hospedagem, integração de diretório e provisionamento SCIM, políticas globais, acesso API, registro de eventos e mais.
|
||||||
|
|
||||||
Use Bitwarden to secure your workforce and share sensitive information with colleagues.
|
Utilizer Bitwarn para proteger os seus empregados e compartilhar informações sensíveis para os colegas.
|
||||||
|
|
||||||
|
Mais razões para escolher Bitwarden:
|
||||||
|
|
||||||
More reasons to choose Bitwarden:
|
Senhas encriptografadas por classe de palavras são protegidas com criptografia de ponta a ponta avançada (AES-256 bit, salted hashtag, and PBKDF2 SHA-256), então os seus dados ficam seguros e privados.
|
||||||
|
|
||||||
World-Class Encryption
|
Auditoria de Terceiros
|
||||||
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private.
|
Bitwarden regularmente conduz auditorias de terceiros com notáveis empresas de segurança. Essas audições anuais incluem qualificação e penetração do código fonte através de IPs da Bitwarden, servidores e aplicações WEB.
|
||||||
|
|
||||||
3rd-party Audits
|
2FA Avançado
|
||||||
Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications.
|
Proteja o seu login com um autenticador de doisfatores, códigos de email ou credenciais FIDO2 WebAuthn como chave de segurança por hardware ou chave de acesso.
|
||||||
|
|
||||||
Advanced 2FA
|
Envio Bitwarden
|
||||||
Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey.
|
Transmita dados diretamente para outros enquanto mantem segurança de encriptografia ponta a ponta e limitando exposição.
|
||||||
|
|
||||||
Bitwarden Send
|
Gerador integrado
|
||||||
Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure.
|
Crie senhas grandes, complexas e diferentes e nomes de usuário unicos para cada site que visitar. Integre com provedores de email para privacidade adicional
|
||||||
|
|
||||||
Built-in Generator
|
Tradutores globais
|
||||||
Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy.
|
As traduções da Bitwarden estão disponíveis para mais de 60 líguas, traduzidas pela comunidade global através do Crowdin.
|
||||||
|
|
||||||
Global Translations
|
Aplicações Multi-Plataforma
|
||||||
Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin.
|
Proteja e compartilhe conteúdo sensível dentro do Vault da Bitwarden de qualquer navegador, dispositivo móvel, ou desktop OS, entre outros.
|
||||||
|
|
||||||
Cross-Platform Applications
|
Bitwarden protege mais do que apenas soluções em gerenciamento de credenciais de senhas encriptografadas ponta a ponta, Bitwarden empodera organizações para proteger qualquer coisa, incluindo segredos de desenvolvedor e chaves de acesso.
|
||||||
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
|
Visite Bitwarden.com para aprender mais sobre Bitwarden Secrets Manager e Bitwarden Passwordless.dev!</value>
|
||||||
|
|
||||||
Bitwarden secures more than just passwords
|
|
||||||
End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev!
|
|
||||||
</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="AssetTitle" xml:space="preserve">
|
<data name="AssetTitle" xml:space="preserve">
|
||||||
<value>Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais.</value>
|
<value>Em casa, no trabalho, ou em qualquer lugar, o Bitwarden protege facilmente todas as suas senhas, senhas e informações confidenciais.</value>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@bitwarden/cli",
|
"name": "@bitwarden/cli",
|
||||||
"description": "A secure and free password manager for all of your devices.",
|
"description": "A secure and free password manager for all of your devices.",
|
||||||
"version": "2024.8.2",
|
"version": "2024.9.0",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bitwarden",
|
"bitwarden",
|
||||||
"password",
|
"password",
|
||||||
|
@ -3,6 +3,7 @@ import { firstValueFrom, map } from "rxjs";
|
|||||||
|
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { UserId } from "@bitwarden/common/types/guid";
|
||||||
|
|
||||||
import { UnlockCommand } from "./auth/commands/unlock.command";
|
import { UnlockCommand } from "./auth/commands/unlock.command";
|
||||||
import { Response } from "./models/response";
|
import { Response } from "./models/response";
|
||||||
@ -135,10 +136,31 @@ export abstract class BaseProgram {
|
|||||||
|
|
||||||
protected async exitIfLocked() {
|
protected async exitIfLocked() {
|
||||||
const userId = await this.exitIfNotAuthed();
|
const userId = await this.exitIfNotAuthed();
|
||||||
if (await this.serviceContainer.cryptoService.hasUserKey()) {
|
|
||||||
|
// If the process.env does not have a BW_SESSION key, then we will never be able to retrieve
|
||||||
|
// the auto user key from secure storage. This is because the auto user key is encrypted with
|
||||||
|
// the session key.
|
||||||
|
const hasUserKey =
|
||||||
|
await this.serviceContainer.userAutoUnlockKeyService.setUserKeyInMemoryIfAutoUserKeySet(
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (hasUserKey) {
|
||||||
|
// User is unlocked
|
||||||
return;
|
return;
|
||||||
} else if (process.env.BW_NOINTERACTION !== "true") {
|
}
|
||||||
// must unlock
|
|
||||||
|
// User is locked
|
||||||
|
await this.handleLockedUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleLockedUser(userId: UserId) {
|
||||||
|
if (process.env.BW_NOINTERACTION === "true") {
|
||||||
|
this.processResponse(Response.error("Vault is locked."), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must unlock with interaction allowed
|
||||||
if (await this.serviceContainer.keyConnectorService.getUsesKeyConnector(userId)) {
|
if (await this.serviceContainer.keyConnectorService.getUsesKeyConnector(userId)) {
|
||||||
const response = Response.error(
|
const response = Response.error(
|
||||||
"Your vault is locked. You must unlock your vault using your session key.\n" +
|
"Your vault is locked. You must unlock your vault using your session key.\n" +
|
||||||
@ -164,9 +186,6 @@ export abstract class BaseProgram {
|
|||||||
this.processResponse(response, true);
|
this.processResponse(response, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.processResponse(Response.error("Vault is locked."), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async exitIfFeatureFlagDisabled(featureFlag: FeatureFlag) {
|
protected async exitIfFeatureFlagDisabled(featureFlag: FeatureFlag) {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import * as chalk from "chalk";
|
import * as chalk from "chalk";
|
||||||
import { program, Command, OptionValues } from "commander";
|
import { program, Command, OptionValues } from "commander";
|
||||||
import { firstValueFrom } from "rxjs";
|
|
||||||
|
|
||||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||||
|
|
||||||
@ -61,18 +60,8 @@ export class Program extends BaseProgram {
|
|||||||
process.env.BW_NOINTERACTION = "true";
|
process.env.BW_NOINTERACTION = "true";
|
||||||
});
|
});
|
||||||
|
|
||||||
program.on("option:session", async (key) => {
|
program.on("option:session", (key) => {
|
||||||
process.env.BW_SESSION = key;
|
process.env.BW_SESSION = key;
|
||||||
|
|
||||||
// once we have the session key, we can set the user key in memory
|
|
||||||
const activeAccount = await firstValueFrom(
|
|
||||||
this.serviceContainer.accountService.activeAccount$,
|
|
||||||
);
|
|
||||||
if (activeAccount) {
|
|
||||||
await this.serviceContainer.userAutoUnlockKeyService.setUserKeyInMemoryIfAutoUserKeySet(
|
|
||||||
activeAccount.id,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
program.on("command:*", () => {
|
program.on("command:*", () => {
|
||||||
|
@ -285,7 +285,13 @@ export class ServiceContainer {
|
|||||||
this.secureStorageService = new NodeEnvSecureStorageService(
|
this.secureStorageService = new NodeEnvSecureStorageService(
|
||||||
this.storageService,
|
this.storageService,
|
||||||
this.logService,
|
this.logService,
|
||||||
this.encryptService,
|
// MAC failures for secure storage are being logged for customers today and
|
||||||
|
// they occur when users unlock / login and refresh a session key but don't
|
||||||
|
// export it into their environment (e.g. BW_SESSION_KEY). This leaves a stale
|
||||||
|
// BW_SESSION key in the env which is attempted to be used to decrypt the auto
|
||||||
|
// unlock user key which obviously fails. So, to resolve this, we will not log
|
||||||
|
// MAC failures for secure storage.
|
||||||
|
new EncryptServiceImplementation(this.cryptoFunctionService, this.logService, false),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.memoryStorageService = new MemoryStorageService();
|
this.memoryStorageService = new MemoryStorageService();
|
||||||
@ -803,6 +809,10 @@ export class ServiceContainer {
|
|||||||
await this.i18nService.init();
|
await this.i18nService.init();
|
||||||
this.twoFactorService.init();
|
this.twoFactorService.init();
|
||||||
|
|
||||||
|
// If a user has a BW_SESSION key stored in their env (not process.env.BW_SESSION),
|
||||||
|
// this should set the user key to unlock the vault on init.
|
||||||
|
// TODO: ideally, we wouldn't want to do this here but instead only for commands that require the vault to be unlocked
|
||||||
|
// as this runs on every command and could be a performance hit
|
||||||
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
|
||||||
if (activeAccount?.id) {
|
if (activeAccount?.id) {
|
||||||
await this.userAutoUnlockKeyService.setUserKeyInMemoryIfAutoUserKeySet(activeAccount.id);
|
await this.userAutoUnlockKeyService.setUserKeyInMemoryIfAutoUserKeySet(activeAccount.id);
|
||||||
|
1
apps/desktop/desktop_native/.gitignore
vendored
1
apps/desktop/desktop_native/.gitignore
vendored
@ -4,4 +4,3 @@ index.node
|
|||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
*.node
|
*.node
|
||||||
dist
|
|
||||||
|
254
apps/desktop/desktop_native/Cargo.lock
generated
254
apps/desktop/desktop_native/Cargo.lock
generated
@ -482,15 +482,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "deranged"
|
|
||||||
version = "0.3.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
|
|
||||||
dependencies = [
|
|
||||||
"powerfmt",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive-new"
|
name = "derive-new"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -512,14 +503,10 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"cbc",
|
"cbc",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"dirs",
|
|
||||||
"futures",
|
|
||||||
"gio",
|
"gio",
|
||||||
"interprocess",
|
|
||||||
"keytar",
|
"keytar",
|
||||||
"libc",
|
"libc",
|
||||||
"libsecret",
|
"libsecret",
|
||||||
"log",
|
|
||||||
"rand",
|
"rand",
|
||||||
"retry",
|
"retry",
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
@ -528,7 +515,6 @@ dependencies = [
|
|||||||
"sha2",
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
|
||||||
"typenum",
|
"typenum",
|
||||||
"widestring",
|
"widestring",
|
||||||
"windows",
|
"windows",
|
||||||
@ -545,22 +531,6 @@ dependencies = [
|
|||||||
"napi",
|
"napi",
|
||||||
"napi-build",
|
"napi-build",
|
||||||
"napi-derive",
|
"napi-derive",
|
||||||
"tokio",
|
|
||||||
"tokio-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "desktop_proxy"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"desktop_core",
|
|
||||||
"embed_plist",
|
|
||||||
"futures",
|
|
||||||
"log",
|
|
||||||
"simplelog",
|
|
||||||
"tokio",
|
|
||||||
"tokio-util",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -573,27 +543,6 @@ dependencies = [
|
|||||||
"crypto-common",
|
"crypto-common",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs"
|
|
||||||
version = "5.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
|
||||||
dependencies = [
|
|
||||||
"dirs-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs-sys"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"option-ext",
|
|
||||||
"redox_users",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dlib"
|
name = "dlib"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@ -603,24 +552,12 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "doctest-file"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "downcast-rs"
|
name = "downcast-rs"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "embed_plist"
|
|
||||||
version = "1.2.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "endi"
|
name = "endi"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -709,21 +646,6 @@ version = "1.0.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures"
|
|
||||||
version = "0.3.30"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
|
|
||||||
dependencies = [
|
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
|
||||||
"futures-executor",
|
|
||||||
"futures-io",
|
|
||||||
"futures-sink",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-channel"
|
name = "futures-channel"
|
||||||
version = "0.3.30"
|
version = "0.3.30"
|
||||||
@ -731,7 +653,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -799,7 +720,6 @@ version = "0.3.30"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
@ -994,27 +914,6 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "interprocess"
|
|
||||||
version = "2.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d2f4e4a06d42fab3e85ab1b419ad32b09eab58b901d40c57935ff92db3287a13"
|
|
||||||
dependencies = [
|
|
||||||
"doctest-file",
|
|
||||||
"futures-core",
|
|
||||||
"libc",
|
|
||||||
"recvmsg",
|
|
||||||
"tokio",
|
|
||||||
"widestring",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "itoa"
|
|
||||||
version = "1.0.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keytar"
|
name = "keytar"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@ -1052,16 +951,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libredox"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsecret"
|
name = "libsecret"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -1149,22 +1038,11 @@ dependencies = [
|
|||||||
"adler",
|
"adler",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mio"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi"
|
name = "napi"
|
||||||
version = "2.16.7"
|
version = "2.16.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "633e41b2b983cf7983134f0c50986ca524d0caf38a2c6fc893ea3fa2e26abb0c"
|
checksum = "dfc300228808a0e6aea5a58115c82889240bcf8dab16fc25ad675b33e454b368"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"ctor",
|
"ctor",
|
||||||
@ -1182,9 +1060,9 @@ checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "napi-derive"
|
name = "napi-derive"
|
||||||
version = "2.16.6"
|
version = "2.16.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "70a8a778fd367b13c64232e58632514b795514ece491ce136d96e976d34a3eb8"
|
checksum = "e0e034ddf6155192cf83f267ede763fe6c164dfa9971585436b16173718d94c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"convert_case",
|
"convert_case",
|
||||||
@ -1253,12 +1131,6 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-conv"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -1269,15 +1141,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_threads"
|
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc-sys"
|
name = "objc-sys"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -1392,12 +1255,6 @@ version = "1.19.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "option-ext"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ordered-stream"
|
name = "ordered-stream"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -1501,12 +1358,6 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "powerfmt"
|
|
||||||
version = "0.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
@ -1582,12 +1433,6 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "recvmsg"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.3"
|
version = "0.5.3"
|
||||||
@ -1597,17 +1442,6 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "redox_users"
|
|
||||||
version = "0.4.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
"libredox",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.6"
|
version = "1.10.6"
|
||||||
@ -1789,17 +1623,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "simplelog"
|
|
||||||
version = "0.12.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "16257adbfaef1ee58b1363bdc0664c9b8e1e30aed86049635fb5f147d065a9c0"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"termcolor",
|
|
||||||
"time",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@ -1815,16 +1638,6 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "socket2"
|
|
||||||
version = "0.5.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "static_assertions"
|
name = "static_assertions"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@ -1903,39 +1716,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time"
|
|
||||||
version = "0.3.36"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
|
||||||
dependencies = [
|
|
||||||
"deranged",
|
|
||||||
"itoa",
|
|
||||||
"libc",
|
|
||||||
"num-conv",
|
|
||||||
"num_threads",
|
|
||||||
"powerfmt",
|
|
||||||
"serde",
|
|
||||||
"time-core",
|
|
||||||
"time-macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time-core"
|
|
||||||
version = "0.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "time-macros"
|
|
||||||
version = "0.2.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"
|
|
||||||
dependencies = [
|
|
||||||
"num-conv",
|
|
||||||
"time-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.38.0"
|
version = "1.38.0"
|
||||||
@ -1944,13 +1724,9 @@ checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
"libc",
|
|
||||||
"mio",
|
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.48.0",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1964,19 +1740,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-util"
|
|
||||||
version = "0.7.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"pin-project-lite",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.19"
|
version = "0.8.19"
|
||||||
@ -2272,15 +2035,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.48.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.48.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["napi", "core", "proxy"]
|
members = ["napi", "core"]
|
||||||
|
@ -1,68 +0,0 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
const child_process = require("child_process");
|
|
||||||
const fs = require("fs");
|
|
||||||
const path = require("path");
|
|
||||||
const process = require("process");
|
|
||||||
|
|
||||||
let crossPlatform = process.argv.length > 2 && process.argv[2] === "cross-platform";
|
|
||||||
|
|
||||||
function buildNapiModule(target, release = true) {
|
|
||||||
const targetArg = target ? `--target ${target}` : "";
|
|
||||||
const releaseArg = release ? "--release" : "";
|
|
||||||
return child_process.execSync(`npm run build -- ${releaseArg} ${targetArg}`, { stdio: 'inherit', cwd: path.join(__dirname, "napi") });
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildProxyBin(target, release = true) {
|
|
||||||
const targetArg = target ? `--target ${target}` : "";
|
|
||||||
const releaseArg = release ? "--release" : "";
|
|
||||||
return child_process.execSync(`cargo build --bin desktop_proxy ${releaseArg} ${targetArg}`, {stdio: 'inherit', cwd: path.join(__dirname, "proxy")});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!crossPlatform) {
|
|
||||||
console.log("Building native modules in debug mode for the native architecture");
|
|
||||||
buildNapiModule(false, false);
|
|
||||||
buildProxyBin(false, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that targets contains pairs of [rust target, node arch]
|
|
||||||
// We do this to move the output binaries to a location that can
|
|
||||||
// be easily accessed from electron-builder using ${os} and ${arch}
|
|
||||||
let targets = [];
|
|
||||||
switch (process.platform) {
|
|
||||||
case "win32":
|
|
||||||
targets = [
|
|
||||||
["i686-pc-windows-msvc", 'ia32'],
|
|
||||||
["x86_64-pc-windows-msvc", 'x64'],
|
|
||||||
["aarch64-pc-windows-msvc", 'arm64']
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "darwin":
|
|
||||||
targets = [
|
|
||||||
["x86_64-apple-darwin", 'x64'],
|
|
||||||
["aarch64-apple-darwin", 'arm64']
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
targets = [
|
|
||||||
['x86_64-unknown-linux-musl', 'x64']
|
|
||||||
];
|
|
||||||
|
|
||||||
process.env["PKG_CONFIG_ALLOW_CROSS"] = "1";
|
|
||||||
process.env["PKG_CONFIG_ALL_STATIC"] = "1";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Cross building native modules for the targets: ", targets.map(([target, _]) => target).join(", "));
|
|
||||||
|
|
||||||
fs.mkdirSync(path.join(__dirname, "dist"), { recursive: true });
|
|
||||||
|
|
||||||
targets.forEach(([target, nodeArch]) => {
|
|
||||||
buildNapiModule(target);
|
|
||||||
buildProxyBin(target);
|
|
||||||
|
|
||||||
const ext = process.platform === "win32" ? ".exe" : "";
|
|
||||||
fs.copyFileSync(path.join(__dirname, "target", target, "release", `desktop_proxy${ext}`), path.join(__dirname, "dist", `desktop_proxy.${process.platform}-${nodeArch}${ext}`));
|
|
||||||
});
|
|
@ -6,21 +6,9 @@ version = "0.0.0"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["sys"]
|
default = []
|
||||||
manual_test = []
|
manual_test = []
|
||||||
|
|
||||||
sys = [
|
|
||||||
"dep:widestring",
|
|
||||||
"dep:windows",
|
|
||||||
"dep:core-foundation",
|
|
||||||
"dep:security-framework",
|
|
||||||
"dep:security-framework-sys",
|
|
||||||
"dep:gio",
|
|
||||||
"dep:libsecret",
|
|
||||||
"dep:zbus",
|
|
||||||
"dep:zbus_polkit",
|
|
||||||
]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aes = "=0.8.4"
|
aes = "=0.8.4"
|
||||||
anyhow = "=1.0.86"
|
anyhow = "=1.0.86"
|
||||||
@ -29,22 +17,17 @@ arboard = { version = "=3.4.0", default-features = false, features = [
|
|||||||
] }
|
] }
|
||||||
base64 = "=0.22.1"
|
base64 = "=0.22.1"
|
||||||
cbc = { version = "=0.1.2", features = ["alloc"] }
|
cbc = { version = "=0.1.2", features = ["alloc"] }
|
||||||
dirs = "=5.0.1"
|
|
||||||
futures = "=0.3.30"
|
|
||||||
interprocess = { version = "=2.2.1", features = ["tokio"] }
|
|
||||||
libc = "=0.2.155"
|
libc = "=0.2.155"
|
||||||
log = "=0.4.22"
|
|
||||||
rand = "=0.8.5"
|
rand = "=0.8.5"
|
||||||
retry = "=2.0.0"
|
retry = "=2.0.0"
|
||||||
scopeguard = "=1.2.0"
|
scopeguard = "=1.2.0"
|
||||||
sha2 = "=0.10.8"
|
sha2 = "=0.10.8"
|
||||||
thiserror = "=1.0.61"
|
thiserror = "=1.0.61"
|
||||||
tokio = { version = "=1.38.0", features = ["io-util", "sync", "macros"] }
|
tokio = { version = "=1.38.0", features = ["io-util", "sync", "macros"] }
|
||||||
tokio-util = "=0.7.11"
|
|
||||||
typenum = "=1.17.0"
|
typenum = "=1.17.0"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
widestring = { version = "=1.1.0", optional = true }
|
widestring = "=1.1.0"
|
||||||
windows = { version = "=0.57.0", features = [
|
windows = { version = "=0.57.0", features = [
|
||||||
"Foundation",
|
"Foundation",
|
||||||
"Security_Credentials_UI",
|
"Security_Credentials_UI",
|
||||||
@ -55,18 +38,18 @@ windows = { version = "=0.57.0", features = [
|
|||||||
"Win32_System_WinRT",
|
"Win32_System_WinRT",
|
||||||
"Win32_UI_Input_KeyboardAndMouse",
|
"Win32_UI_Input_KeyboardAndMouse",
|
||||||
"Win32_UI_WindowsAndMessaging",
|
"Win32_UI_WindowsAndMessaging",
|
||||||
], optional = true }
|
] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dev-dependencies]
|
[target.'cfg(windows)'.dev-dependencies]
|
||||||
keytar = "=0.1.6"
|
keytar = "=0.1.6"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
core-foundation = { version = "=0.9.4", optional = true }
|
core-foundation = "=0.9.4"
|
||||||
security-framework = { version = "=2.11.0", optional = true }
|
security-framework = "=2.11.0"
|
||||||
security-framework-sys = { version = "=2.11.0", optional = true }
|
security-framework-sys = "=2.11.0"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
gio = { version = "=0.19.5", optional = true }
|
gio = "=0.19.5"
|
||||||
libsecret = { version = "=0.5.0", optional = true }
|
libsecret = "=0.5.0"
|
||||||
zbus = { version = "=4.3.1", optional = true }
|
zbus = "=4.3.1"
|
||||||
zbus_polkit = { version = "=4.0.0", optional = true }
|
zbus_polkit = "=4.0.0"
|
||||||
|
@ -1,102 +0,0 @@
|
|||||||
use std::{
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use interprocess::local_socket::{
|
|
||||||
tokio::{prelude::*, Stream},
|
|
||||||
GenericFilePath, ToFsName,
|
|
||||||
};
|
|
||||||
use log::{error, info};
|
|
||||||
use tokio::{
|
|
||||||
io::{AsyncReadExt, AsyncWriteExt},
|
|
||||||
time::sleep,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::ipc::NATIVE_MESSAGING_BUFFER_SIZE;
|
|
||||||
|
|
||||||
pub async fn connect(
|
|
||||||
path: PathBuf,
|
|
||||||
send: tokio::sync::mpsc::Sender<String>,
|
|
||||||
mut recv: tokio::sync::mpsc::Receiver<String>,
|
|
||||||
) {
|
|
||||||
// Keep track of connection failures to make sure we don't leave the process as a zombie
|
|
||||||
let mut connection_failures = 0;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match connect_inner(&path, &send, &mut recv).await {
|
|
||||||
Ok(()) => return,
|
|
||||||
Err(e) => {
|
|
||||||
connection_failures += 1;
|
|
||||||
if connection_failures >= 20 {
|
|
||||||
error!("Failed to connect to IPC server after 20 attempts: {e}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
error!("Failed to connect to IPC server: {e}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(Duration::from_secs(5)).await;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn connect_inner(
|
|
||||||
path: &Path,
|
|
||||||
send: &tokio::sync::mpsc::Sender<String>,
|
|
||||||
recv: &mut tokio::sync::mpsc::Receiver<String>,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
info!("Attempting to connect to {}", path.display());
|
|
||||||
|
|
||||||
let name = path.as_os_str().to_fs_name::<GenericFilePath>()?;
|
|
||||||
let mut conn = Stream::connect(name).await?;
|
|
||||||
|
|
||||||
info!("Connected to {}", path.display());
|
|
||||||
|
|
||||||
// This `connected` and the latter `disconnected` messages are the only ones that
|
|
||||||
// are sent from the Rust IPC code and not just forwarded from the desktop app.
|
|
||||||
// As it's only two, we hardcode the JSON values to avoid pulling in a JSON library.
|
|
||||||
send.send("{\"command\":\"connected\"}".to_owned()).await?;
|
|
||||||
|
|
||||||
let mut buffer = vec![0; NATIVE_MESSAGING_BUFFER_SIZE];
|
|
||||||
|
|
||||||
// Listen to IPC messages
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
// Forward messages to the IPC server
|
|
||||||
msg = recv.recv() => {
|
|
||||||
match msg {
|
|
||||||
Some(msg) => {
|
|
||||||
conn.write_all(msg.as_bytes()).await?;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
info!("Client channel closed");
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Forward messages from the IPC server
|
|
||||||
res = conn.read(&mut buffer[..]) => {
|
|
||||||
match res {
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error reading from IPC server: {e}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Ok(0) => {
|
|
||||||
info!("Connection closed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Ok(n) => {
|
|
||||||
let message = String::from_utf8_lossy(&buffer[..n]).to_string();
|
|
||||||
send.send(message).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = send.send("{\"command\":\"disconnected\"}".to_owned()).await;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
pub mod client;
|
|
||||||
pub mod server;
|
|
||||||
|
|
||||||
/// The maximum size of a message that can be sent over IPC.
|
|
||||||
/// According to the documentation, the maximum size sent to the browser is 1MB.
|
|
||||||
/// While the maximum size sent from the browser to the native messaging host is 4GB.
|
|
||||||
///
|
|
||||||
/// Currently we are setting the maximum both ways to be 1MB.
|
|
||||||
///
|
|
||||||
/// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging#app_side
|
|
||||||
/// https://developer.chrome.com/docs/extensions/develop/concepts/native-messaging#native-messaging-host-protocol
|
|
||||||
pub const NATIVE_MESSAGING_BUFFER_SIZE: usize = 1024 * 1024;
|
|
||||||
|
|
||||||
/// The maximum number of messages that can be buffered in a channel.
|
|
||||||
/// This number is more or less arbitrary and can be adjusted as needed,
|
|
||||||
/// but ideally the messages should be processed as quickly as possible.
|
|
||||||
pub const MESSAGE_CHANNEL_BUFFER: usize = 32;
|
|
||||||
|
|
||||||
/// Resolve the path to the IPC socket.
|
|
||||||
pub fn path(name: &str) -> std::path::PathBuf {
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
|
||||||
// Use a unique IPC pipe //./pipe/xxxxxxxxxxxxxxxxx.app.bitwarden per user.
|
|
||||||
// Hashing prevents problems with reserved characters and file length limitations.
|
|
||||||
use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine};
|
|
||||||
use sha2::Digest;
|
|
||||||
let home = dirs::home_dir().unwrap();
|
|
||||||
let hash = sha2::Sha256::digest(home.as_os_str().as_encoded_bytes());
|
|
||||||
let hash_b64 = URL_SAFE_NO_PAD.encode(hash.as_slice());
|
|
||||||
|
|
||||||
format!(r"\\.\pipe\{hash_b64}.app.{name}").into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
let mut home = dirs::home_dir().unwrap();
|
|
||||||
|
|
||||||
// When running in an unsandboxed environment, path is: /Users/<user>/
|
|
||||||
// While running sandboxed, it's different: /Users/<user>/Library/Containers/com.bitwarden.desktop/Data
|
|
||||||
//
|
|
||||||
// We want to use App Groups in /Users/<user>/Library/Group Containers/LTZ2PFU5D6.com.bitwarden.desktop,
|
|
||||||
// so we need to remove all the components after the user.
|
|
||||||
// Note that we subtract 3 because the root directory is counted as a component (/, Users, <user>).
|
|
||||||
let num_components = home.components().count();
|
|
||||||
for _ in 0..num_components - 3 {
|
|
||||||
home.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
home.join(format!(
|
|
||||||
"Library/Group Containers/LTZ2PFU5D6.com.bitwarden.desktop/tmp/app.{name}"
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
// On Linux, we use the user's cache directory.
|
|
||||||
let home = dirs::cache_dir().unwrap();
|
|
||||||
let path_dir = home.join("com.bitwarden.desktop");
|
|
||||||
|
|
||||||
// The chache directory might not exist, so create it
|
|
||||||
let _ = std::fs::create_dir_all(&path_dir);
|
|
||||||
path_dir.join(format!("app.{name}"))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,232 +0,0 @@
|
|||||||
use std::{error::Error, path::Path, vec};
|
|
||||||
|
|
||||||
use futures::TryFutureExt;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use interprocess::local_socket::{tokio::prelude::*, GenericFilePath, ListenerOptions};
|
|
||||||
use log::{error, info};
|
|
||||||
use tokio::{
|
|
||||||
io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt},
|
|
||||||
sync::{broadcast, mpsc},
|
|
||||||
};
|
|
||||||
use tokio_util::sync::CancellationToken;
|
|
||||||
|
|
||||||
use super::{MESSAGE_CHANNEL_BUFFER, NATIVE_MESSAGING_BUFFER_SIZE};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Message {
|
|
||||||
pub client_id: u32,
|
|
||||||
pub kind: MessageType,
|
|
||||||
// This value should be Some for MessageType::Message and None for the rest
|
|
||||||
pub message: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum MessageType {
|
|
||||||
Connected,
|
|
||||||
Disconnected,
|
|
||||||
Message,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Server {
|
|
||||||
cancel_token: CancellationToken,
|
|
||||||
server_to_clients_send: broadcast::Sender<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
/// Create and start the IPC server without blocking.
|
|
||||||
///
|
|
||||||
/// # Parameters
|
|
||||||
///
|
|
||||||
/// - `name`: The endpoint name to listen on. This name uniquely identifies the IPC connection and must be the same for both the server and client.
|
|
||||||
/// - `client_to_server_send`: This [`mpsc::Sender<Message>`] will receive all the [`Message`]'s that the clients send to this server.
|
|
||||||
pub fn start(
|
|
||||||
path: &Path,
|
|
||||||
client_to_server_send: mpsc::Sender<Message>,
|
|
||||||
) -> Result<Self, Box<dyn Error>> {
|
|
||||||
// If the unix socket file already exists, we get an error when trying to bind to it. So we remove it first.
|
|
||||||
// Any processes that were using the old socket should remain connected to it but any new connections will use the new socket.
|
|
||||||
if !cfg!(windows) {
|
|
||||||
let _ = std::fs::remove_file(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
let name = path.as_os_str().to_fs_name::<GenericFilePath>()?;
|
|
||||||
let opts = ListenerOptions::new().name(name);
|
|
||||||
let listener = opts.create_tokio()?;
|
|
||||||
|
|
||||||
// This broadcast channel is used for sending messages to all connected clients, and so the sender
|
|
||||||
// will be stored in the server while the receiver will be cloned and passed to each client handler.
|
|
||||||
let (server_to_clients_send, server_to_clients_recv) =
|
|
||||||
broadcast::channel::<String>(MESSAGE_CHANNEL_BUFFER);
|
|
||||||
|
|
||||||
// This cancellation token allows us to cleanly stop the server and all the spawned
|
|
||||||
// tasks without having to wait on all the pending tasks finalizing first
|
|
||||||
let cancel_token = CancellationToken::new();
|
|
||||||
|
|
||||||
// Create the server and start listening for incoming connections
|
|
||||||
// in a separate task to avoid blocking the current task
|
|
||||||
let server = Server {
|
|
||||||
cancel_token: cancel_token.clone(),
|
|
||||||
server_to_clients_send,
|
|
||||||
};
|
|
||||||
tokio::spawn(listen_incoming(
|
|
||||||
listener,
|
|
||||||
client_to_server_send,
|
|
||||||
server_to_clients_recv,
|
|
||||||
cancel_token,
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(server)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a message over the IPC server to all the connected clients
|
|
||||||
///
|
|
||||||
/// # Returns
|
|
||||||
///
|
|
||||||
/// The number of clients that the message was sent to. Note that the number of messages
|
|
||||||
/// sent may be less than the number of connected clients if some clients disconnect while
|
|
||||||
/// the message is being sent.
|
|
||||||
pub fn send(&self, message: String) -> Result<usize> {
|
|
||||||
let sent = self.server_to_clients_send.send(message)?;
|
|
||||||
Ok(sent)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stop the IPC server.
|
|
||||||
pub fn stop(&self) {
|
|
||||||
self.cancel_token.cancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Server {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn listen_incoming(
|
|
||||||
listener: LocalSocketListener,
|
|
||||||
client_to_server_send: mpsc::Sender<Message>,
|
|
||||||
server_to_clients_recv: broadcast::Receiver<String>,
|
|
||||||
cancel_token: CancellationToken,
|
|
||||||
) {
|
|
||||||
// We use a simple incrementing ID for each client
|
|
||||||
let mut next_client_id = 1_u32;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
_ = cancel_token.cancelled() => {
|
|
||||||
info!("IPC server cancelled.");
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
|
|
||||||
// A new client connection has been established
|
|
||||||
msg = listener.accept() => {
|
|
||||||
match msg {
|
|
||||||
Ok(client_stream) => {
|
|
||||||
let client_id = next_client_id;
|
|
||||||
next_client_id += 1;
|
|
||||||
|
|
||||||
let future = handle_connection(
|
|
||||||
client_stream,
|
|
||||||
client_to_server_send.clone(),
|
|
||||||
// We resubscribe to the receiver here so this task can have it's own copy
|
|
||||||
// Note that this copy will only receive messages sent after this point,
|
|
||||||
// but that is okay, realistically we don't want any messages before we get a chance
|
|
||||||
// to send the connected message to the client, which is done inside [`handle_connection`]
|
|
||||||
server_to_clients_recv.resubscribe(),
|
|
||||||
cancel_token.clone(),
|
|
||||||
client_id
|
|
||||||
);
|
|
||||||
tokio::spawn(future.map_err(|e| {
|
|
||||||
error!("Error handling connection: {}", e)
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
error!("Error accepting connection: {}", e);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn handle_connection(
|
|
||||||
mut client_stream: impl AsyncRead + AsyncWrite + Unpin,
|
|
||||||
client_to_server_send: mpsc::Sender<Message>,
|
|
||||||
mut server_to_clients_recv: broadcast::Receiver<String>,
|
|
||||||
cancel_token: CancellationToken,
|
|
||||||
client_id: u32,
|
|
||||||
) -> Result<(), Box<dyn Error>> {
|
|
||||||
client_to_server_send
|
|
||||||
.send(Message {
|
|
||||||
client_id,
|
|
||||||
kind: MessageType::Connected,
|
|
||||||
message: None,
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mut buf = vec![0u8; NATIVE_MESSAGING_BUFFER_SIZE];
|
|
||||||
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
_ = cancel_token.cancelled() => {
|
|
||||||
info!("Client {client_id} cancelled.");
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Forward messages to the IPC clients
|
|
||||||
msg = server_to_clients_recv.recv() => {
|
|
||||||
match msg {
|
|
||||||
Ok(msg) => {
|
|
||||||
client_stream.write_all(msg.as_bytes()).await?;
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
info!("Error reading message: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Forwards messages from the IPC clients to the server
|
|
||||||
// Note that we also send connect and disconnect events so that
|
|
||||||
// the server can keep track of multiple clients
|
|
||||||
result = client_stream.read(&mut buf) => {
|
|
||||||
match result {
|
|
||||||
Err(e) => {
|
|
||||||
info!("Error reading from client {client_id}: {e}");
|
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
|
||||||
client_id,
|
|
||||||
kind: MessageType::Disconnected,
|
|
||||||
message: None,
|
|
||||||
}).await?;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Ok(0) => {
|
|
||||||
info!("Client {client_id} disconnected.");
|
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
|
||||||
client_id,
|
|
||||||
kind: MessageType::Disconnected,
|
|
||||||
message: None,
|
|
||||||
}).await?;
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
Ok(size) => {
|
|
||||||
let msg = std::str::from_utf8(&buf[..size])?;
|
|
||||||
|
|
||||||
client_to_server_send.send(Message {
|
|
||||||
client_id,
|
|
||||||
kind: MessageType::Message,
|
|
||||||
message: Some(msg.to_string()),
|
|
||||||
}).await?;
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,13 +1,7 @@
|
|||||||
#[cfg(feature = "sys")]
|
|
||||||
pub mod biometric;
|
pub mod biometric;
|
||||||
#[cfg(feature = "sys")]
|
|
||||||
pub mod clipboard;
|
pub mod clipboard;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod ipc;
|
|
||||||
#[cfg(feature = "sys")]
|
|
||||||
pub mod password;
|
pub mod password;
|
||||||
#[cfg(feature = "sys")]
|
|
||||||
pub mod process_isolation;
|
pub mod process_isolation;
|
||||||
#[cfg(feature = "sys")]
|
|
||||||
pub mod powermonitor;
|
pub mod powermonitor;
|
||||||
|
@ -16,10 +16,8 @@ manual_test = []
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "=1.0.86"
|
anyhow = "=1.0.86"
|
||||||
desktop_core = { path = "../core" }
|
desktop_core = { path = "../core" }
|
||||||
napi = { version = "=2.16.7", features = ["async"] }
|
napi = { version = "=2.16.6", features = ["async"] }
|
||||||
napi-derive = "=2.16.6"
|
napi-derive = "=2.16.5"
|
||||||
tokio = { version = "1.38.0" }
|
|
||||||
tokio-util = "0.7.11"
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
napi-build = "=2.1.3"
|
napi-build = "=2.1.3"
|
||||||
|
24
apps/desktop/desktop_native/napi/build.js
Normal file
24
apps/desktop/desktop_native/napi/build.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
|
const child_process = require("child_process");
|
||||||
|
const process = require("process");
|
||||||
|
|
||||||
|
let targets = [];
|
||||||
|
switch (process.platform) {
|
||||||
|
case "win32":
|
||||||
|
targets = ["i686-pc-windows-msvc", "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc"];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "darwin":
|
||||||
|
targets = ["x86_64-apple-darwin", "aarch64-apple-darwin"];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
targets = ['x86_64-unknown-linux-musl'];
|
||||||
|
process.env["PKG_CONFIG_ALLOW_CROSS"] = "1";
|
||||||
|
process.env["PKG_CONFIG_ALL_STATIC"] = "1";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
targets.forEach(target => {
|
||||||
|
child_process.execSync(`npm run build -- --target ${target}`, {stdio: 'inherit'});
|
||||||
|
});
|
30
apps/desktop/desktop_native/napi/index.d.ts
vendored
30
apps/desktop/desktop_native/napi/index.d.ts
vendored
@ -51,33 +51,3 @@ export namespace powermonitors {
|
|||||||
export function onLock(callback: (err: Error | null, ) => any): Promise<void>
|
export function onLock(callback: (err: Error | null, ) => any): Promise<void>
|
||||||
export function isLockMonitorAvailable(): Promise<boolean>
|
export function isLockMonitorAvailable(): Promise<boolean>
|
||||||
}
|
}
|
||||||
export namespace ipc {
|
|
||||||
export interface IpcMessage {
|
|
||||||
clientId: number
|
|
||||||
kind: IpcMessageType
|
|
||||||
message?: string
|
|
||||||
}
|
|
||||||
export const enum IpcMessageType {
|
|
||||||
Connected = 0,
|
|
||||||
Disconnected = 1,
|
|
||||||
Message = 2
|
|
||||||
}
|
|
||||||
export class IpcServer {
|
|
||||||
/**
|
|
||||||
* Create and start the IPC server without blocking.
|
|
||||||
*
|
|
||||||
* @param name The endpoint name to listen on. This name uniquely identifies the IPC connection and must be the same for both the server and client.
|
|
||||||
* @param callback This function will be called whenever a message is received from a client.
|
|
||||||
*/
|
|
||||||
static listen(name: string, callback: (error: null | Error, message: IpcMessage) => void): Promise<IpcServer>
|
|
||||||
/** Stop the IPC server. */
|
|
||||||
stop(): void
|
|
||||||
/**
|
|
||||||
* Send a message over the IPC server to all the connected clients
|
|
||||||
*
|
|
||||||
* @return The number of clients that the message was sent to. Note that the number of messages
|
|
||||||
* actually received may be less, as some clients could disconnect before receiving the message.
|
|
||||||
*/
|
|
||||||
send(message: string): number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -206,4 +206,10 @@ if (!nativeBinding) {
|
|||||||
throw new Error(`Failed to load native binding`)
|
throw new Error(`Failed to load native binding`)
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = nativeBinding
|
const { passwords, biometrics, clipboards, processisolations, powermonitors } = nativeBinding
|
||||||
|
|
||||||
|
module.exports.passwords = passwords
|
||||||
|
module.exports.biometrics = biometrics
|
||||||
|
module.exports.clipboards = clipboards
|
||||||
|
module.exports.processisolations = processisolations
|
||||||
|
module.exports.powermonitors = powermonitors
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "napi build --platform --js false",
|
"build": "napi build --release --platform --js false",
|
||||||
|
"build:debug": "napi build --platform --js false",
|
||||||
|
"build:cross-platform": "node build.js",
|
||||||
"test": "cargo test"
|
"test": "cargo test"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@ -189,103 +189,3 @@ pub mod powermonitors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub mod ipc {
|
|
||||||
use desktop_core::ipc::server::{Message, MessageType};
|
|
||||||
use napi::threadsafe_function::{
|
|
||||||
ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[napi(object)]
|
|
||||||
pub struct IpcMessage {
|
|
||||||
pub client_id: u32,
|
|
||||||
pub kind: IpcMessageType,
|
|
||||||
pub message: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Message> for IpcMessage {
|
|
||||||
fn from(message: Message) -> Self {
|
|
||||||
IpcMessage {
|
|
||||||
client_id: message.client_id,
|
|
||||||
kind: message.kind.into(),
|
|
||||||
message: message.message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub enum IpcMessageType {
|
|
||||||
Connected,
|
|
||||||
Disconnected,
|
|
||||||
Message,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MessageType> for IpcMessageType {
|
|
||||||
fn from(message_type: MessageType) -> Self {
|
|
||||||
match message_type {
|
|
||||||
MessageType::Connected => IpcMessageType::Connected,
|
|
||||||
MessageType::Disconnected => IpcMessageType::Disconnected,
|
|
||||||
MessageType::Message => IpcMessageType::Message,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
pub struct IpcServer {
|
|
||||||
server: desktop_core::ipc::server::Server,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[napi]
|
|
||||||
impl IpcServer {
|
|
||||||
/// Create and start the IPC server without blocking.
|
|
||||||
///
|
|
||||||
/// @param name The endpoint name to listen on. This name uniquely identifies the IPC connection and must be the same for both the server and client.
|
|
||||||
/// @param callback This function will be called whenever a message is received from a client.
|
|
||||||
#[napi(factory)]
|
|
||||||
pub async fn listen(
|
|
||||||
name: String,
|
|
||||||
#[napi(ts_arg_type = "(error: null | Error, message: IpcMessage) => void")]
|
|
||||||
callback: ThreadsafeFunction<IpcMessage, ErrorStrategy::CalleeHandled>,
|
|
||||||
) -> napi::Result<Self> {
|
|
||||||
let (send, mut recv) = tokio::sync::mpsc::channel::<Message>(32);
|
|
||||||
tokio::spawn(async move {
|
|
||||||
while let Some(message) = recv.recv().await {
|
|
||||||
callback.call(Ok(message.into()), ThreadsafeFunctionCallMode::NonBlocking);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let path = desktop_core::ipc::path(&name);
|
|
||||||
|
|
||||||
let server = desktop_core::ipc::server::Server::start(&path, send).map_err(|e| {
|
|
||||||
napi::Error::from_reason(format!(
|
|
||||||
"Error listening to server - Path: {path:?} - Error: {e} - {e:?}"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(IpcServer { server })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Stop the IPC server.
|
|
||||||
#[napi]
|
|
||||||
pub fn stop(&self) -> napi::Result<()> {
|
|
||||||
self.server.stop();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Send a message over the IPC server to all the connected clients
|
|
||||||
///
|
|
||||||
/// @return The number of clients that the message was sent to. Note that the number of messages
|
|
||||||
/// actually received may be less, as some clients could disconnect before receiving the message.
|
|
||||||
#[napi]
|
|
||||||
pub fn send(&self, message: String) -> napi::Result<u32> {
|
|
||||||
self.server
|
|
||||||
.send(message)
|
|
||||||
.map_err(|e| {
|
|
||||||
napi::Error::from_reason(format!("Error sending message - Error: {e} - {e:?}"))
|
|
||||||
})
|
|
||||||
// NAPI doesn't support u64 or usize, so we need to convert to u32
|
|
||||||
.map(|u| u32::try_from(u).unwrap_or_default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user