diff --git a/.eslintrc.json b/.eslintrc.json
index d6c329a94dc..44b4e09adf2 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -179,6 +179,23 @@
"rules": {
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/vault/*", "src/**/*"] }]
}
+ },
+ {
+ "files": ["apps/browser/src/**/*.ts", "libs/**/*.ts"],
+ "excludedFiles": "apps/browser/src/autofill/{content,notification}/**/*.ts",
+ "rules": {
+ "no-restricted-syntax": [
+ "error",
+ {
+ "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.messageListener` instead",
+ "selector": "CallExpression > [object.object.object.name='chrome'][object.object.property.name='runtime'][object.property.name='onMessage'][property.name='addListener']"
+ },
+ {
+ "message": "Using addListener in the browser popup produces a memory leak in Safari, use `BrowserApi.storageChangeListener` instead",
+ "selector": "CallExpression > [object.object.object.name='chrome'][object.object.property.name='storage'][object.property.name='onChanged'][property.name='addListener']"
+ }
+ ]
+ }
}
]
}
diff --git a/.github/workflows/release-cli.yml b/.github/workflows/release-cli.yml
index 73c0f24affd..04a8a04f4f5 100644
--- a/.github/workflows/release-cli.yml
+++ b/.github/workflows/release-cli.yml
@@ -157,8 +157,6 @@ jobs:
- name: Install Snap
uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1
- with:
- snapcraft_token: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
- name: Download artifacts
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
@@ -185,7 +183,7 @@ jobs:
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
run: |
- snapcraft push bw_${{ env._PKG_VERSION }}_amd64.snap --release stable
+ snapcraft upload bw_${{ env._PKG_VERSION }}_amd64.snap --release stable
snapcraft logout
choco:
diff --git a/.github/workflows/release-desktop.yml b/.github/workflows/release-desktop.yml
index 28314e8e9c1..b9ffa80e512 100644
--- a/.github/workflows/release-desktop.yml
+++ b/.github/workflows/release-desktop.yml
@@ -270,8 +270,6 @@ jobs:
- name: Install Snap
uses: samuelmeuli/action-snapcraft@d33c176a9b784876d966f80fb1b461808edc0641 # v2.1.1
- env:
- SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
- name: Setup
run: mkdir dist
@@ -302,8 +300,8 @@ jobs:
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
run: |
- /snap/bin/snapcraft upload bitwarden_${{ env._PKG_VERSION }}_amd64.snap --release stable
- /snap/bin/snapcraft logout
+ snapcraft upload bitwarden_${{ env._PKG_VERSION }}_amd64.snap --release stable
+ snapcraft logout
working-directory: apps/desktop/dist
choco:
diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json
index ba917a9e681..c3ba5c4a950 100644
--- a/apps/browser/src/_locales/ar/messages.json
+++ b/apps/browser/src/_locales/ar/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "التعبئة التلقائية"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "إنشاء كلمة مرور (تم النسخ)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "لا توجد تسجيلات دخول مطابقة."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "افتح خزنتك"
},
diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json
index b784592a3b0..483dc2c14f1 100644
--- a/apps/browser/src/_locales/az/messages.json
+++ b/apps/browser/src/_locales/az/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Avto-doldurma"
},
+ "autoFillLogin": {
+ "message": "Giriş avto-doldurma"
+ },
+ "autoFillCard": {
+ "message": "Kart avto-doldurma"
+ },
+ "autoFillIdentity": {
+ "message": "Kimlik avto-doldurma"
+ },
"generatePasswordCopied": {
"message": "Parol yarat (kopyalandı)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Uyğun gələn hesab yoxdur."
},
+ "noCards": {
+ "message": "Kart yoxdur"
+ },
+ "noIdentities": {
+ "message": "Kimlik yoxdur"
+ },
+ "addLoginMenu": {
+ "message": "Giriş əlavə et"
+ },
+ "addCardMenu": {
+ "message": "Kart əlavə et"
+ },
+ "addIdentityMenu": {
+ "message": "Kimlik əlavə et"
+ },
"unlockVaultMenu": {
"message": "Anbarın kilidini açın"
},
@@ -671,7 +695,7 @@
"description": "'Solarized' is a noun and the name of a color scheme. It should not be translated."
},
"exportVault": {
- "message": "Anbarı ixrac et"
+ "message": "Anbarı xaricə köçür"
},
"fileFormat": {
"message": "Fayl formatı"
@@ -681,19 +705,19 @@
"description": "WARNING (should stay in capitalized letters if the language permits)"
},
"confirmVaultExport": {
- "message": "Anbarın ixracını təsdiqləyin"
+ "message": "Anbarın xaricə köçürülməsini təsdiqləyin"
},
"exportWarningDesc": {
- "message": "Bu ixrac faylındakı anbar verilənləriniz şifrələnməmiş formatdadır. İxrac edilən faylı, güvənli olmayan kanallar üzərində saxlamamalı və ya göndərməməlisiniz (e-poçt kimi). Bu faylı işiniz bitdikdən sonra dərhal silin."
+ "message": "Xaricə köçürdüyünüz bu fayldakı datanız şifrələnməmiş formatdadır. Bu faylı güvənli olmayan kanallar (e-poçt kimi) üzərində saxlamamalı və ya göndərməməlisiniz. İşiniz bitdikdən sonra faylı dərhal silin."
},
"encExportKeyWarningDesc": {
- "message": "Bu ixrac faylı, hesabınızın şifrələmə açarını istifadə edərək verilənlərinizi şifrələyir. Hesabınızın şifrələmə açarını döndərsəniz, bu ixrac faylının şifrəsini aça bilməyəcəyiniz üçün yenidən ixrac etməli olacaqsınız."
+ "message": "Xaricə köçürdüyünüz bu fayldakı data, hesabınızın şifrələmə açarı istifadə edilərək şifrələnir. Hesabınızın şifrələmə açarını dəyişdirsəniz, bu faylın şifrəsini aça bilməyəcəksiniz və onu yenidən xaricə köçürməli olacaqsınız."
},
"encExportAccountWarningDesc": {
"message": "Hesab şifrələmə açarları, hər Bitwarden istifadəçi hesabı üçün unikaldır, buna görə də şifrələnmiş bir ixracı, fərqli bir hesaba idxal edə bilməzsiniz."
},
"exportMasterPassword": {
- "message": "Anbar verilənlərinizi ixrac etmək üçün ana parolunuzu daxil edin."
+ "message": "Anbar datanızı xaricə köçürmək üçün ana parolunuzu daxil edin."
},
"shared": {
"message": "Paylaşılan"
@@ -799,7 +823,7 @@
"message": "YubiKey və Duo kimi mülkiyyətçi iki addımlı giriş seçimləri."
},
"ppremiumSignUpReports": {
- "message": "Anbarınızın təhlükəsiyini təmin etmək üçün parol gigiyenası, hesab sağlamlığı və verilənlərin pozulması hesabatları."
+ "message": "Anbarınızın təhlükəsizliyini təmin etmək üçün parol gigiyenası, hesab sağlamlığı və data pozuntusu hesabatları."
},
"ppremiumSignUpTotp": {
"message": "Anbarınızdakı hesablar üçün TOTP təsdiqləmə kodu (2FA) yaradıcısı."
@@ -2408,18 +2432,18 @@
"description": "Toggling an expand/collapse state."
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "Domen ləqəbi"
},
"passwordRepromptDisabledAutofillOnPageLoad": {
- "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.",
+ "message": "\"Ana parolu təkrar soruş\" özəlliyi olan elementlər səhifə yüklənəndə avto-doldurulmur. \"Səhifə yüklənəndə avto-doldurma\" özəlliyi söndürülüb.",
"description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load."
},
"autofillOnPageLoadSetToDefault": {
- "message": "Auto-fill on page load set to use default setting.",
+ "message": "\"Səhifə yüklənəndə avto-doldurma\" özəlliyi ilkin tənzimləməni istifadə etmək üzrə tənzimləndi.",
"description": "Toast message for informing the user that auto-fill on page load has been set to the default setting."
},
"turnOffMasterPasswordPromptToEditField": {
- "message": "Turn off master password re-prompt to edit this field",
+ "message": "Bu sahəyə düzəliş etmək üçün \"Ana parolu təkrar soruş\"u söndürün",
"description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item."
}
}
diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json
index e941d525936..d0c1bac2bb7 100644
--- a/apps/browser/src/_locales/be/messages.json
+++ b/apps/browser/src/_locales/be/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Аўтазапаўненне"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Генерыраваць пароль (з капіяваннем)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Няма адпаведных лагінаў."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Разблакіраваць сховішча"
},
diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json
index 08451607d2b..75d86dd2b41 100644
--- a/apps/browser/src/_locales/bg/messages.json
+++ b/apps/browser/src/_locales/bg/messages.json
@@ -14,7 +14,7 @@
"message": "Впишете се или създайте нов абонамент, за да достъпите защитен трезор."
},
"createAccount": {
- "message": "Създаване на абонамент"
+ "message": "Създаване на акаунт"
},
"login": {
"message": "Вписване"
@@ -83,7 +83,7 @@
"message": "Копиране на потребителското име"
},
"copyNumber": {
- "message": "Копиране на номера"
+ "message": "Копиране на но̀мера"
},
"copySecurityCode": {
"message": "Копиране на кода за сигурност"
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Автоматично дописване"
},
+ "autoFillLogin": {
+ "message": "Авт. попълване на данни за вход"
+ },
+ "autoFillCard": {
+ "message": "Самопопълваща се карта"
+ },
+ "autoFillIdentity": {
+ "message": "Самопопълваща се самоличност"
+ },
"generatePasswordCopied": {
"message": "Генериране на парола (копирана)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Няма съвпадащи записи."
},
+ "noCards": {
+ "message": "Няма карти"
+ },
+ "noIdentities": {
+ "message": "Няма самоличности"
+ },
+ "addLoginMenu": {
+ "message": "Добавяне на запис за вход"
+ },
+ "addCardMenu": {
+ "message": "Добавяне на карта"
+ },
+ "addIdentityMenu": {
+ "message": "Добавяне на самоличност"
+ },
"unlockVaultMenu": {
"message": "Отключете трезора си"
},
@@ -233,7 +257,7 @@
"message": "Избор"
},
"generatePassword": {
- "message": "Генериране на парола"
+ "message": "Нова парола"
},
"regeneratePassword": {
"message": "Регенериране на паролата"
@@ -467,7 +491,7 @@
"message": "Грешен код за потвърждаване"
},
"valueCopied": {
- "message": "$VALUE$ — копирано",
+ "message": "Копирано е $VALUE$",
"description": "Value has been copied to the clipboard.",
"placeholders": {
"value": {
@@ -537,7 +561,7 @@
"message": "Копирана парола"
},
"uri": {
- "message": "Адрес"
+ "message": "Унифициран идентификатор на ресурс"
},
"uriPosition": {
"message": "Адрес $POSITION$",
@@ -550,7 +574,7 @@
}
},
"newUri": {
- "message": "Нов адрес"
+ "message": "Нов унифициран идентификатор на ресурс"
},
"addedItem": {
"message": "Елементът е добавен"
@@ -631,7 +655,7 @@
"message": "Да се обнови ли паролата в Bitwarden?"
},
"notificationChangeSave": {
- "message": "Да, нека се обнови сега"
+ "message": "Осъвременяване"
},
"notificationUnlockDesc": {
"message": "Отключете трезора си в Битуорден, за да завършите заявката за автоматично попълване."
@@ -684,7 +708,7 @@
"message": "Потвърждаване на изнасянето на трезора"
},
"exportWarningDesc": {
- "message": "Данните от трезора ви ще се изнесат в незащитен формат. Не го пращайте по незащитени канали като е-поща. Изтрийте файла незабавно след като свършите работата си с него."
+ "message": "Този износ съдържа данни на трезора ви в некриптиран формат. Не трябва да съхранявате или изпращате износния файл през незащитени канали (като имейл). Изтрийте файла моментално след като свършите работата си с него."
},
"encExportKeyWarningDesc": {
"message": "При изнасяне данните се шифрират с ключа ви. Ако го смените, ще трябва наново да ги изнесете, защото няма да може да дешифрирате настоящия файл."
@@ -699,10 +723,10 @@
"message": "Споделено"
},
"learnOrg": {
- "message": "Разберете повече за организациите"
+ "message": "Научете за организациите"
},
"learnOrgConfirmation": {
- "message": "Битуорден позволява да споделяте части от трезора си чрез използването на организация. Искате ли да научите повече от сайта bitwarden.com?"
+ "message": "Битуорден позволява да споделяте елементи от трезора си а други, използвайки организация. Бихте ли посетили сайта bitwarden.com, за да научите повече?"
},
"moveToOrganization": {
"message": "Преместване в организация"
@@ -781,7 +805,7 @@
"message": "Управление на абонамента"
},
"premiumManageAlert": {
- "message": "Можете да управлявате абонамента си през сайта bitwarden.com. Искате ли да го посетите сега?"
+ "message": "Може да управлявате членството си в мрежата на трезора в bitwarden.com. Искате ли да посетите уебсайта сега?"
},
"premiumRefresh": {
"message": "Опресняване на абонамента"
@@ -901,7 +925,7 @@
"message": "Регистрацията е защитена с двустепенно удостоверяване, но никой от настроените доставчици на удостоверяване не се поддържа от този браузър."
},
"noTwoStepProviders2": {
- "message": "Пробвайте с поддържан уеб браузър (като Chrome или Firefox) и други доставчици на удостоверяване, които се поддържат от браузърите (като специални програми за удостоверяване)."
+ "message": "Употребявайте поддържан браузър (като Chrome, Firefox) и/или добавете други доставчици на удостоверяване, които се поддържат по-добре от браузърите (като специални програми за удостоверяване)."
},
"twoStepOptions": {
"message": "Настройки на двустепенното удостоверяване"
@@ -920,10 +944,10 @@
"description": "'Authy' and 'Google Authenticator' are product names and should not be translated."
},
"yubiKeyTitle": {
- "message": "Устройство YubiKey OTP"
+ "message": "Ключ за сигурност YubiKey OTP"
},
"yubiKeyDesc": {
- "message": "Използвайте устройство на YubiKey, за да влезете в абонамента си. Поддържат се моделите YubiKey 4, 4 Nano, 4C и NEO."
+ "message": "Използвайте ключа за сигурност YubiKey, за да влезете в акаунта си. Работи с устройствата YubiKey 4, 4 Nano, 4C и NEO."
},
"duoDesc": {
"message": "Удостоверяване чрез Duo Security, с ползване на приложението Duo Mobile, SMS, телефонен разговор или устройство U2F.",
@@ -2096,7 +2120,7 @@
"message": "собствен хостинг"
},
"thirdParty": {
- "message": "Third-party"
+ "message": "Трета страна"
},
"thirdPartyServerMessage": {
"message": "Connected to third-party server implementation, $SERVERNAME$. Please verify bugs using the official server, or report them to the third-party server.",
diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json
index edee2852116..f8c5fb8c85b 100644
--- a/apps/browser/src/_locales/bn/messages.json
+++ b/apps/browser/src/_locales/bn/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "স্বতঃপূরণ"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "পাসওয়ার্ড তৈরি করুন (অনুলিপিকৃত)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "কোনও মিলত লগইন নেই।"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json
index e984a88b7bc..d5d1bbb16a6 100644
--- a/apps/browser/src/_locales/bs/messages.json
+++ b/apps/browser/src/_locales/bs/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json
index 7839cceebcb..af85e586c80 100644
--- a/apps/browser/src/_locales/ca/messages.json
+++ b/apps/browser/src/_locales/ca/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Emplenament automàtic"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Genera contrasenya (copiada)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No hi ha inicis de sessió coincidents."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "1. Desbloquegeu la caixa forta."
},
diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json
index 71446db9f2c..e9b3bf997cd 100644
--- a/apps/browser/src/_locales/cs/messages.json
+++ b/apps/browser/src/_locales/cs/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automatické vyplňování"
},
+ "autoFillLogin": {
+ "message": "Automaticky vyplnit přihlášení"
+ },
+ "autoFillCard": {
+ "message": "Automaticky vyplnit kartu"
+ },
+ "autoFillIdentity": {
+ "message": "Automaticky vyplnit identitu"
+ },
"generatePasswordCopied": {
"message": "Vygenerovat heslo a zkopírovat do schránky"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Žádné odpovídající přihlašovací údaje"
},
+ "noCards": {
+ "message": "Žádné karty"
+ },
+ "noIdentities": {
+ "message": "Žádné identity"
+ },
+ "addLoginMenu": {
+ "message": "Přidat přihlašovací údaje"
+ },
+ "addCardMenu": {
+ "message": "Přidat kartu"
+ },
+ "addIdentityMenu": {
+ "message": "Přidat identitu"
+ },
"unlockVaultMenu": {
"message": "Odemknout Váš trezor"
},
diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json
index 7292370f533..ff3ccc684f7 100644
--- a/apps/browser/src/_locales/cy/messages.json
+++ b/apps/browser/src/_locales/cy/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Llenwi'n awtomatig"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Cynhyrchu cyfrinair (wedi'i gopïo)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Datgloi'ch cell"
},
diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json
index 1bc0ed79e5a..5dd437827f3 100644
--- a/apps/browser/src/_locales/da/messages.json
+++ b/apps/browser/src/_locales/da/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-udfyld"
},
+ "autoFillLogin": {
+ "message": "Autoudfyld login"
+ },
+ "autoFillCard": {
+ "message": "Autoudfyld kort"
+ },
+ "autoFillIdentity": {
+ "message": "Autoudfyld identitet"
+ },
"generatePasswordCopied": {
"message": "Generér adgangskode (kopieret)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Ingen matchende logins"
},
+ "noCards": {
+ "message": "Ingen kort"
+ },
+ "noIdentities": {
+ "message": "Ingen identiteter"
+ },
+ "addLoginMenu": {
+ "message": "Tilføj login"
+ },
+ "addCardMenu": {
+ "message": "Tilføj kort"
+ },
+ "addIdentityMenu": {
+ "message": "Tilføj identitet"
+ },
"unlockVaultMenu": {
"message": "Lås din boks op"
},
diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json
index 443d4294cd3..3edd462918f 100644
--- a/apps/browser/src/_locales/de/messages.json
+++ b/apps/browser/src/_locales/de/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-Ausfüllen"
},
+ "autoFillLogin": {
+ "message": "Zugangsdaten automatisch ausfüllen"
+ },
+ "autoFillCard": {
+ "message": "Karte automatisch ausfüllen"
+ },
+ "autoFillIdentity": {
+ "message": "Identität automatisch ausfüllen"
+ },
"generatePasswordCopied": {
"message": "Passwort generieren (kopiert)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Keine passenden Zugangsdaten"
},
+ "noCards": {
+ "message": "Keine Karten"
+ },
+ "noIdentities": {
+ "message": "Keine Identitäten"
+ },
+ "addLoginMenu": {
+ "message": "Zugangsdaten hinzufügen"
+ },
+ "addCardMenu": {
+ "message": "Karte hinzufügen"
+ },
+ "addIdentityMenu": {
+ "message": "Identität hinzufügen"
+ },
"unlockVaultMenu": {
"message": "Entsperre deinen Tresor"
},
diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json
index c0b349f8aff..2692a89b7db 100644
--- a/apps/browser/src/_locales/el/messages.json
+++ b/apps/browser/src/_locales/el/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Αυτόματη συμπλήρωση"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Δημιουργία Κωδικού (αντιγράφηκε)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Δεν υπάρχουν αντιστοιχίσεις σύνδεσης."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Ξεκλειδώστε το vault σας"
},
diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json
index fbe9e4fc31e..4e1057956fa 100644
--- a/apps/browser/src/_locales/en_GB/messages.json
+++ b/apps/browser/src/_locales/en_GB/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json
index 0ae234fbece..32dd196f2ae 100644
--- a/apps/browser/src/_locales/en_IN/messages.json
+++ b/apps/browser/src/_locales/en_IN/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json
index 15f8b4fbefa..b81a05c9a4b 100644
--- a/apps/browser/src/_locales/es/messages.json
+++ b/apps/browser/src/_locales/es/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Autorellenar"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generar contraseña (copiada)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Sin entradas coincidentes."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Desbloquea la caja fuerte"
},
diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json
index b799c3a63a3..4fe20767c0e 100644
--- a/apps/browser/src/_locales/et/messages.json
+++ b/apps/browser/src/_locales/et/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automaatne täitmine"
},
+ "autoFillLogin": {
+ "message": "Täida konto andmed"
+ },
+ "autoFillCard": {
+ "message": "Täida kaardi andmed"
+ },
+ "autoFillIdentity": {
+ "message": "Täida identiteet"
+ },
"generatePasswordCopied": {
"message": "Genereeri parool (kopeeritakse)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Sobivaid kontoandmeid ei leitud."
},
+ "noCards": {
+ "message": "Kaardid puuduvad"
+ },
+ "noIdentities": {
+ "message": "Identiteedid puuduvad"
+ },
+ "addLoginMenu": {
+ "message": "Lisa konto andmed"
+ },
+ "addCardMenu": {
+ "message": "Lisa kaart"
+ },
+ "addIdentityMenu": {
+ "message": "Lisa identiteet"
+ },
"unlockVaultMenu": {
"message": "Lukusta hoidla lahti"
},
diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json
index 6290304cda6..291a687f8b4 100644
--- a/apps/browser/src/_locales/eu/messages.json
+++ b/apps/browser/src/_locales/eu/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-betetzea"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Sortu pasahitza (kopiatuta)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Bat datozen saio-hasierarik gabe"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Desblokeatu kutxa gotorra"
},
diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json
index 250ca3631a5..c366c3a00b6 100644
--- a/apps/browser/src/_locales/fa/messages.json
+++ b/apps/browser/src/_locales/fa/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "پر کردن خودکار"
},
+ "autoFillLogin": {
+ "message": "پر کردن خودکار ورود"
+ },
+ "autoFillCard": {
+ "message": "پر کردن خودکار کارت"
+ },
+ "autoFillIdentity": {
+ "message": "پر کردن خودکار هویت"
+ },
"generatePasswordCopied": {
"message": "ساخت کلمه عبور (کپی شد)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "ورودیها منتطبق نیست"
},
+ "noCards": {
+ "message": "کارتی وجود ندارد"
+ },
+ "noIdentities": {
+ "message": "هویتی وجود ندارد"
+ },
+ "addLoginMenu": {
+ "message": "افزودن ورود"
+ },
+ "addCardMenu": {
+ "message": "افزودن کارت"
+ },
+ "addIdentityMenu": {
+ "message": "افزودن هویت"
+ },
"unlockVaultMenu": {
"message": "قفل گاوصندوق خود را باز کنید"
},
@@ -637,7 +661,7 @@
"message": "برای پر کردن خودکار گاوصندوق Bitwarden خود را باز کنید."
},
"notificationUnlock": {
- "message": "بازگشایی"
+ "message": "باز کردن قفل"
},
"enableContextMenuItem": {
"message": "نمایش گزینههای منوی زمینه"
@@ -702,7 +726,7 @@
"message": "درباره سازمانها اطلاعات کسب کنید"
},
"learnOrgConfirmation": {
- "message": "Bitwarden به شما اجازه میدهد با استفاده از سازماندهی، موارد گاوصندوق خود را با دیگران به اشتراک بگذارید. آیا مایل به بازدید از وب سایت bitwarden.com برای کسب اطلاعات بیشتر هستید؟"
+ "message": "Bitwarden به شما اجازه میدهد با استفاده از سازمان، موارد گاوصندوق خود را با دیگران به اشتراک بگذارید. آیا مایل به بازدید از وب سایت bitwarden.com برای کسب اطلاعات بیشتر هستید؟"
},
"moveToOrganization": {
"message": "انتقال به سازمان"
@@ -772,7 +796,7 @@
"message": "ویژگی موجود نیست"
},
"encryptionKeyMigrationRequired": {
- "message": "Encryption key migration required. Please login through the web vault to update your encryption key."
+ "message": "انتقال کلید رمزگذاری مورد نیاز است. لطفاً از طریق گاوصندوق وب وارد شوید تا کلید رمزگذاری خود را به روز کنید."
},
"premiumMembership": {
"message": "عضویت پرمیوم"
@@ -1606,10 +1630,10 @@
"message": "بیومتریک مرورگر در این دستگاه پشتیبانی نمیشود."
},
"biometricsFailedTitle": {
- "message": "زیستسنجی ناتمام ماند"
+ "message": "زیستسنجی ناموفق بود"
},
"biometricsFailedDesc": {
- "message": "زیستسنجی نمی تواند انجام شود، استفاده از کلمه عبور اصلی یا خروج را در نظر بگیرید. اگر این مشکل ادامه یافت لطفا با پشتیبانی Bitwarden تماس بگیرید."
+ "message": "زیستسنجی نمیتواند انجام شود، استفاده از کلمه عبور اصلی یا خروج را در نظر بگیرید. اگر این مشکل ادامه یافت لطفاً با پشتیبانی Bitwarden تماس بگیرید."
},
"nativeMessaginPermissionErrorTitle": {
"message": "مجوز ارائه نشده است"
@@ -1992,7 +2016,7 @@
"message": "برون ریزی گاوصندوق شخصی"
},
"exportingIndividualVaultDescription": {
- "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.",
+ "message": "فقط موارد شخصی گاوصندوق مرتبط با $EMAIL$ برون ریزی خواهند شد. موارد گاوصندوق سازمان شامل نخواهد شد. فقط اطلاعات مورد گاوصندوق برون ریزی خواهد شد و شامل تاریخچه کلمه عبور مرتبط یا پیوست نمیشود.",
"placeholders": {
"email": {
"content": "$1",
@@ -2234,28 +2258,28 @@
}
},
"loggingInOn": {
- "message": "ورود به عنوان"
+ "message": "ورود با"
},
"opensInANewWindow": {
"message": "در پنجره جدید باز میشود"
},
"deviceApprovalRequired": {
- "message": "تایید دستگاه لازم است. یک روش تایید برگزینید:"
+ "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:"
},
"rememberThisDevice": {
"message": "این دستگاه را به خاطر بسپار"
},
"uncheckIfPublicDevice": {
- "message": "بردارید اگر از دستگاه عمومی استفاده میکنید"
+ "message": "اگر از دستگاه عمومی استفاده میکنید علامت را بردارید"
},
"approveFromYourOtherDevice": {
- "message": "تایید با دستگاه دیگرتان"
+ "message": "تأیید با دستگاه دیگرتان"
},
"requestAdminApproval": {
- "message": "درخواست تایید مدیر"
+ "message": "درخواست تأیید مدیر"
},
"approveWithMasterPassword": {
- "message": "تایید با کلمه عبور اصلی"
+ "message": "تأیید با کلمه عبور اصلی"
},
"ssoIdentifierRequired": {
"message": "شناسه سازمان SSO مورد نیاز است."
@@ -2283,37 +2307,37 @@
"message": "حساب کاربری با موفقیت ایجاد شد!"
},
"adminApprovalRequested": {
- "message": "تایید مدیر در خواست شد"
+ "message": "تأیید مدیر درخواست شد"
},
"adminApprovalRequestSentToAdmins": {
"message": "درخواست شما به مدیرتان فرستاده شد."
},
"youWillBeNotifiedOnceApproved": {
- "message": "به محض تایید مطلع خواهید شد."
+ "message": "به محض تأیید مطلع خواهید شد."
},
"troubleLoggingIn": {
"message": "در ورود مشکلی دارید؟"
},
"loginApproved": {
- "message": "ورود تایید شد"
+ "message": "ورود تأیید شد"
},
"userEmailMissing": {
- "message": "رایانامه کاربر کم است"
+ "message": "ایمیل کاربر وجود ندارد"
},
"deviceTrusted": {
"message": "دستگاه مورد اعتماد است"
},
"inputRequired": {
- "message": "ورودی مورد نیاز است."
+ "message": "ورودی ضروری است."
},
"required": {
- "message": "الزامی"
+ "message": "ضروری"
},
"search": {
"message": "جستجو"
},
"inputMinLength": {
- "message": "ورودی باید حداقل $COUNT$ نشانه داشته باشد.",
+ "message": "ورودی باید حداقل $COUNT$ کاراکتر داشته باشد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2322,7 +2346,7 @@
}
},
"inputMaxLength": {
- "message": "اندازه ورودی نباید بیش از $COUNT$ نشانه باشد.",
+ "message": "طول ورودی نباید بیش از $COUNT$ کاراکتر باشد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2331,7 +2355,7 @@
}
},
"inputForbiddenCharacters": {
- "message": "نشانه های زیر مجاز نیستند: $CHARACTERS$",
+ "message": "کاراکترهای زیر مجاز نیستند: $CHARACTERS$",
"placeholders": {
"characters": {
"content": "$1",
@@ -2340,7 +2364,7 @@
}
},
"inputMinValue": {
- "message": "مقدار ورودی باید دست کم $MIN$ باشد.",
+ "message": "مقدار ورودی باید حداقل $MIN$ باشد.",
"placeholders": {
"min": {
"content": "$1",
@@ -2349,7 +2373,7 @@
}
},
"inputMaxValue": {
- "message": "مقدار ورودی نباید بیش از $MAX$ باشد.",
+ "message": "مقدار ورودی نباید از $MAX$ تجاوز کند.",
"placeholders": {
"max": {
"content": "$1",
@@ -2358,17 +2382,17 @@
}
},
"multipleInputEmails": {
- "message": "یک یا چند رایانامه نامعتبر است"
+ "message": "یک یا چند ایمیل نامعتبر است"
},
"inputTrimValidator": {
- "message": "ورودی نباید فقط فاصله باشد.",
+ "message": "ورودی نباید فقط حاوی فضای خالی باشد.",
"description": "Notification to inform the user that a form's input can't contain only whitespace."
},
"inputEmail": {
- "message": "ورودی یک نشانی رایانامه نیست."
+ "message": "ورودی یک نشانی ایمیل نیست."
},
"fieldsNeedAttention": {
- "message": "بخش (های) $COUNT$ در بالا نیازمند توجه شما است.",
+ "message": "فیلد $COUNT$ در بالا به توجه شما نیاز دارد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2380,16 +2404,16 @@
"message": "-- انتخاب --"
},
"multiSelectPlaceholder": {
- "message": "-- برای گزینش چیزی بنویسید --"
+ "message": "-- برای فیلتر تایپ کنید --"
},
"multiSelectLoading": {
"message": "در حال بازیابی گزینهها..."
},
"multiSelectNotFound": {
- "message": "موردی پیدا نشد"
+ "message": "موردی یافت نشد"
},
"multiSelectClearAll": {
- "message": "پاک کردن همه"
+ "message": "پاککردن همه"
},
"plusNMore": {
"message": "+ $QUANTITY$ بیشتر",
@@ -2401,25 +2425,25 @@
}
},
"submenu": {
- "message": "زیرفهرست"
+ "message": "زیرمنو"
},
"toggleCollapse": {
- "message": "باز و بسته کردن",
+ "message": "دکمه بستن",
"description": "Toggling an expand/collapse state."
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "دامنه مستعار"
},
"passwordRepromptDisabledAutofillOnPageLoad": {
- "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.",
+ "message": "موارد با درخواست مجدد کلمه عبور اصلی را نمیتوان در بارگذاری صفحه بهصورت خودکار پر کرد. پر کردن خودکار در بارگیری صفحه خاموش شد.",
"description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load."
},
"autofillOnPageLoadSetToDefault": {
- "message": "Auto-fill on page load set to use default setting.",
+ "message": "پر کردن خودکار در بارگیری صفحه برای استفاده از تنظیمات پیشفرض تنظیم شده است.",
"description": "Toast message for informing the user that auto-fill on page load has been set to the default setting."
},
"turnOffMasterPasswordPromptToEditField": {
- "message": "Turn off master password re-prompt to edit this field",
+ "message": "برای ویرایش این فیلد، درخواست مجدد کلمه عبور اصلی را خاموش کنید",
"description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item."
}
}
diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json
index 3a829d4783d..daaa9a89258 100644
--- a/apps/browser/src/_locales/fi/messages.json
+++ b/apps/browser/src/_locales/fi/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automaattinen täyttö"
},
+ "autoFillLogin": {
+ "message": "Täytä kirjautumistieto automaattisesti"
+ },
+ "autoFillCard": {
+ "message": "Täytä kortti automaattisesti"
+ },
+ "autoFillIdentity": {
+ "message": "Täytä identiteetti automaattisesti"
+ },
"generatePasswordCopied": {
"message": "Luo salasana (leikepöydälle)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Ei tunnistettuja kirjautumistietoja."
},
+ "noCards": {
+ "message": "Kortteja ei ole"
+ },
+ "noIdentities": {
+ "message": "Identiteettejä ei ole"
+ },
+ "addLoginMenu": {
+ "message": "Lisää kirjautumistieto"
+ },
+ "addCardMenu": {
+ "message": "Lisää kortti"
+ },
+ "addIdentityMenu": {
+ "message": "Lisää identiteetti"
+ },
"unlockVaultMenu": {
"message": "Avaa holvisi"
},
diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json
index a8673d001ae..464cf888899 100644
--- a/apps/browser/src/_locales/fil/messages.json
+++ b/apps/browser/src/_locales/fil/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill sa Filipino ay Awtomatikong Pagpuno"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Maglagay ng Password"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Walang tumutugmang mga login"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Buksan ang iyong kahadeyero"
},
diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json
index ba4d6a6dd86..b0827b39006 100644
--- a/apps/browser/src/_locales/fr/messages.json
+++ b/apps/browser/src/_locales/fr/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Saisie automatique"
},
+ "autoFillLogin": {
+ "message": "Saisie automatique de l'identifiant"
+ },
+ "autoFillCard": {
+ "message": "Saisie automatique de la carte"
+ },
+ "autoFillIdentity": {
+ "message": "Saisie automatique de l'identité"
+ },
"generatePasswordCopied": {
"message": "Générer un mot de passe (copié)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Aucun identifiant correspondant."
},
+ "noCards": {
+ "message": "Aucune carte"
+ },
+ "noIdentities": {
+ "message": "Aucune identité"
+ },
+ "addLoginMenu": {
+ "message": "Ajouter un identifiant"
+ },
+ "addCardMenu": {
+ "message": "Ajouter une carte"
+ },
+ "addIdentityMenu": {
+ "message": "Ajouter une identité"
+ },
"unlockVaultMenu": {
"message": "Déverrouillez votre coffre"
},
@@ -634,7 +658,7 @@
"message": "Mettre à jour"
},
"notificationUnlockDesc": {
- "message": "Unlock your Bitwarden vault to complete the auto-fill request."
+ "message": "Déverrouillez votre coffre Bitwarden pour terminer la demande de saisie automatique."
},
"notificationUnlock": {
"message": "Déverrouiller"
diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/gl/messages.json
+++ b/apps/browser/src/_locales/gl/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json
index 68f1ebc1218..19985cd5ec8 100644
--- a/apps/browser/src/_locales/he/messages.json
+++ b/apps/browser/src/_locales/he/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "השלמה אוטומטית"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "צור סיסמה (העתק)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "לא נמצאו פרטי כניסה תואמים."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "שחרור הכספת שלך"
},
diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json
index 2b99c964209..4b686192902 100644
--- a/apps/browser/src/_locales/hi/messages.json
+++ b/apps/browser/src/_locales/hi/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "स्वत:भरण"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate Password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "कोई मेल-मिला लॉगिन नहीं |"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "आपकी तिजोरी का ताला खोलें"
},
diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json
index b88c097804f..b334d22332f 100644
--- a/apps/browser/src/_locales/hr/messages.json
+++ b/apps/browser/src/_locales/hr/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-ispuna"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generiraj lozinku (i kopiraj)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nema podudarajućih prijava"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Otključaj svoj trezor"
},
diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json
index efe6d260355..abf5a12e5e5 100644
--- a/apps/browser/src/_locales/hu/messages.json
+++ b/apps/browser/src/_locales/hu/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automatikus kitöltés"
},
+ "autoFillLogin": {
+ "message": "Automatikus kitöltés bejelentkezés"
+ },
+ "autoFillCard": {
+ "message": "Automatikus kitöltés kártya"
+ },
+ "autoFillIdentity": {
+ "message": "Automatikus kitöltés személyazonosság"
+ },
"generatePasswordCopied": {
"message": "Jelszó generálás (másolt)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nincsenek egyező bejelentkezések."
},
+ "noCards": {
+ "message": "Nincsenek kártyák"
+ },
+ "noIdentities": {
+ "message": "Nincsenek személyazonosságok"
+ },
+ "addLoginMenu": {
+ "message": "Bejelentkezés hozzáadása"
+ },
+ "addCardMenu": {
+ "message": "Kártya hozzáadása"
+ },
+ "addIdentityMenu": {
+ "message": "Személyazonossság hozzáadása"
+ },
"unlockVaultMenu": {
"message": "Széf kinyitása"
},
@@ -143,7 +167,7 @@
"message": "A folytatáshoz meg kell erősíteni a személyazonosságot."
},
"account": {
- "message": "Felhasználó"
+ "message": "Fiók"
},
"changeMasterPassword": {
"message": "Mesterjelszó módosítása"
@@ -513,7 +537,7 @@
"message": "A kétlépcsős bejelentkezés biztonságosabbá teszi a fiókot azáltal, hogy ellenőrizni kell a bejelentkezést egy másik olyan eszközzel mint például biztonsági kulcs, hitelesítő alkalmazás, SMS, telefon hívás vagy email. A kétlépcsős bejelentkezést a bitwarden.com webes széfben lehet engedélyezni. Felkeressük a webhelyet most?"
},
"editedFolder": {
- "message": "A mappa módosításra került."
+ "message": "A mappa mentésre került."
},
"deleteFolderConfirmation": {
"message": "Biztos, hogy törölni akarod ezt a mappát?"
@@ -562,7 +586,7 @@
"message": "Biztosan törlésre kerüljön ezt az elem?"
},
"deletedItem": {
- "message": "Az elem törlésre került."
+ "message": "Az elem a lomtárba került."
},
"overwritePassword": {
"message": "Jelszó felülírása"
@@ -769,7 +793,7 @@
"message": "A naximális fájlméret 500 MB."
},
"featureUnavailable": {
- "message": "Ez a funkció nem érhető el."
+ "message": "A funkció nem érhető el."
},
"encryptionKeyMigrationRequired": {
"message": "Titkosítási kulcs migráció szükséges. Jelentkezzünk be a webes széfen keresztül a titkosítási kulcs frissítéséhez."
@@ -787,7 +811,7 @@
"message": "Tagság frissítése"
},
"premiumNotCurrentMember": {
- "message": "Jelenleg nincs prémium tagság."
+ "message": "Jelenleg nem vagyunk prémium tag."
},
"premiumSignUpAndGet": {
"message": "Regisztráció a prémium tagságra az alábbi funkciókért:"
@@ -796,7 +820,7 @@
"message": "1 GB titkosított tárhely a fájlmellékleteknek."
},
"premiumSignUpTwoStepOptions": {
- "message": "Proprietary two-step login options such as YubiKey and Duo."
+ "message": "Saját kétlépcsős bejelentkezési lehetőségek mint a YubiKey és a Duo."
},
"ppremiumSignUpReports": {
"message": "Jelszó higiénia, fiók biztonság és adatszivárgási jelentések a széf biztonsága érdekében."
@@ -817,7 +841,7 @@
"message": "A prémium tagság megvásárolható a bitwarden.com webes széfben. Szeretnénk felkeresni a webhelyet most?"
},
"premiumCurrentMember": {
- "message": "Jelenleg a prémium tagság érvényben van."
+ "message": "Prémium tag vagyunk!"
},
"premiumCurrentMemberThanks": {
"message": "Köszönjük a Bitwarden támogatását."
@@ -994,7 +1018,7 @@
"message": "Alapértelmezett beállítások bejelentkezési elemekhez"
},
"defaultAutoFillOnPageLoadDesc": {
- "message": "Az Automatikus kitöltés engedélyezése az oldalbetöltéskor engedélyezheti vagy letilthatja a funkciót az egyes bejelentkezési elemeknél. Ez az alapértelmezett beállítás a bejelentkezési elemeknéll, amelyek nincsenek külön konfigurálva."
+ "message": "Az egyes bejelentkezési elemeknél kikapcsolhatjuk oldalbetöltéskor az automatikus kitöltést az elem Szerkesztés nézetében."
},
"itemAutoFillOnPageLoad": {
"message": "Automatikus kitöltés oldal betöltésnél (Ha engedélyezett az opcióknál)"
@@ -1905,7 +1929,7 @@
"message": "Perc"
},
"vaultTimeoutPolicyInEffect": {
- "message": "A szervezeti házirendek hatással vannak a széf időkorlátjára. A széf időkorlátja legfeljebb $HOURS$ óra és $MINUTES$ perc lehet.",
+ "message": "A szervezeti szabályzata $HOURS$ órára és $MINUTES$ percre állította be a maximálisan megengedett széf időtúllépést.",
"placeholders": {
"hours": {
"content": "$1",
diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json
index f3fdd1a7c27..7b19a6838c0 100644
--- a/apps/browser/src/_locales/id/messages.json
+++ b/apps/browser/src/_locales/id/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Isi otomatis"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Membuat Kata Sandi (tersalin)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Tidak ada info masuk yang cocok."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Buka brankas Anda"
},
diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json
index 691e2484cba..9bca2da6062 100644
--- a/apps/browser/src/_locales/it/messages.json
+++ b/apps/browser/src/_locales/it/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Riempimento automatico"
},
+ "autoFillLogin": {
+ "message": "Riempi automaticamente login"
+ },
+ "autoFillCard": {
+ "message": "Riempi automaticamente carta"
+ },
+ "autoFillIdentity": {
+ "message": "Riempi automaticamente identità"
+ },
"generatePasswordCopied": {
"message": "Genera password e copiala"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nessun login corrispondente"
},
+ "noCards": {
+ "message": "Nessuna carta"
+ },
+ "noIdentities": {
+ "message": "Nessuna identità"
+ },
+ "addLoginMenu": {
+ "message": "Aggiungi login"
+ },
+ "addCardMenu": {
+ "message": "Aggiungi carta"
+ },
+ "addIdentityMenu": {
+ "message": "Aggiungi identità"
+ },
"unlockVaultMenu": {
"message": "Sblocca la tua cassaforte"
},
diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json
index c3762ae4ef8..d2528a45489 100644
--- a/apps/browser/src/_locales/ja/messages.json
+++ b/apps/browser/src/_locales/ja/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "自動入力"
},
+ "autoFillLogin": {
+ "message": "自動入力ログイン"
+ },
+ "autoFillCard": {
+ "message": "自動入力カード"
+ },
+ "autoFillIdentity": {
+ "message": "自動入力 ID"
+ },
"generatePasswordCopied": {
"message": "パスワードを生成 (コピー)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "一致するログインがありません。"
},
+ "noCards": {
+ "message": "カードなし"
+ },
+ "noIdentities": {
+ "message": "ID なし"
+ },
+ "addLoginMenu": {
+ "message": "ログイン情報を追加"
+ },
+ "addCardMenu": {
+ "message": "カードを追加"
+ },
+ "addIdentityMenu": {
+ "message": "ID を追加"
+ },
"unlockVaultMenu": {
"message": "保管庫のロックを解除"
},
diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json
index 50a25ad0dd9..2d2b5cb8a5e 100644
--- a/apps/browser/src/_locales/ka/messages.json
+++ b/apps/browser/src/_locales/ka/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "თვითშევსება"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/km/messages.json
+++ b/apps/browser/src/_locales/km/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json
index 06f9461e5fd..95c9350aff8 100644
--- a/apps/browser/src/_locales/kn/messages.json
+++ b/apps/browser/src/_locales/kn/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "ಸ್ವಯಂ ಭರ್ತಿ"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "ಪಾಸ್ವರ್ಡ್ ರಚಿಸಿ (ನಕಲಿಸಲಾಗಿದೆ)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "ಹೊಂದಾಣಿಕೆಯ ಲಾಗಿನ್ಗಳು ಇಲ್ಲ."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json
index 5921e579e24..e7aba95f493 100644
--- a/apps/browser/src/_locales/ko/messages.json
+++ b/apps/browser/src/_locales/ko/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "자동 완성"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "비밀번호 생성 및 클립보드에 복사"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "사용할 수 있는 로그인이 없습니다."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "보관함 잠금 해제"
},
diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json
index 425d0c98233..885b3cbec8f 100644
--- a/apps/browser/src/_locales/lt/messages.json
+++ b/apps/browser/src/_locales/lt/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automatinis užpildymas"
},
+ "autoFillLogin": {
+ "message": "Automatinio užpildymo prisijungimas"
+ },
+ "autoFillCard": {
+ "message": "Automatinio užpildymo kortelė"
+ },
+ "autoFillIdentity": {
+ "message": "Automatinio užpildymo tapatybė"
+ },
"generatePasswordCopied": {
"message": "Kurti slaptažodį (paruoštas įterpti)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nėra atitinkančių prisijungimų."
},
+ "noCards": {
+ "message": "Nėra kortelių"
+ },
+ "noIdentities": {
+ "message": "Nėra tapatybių"
+ },
+ "addLoginMenu": {
+ "message": "Pridėti prisijungimą"
+ },
+ "addCardMenu": {
+ "message": "Pridėti kortelę"
+ },
+ "addIdentityMenu": {
+ "message": "Pridėti tapatybę"
+ },
"unlockVaultMenu": {
"message": "Atrakinti saugyklą"
},
diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json
index 624904d7213..2abb0ac4de6 100644
--- a/apps/browser/src/_locales/lv/messages.json
+++ b/apps/browser/src/_locales/lv/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automātiskā aizpildīšana"
},
+ "autoFillLogin": {
+ "message": "Automātiski aizpildīt pieteikšanos"
+ },
+ "autoFillCard": {
+ "message": "Automātiski aizpildīt karti"
+ },
+ "autoFillIdentity": {
+ "message": "Automātiski aizpildīt identitāti"
+ },
"generatePasswordCopied": {
"message": "Izveidot paroli (tiks ievietota starpliktuvē)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nav atbilstošu pieteikšanās vienumu"
},
+ "noCards": {
+ "message": "Nav karšu"
+ },
+ "noIdentities": {
+ "message": "Nav identitāšu"
+ },
+ "addLoginMenu": {
+ "message": "Pievienot pieteikšanās vienumu"
+ },
+ "addCardMenu": {
+ "message": "Pievienot karti"
+ },
+ "addIdentityMenu": {
+ "message": "Pievienot identitāti"
+ },
"unlockVaultMenu": {
"message": "Atslēgt glabātavu"
},
diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json
index 58d5b04fc8b..258ad3fd966 100644
--- a/apps/browser/src/_locales/ml/messages.json
+++ b/apps/browser/src/_locales/ml/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "ഓട്ടോഫിൽ"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "പാസ്വേഡ് സൃഷ്ടിക്കുക (പകർത്തുക )"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "പൊരുത്തപ്പെടുന്ന ലോഗിനുകളൊന്നുമില്ല."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json
index 8f8f58775f7..131c062d544 100644
--- a/apps/browser/src/_locales/mr/messages.json
+++ b/apps/browser/src/_locales/mr/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "स्वयंभरण"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "तिजोरी उघडा"
},
diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/my/messages.json
+++ b/apps/browser/src/_locales/my/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json
index 4dadbbc8a7b..43a19478bb0 100644
--- a/apps/browser/src/_locales/nb/messages.json
+++ b/apps/browser/src/_locales/nb/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-utfylling"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generer et passord (kopiert)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Ingen samsvarende innlogginger."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Lås opp hvelvet ditt"
},
diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/ne/messages.json
+++ b/apps/browser/src/_locales/ne/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json
index 5915dad872a..630510f6723 100644
--- a/apps/browser/src/_locales/nl/messages.json
+++ b/apps/browser/src/_locales/nl/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-invullen"
},
+ "autoFillLogin": {
+ "message": "Login automatisch invullen"
+ },
+ "autoFillCard": {
+ "message": "Kaart automatisch invullen"
+ },
+ "autoFillIdentity": {
+ "message": "Identiteit automatisch invullen"
+ },
"generatePasswordCopied": {
"message": "Wachtwoord genereren (op klembord)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Geen overeenkomstige logins."
},
+ "noCards": {
+ "message": "Geen kaarten"
+ },
+ "noIdentities": {
+ "message": "Geen identiteiten"
+ },
+ "addLoginMenu": {
+ "message": "Login toevoegen"
+ },
+ "addCardMenu": {
+ "message": "Kaart toevoegen"
+ },
+ "addIdentityMenu": {
+ "message": "Identiteit toevoegen"
+ },
"unlockVaultMenu": {
"message": "Ontgrendel je kluis"
},
@@ -772,7 +796,7 @@
"message": "Functionaliteit niet beschikbaar"
},
"encryptionKeyMigrationRequired": {
- "message": "Encryption key migration required. Please login through the web vault to update your encryption key."
+ "message": "Migratie van de encryptiesleutel vereist. Login via de website om je sleutel te bij te werken."
},
"premiumMembership": {
"message": "Premium-abonnement"
diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/nn/messages.json
+++ b/apps/browser/src/_locales/nn/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/or/messages.json
+++ b/apps/browser/src/_locales/or/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json
index 2f28c87d801..5b16c13ef14 100644
--- a/apps/browser/src/_locales/pl/messages.json
+++ b/apps/browser/src/_locales/pl/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Autouzupełnianie"
},
+ "autoFillLogin": {
+ "message": "Autouzupełnianie logowania"
+ },
+ "autoFillCard": {
+ "message": "Autouzupełnianie karty"
+ },
+ "autoFillIdentity": {
+ "message": "Autouzupełnianie tożsamości"
+ },
"generatePasswordCopied": {
"message": "Wygeneruj hasło (do schowka)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Brak pasujących danych logowania"
},
+ "noCards": {
+ "message": "Brak kart"
+ },
+ "noIdentities": {
+ "message": "Brak tożsamości"
+ },
+ "addLoginMenu": {
+ "message": "Dodaj dane logowania"
+ },
+ "addCardMenu": {
+ "message": "Dodaj kartę"
+ },
+ "addIdentityMenu": {
+ "message": "Dodaj tożsamość"
+ },
"unlockVaultMenu": {
"message": "Odblokuj sejf"
},
diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json
index ed62f893a19..7578ae170ca 100644
--- a/apps/browser/src/_locales/pt_BR/messages.json
+++ b/apps/browser/src/_locales/pt_BR/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Autopreencher"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Gerar Senha (copiada)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Sem credenciais correspondentes."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Desbloqueie seu cofre"
},
diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json
index 735edf60afe..1495b64e453 100644
--- a/apps/browser/src/_locales/pt_PT/messages.json
+++ b/apps/browser/src/_locales/pt_PT/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Preenchimento automático"
},
+ "autoFillLogin": {
+ "message": "Preenchimento automático da credencial"
+ },
+ "autoFillCard": {
+ "message": "Preenchimento automático do cartão"
+ },
+ "autoFillIdentity": {
+ "message": "Preenchimento automático da identidade"
+ },
"generatePasswordCopied": {
"message": "Gerar palavra-passe (copiada)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Sem credenciais correspondentes"
},
+ "noCards": {
+ "message": "Sem cartões"
+ },
+ "noIdentities": {
+ "message": "Sem identidades"
+ },
+ "addLoginMenu": {
+ "message": "Adicionar credencial"
+ },
+ "addCardMenu": {
+ "message": "Adicionar cartão"
+ },
+ "addIdentityMenu": {
+ "message": "Adicionar identidade"
+ },
"unlockVaultMenu": {
"message": "Desbloquear o cofre"
},
diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json
index f525f87b6c2..085951a93f1 100644
--- a/apps/browser/src/_locales/ro/messages.json
+++ b/apps/browser/src/_locales/ro/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-completare"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generare parolă (s-a copiat)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Nu există potrivire de autentificări"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Deblocați-vă seiful"
},
diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json
index 40452e56dce..40ecd382bd5 100644
--- a/apps/browser/src/_locales/ru/messages.json
+++ b/apps/browser/src/_locales/ru/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Автозаполнение"
},
+ "autoFillLogin": {
+ "message": "Автозаполнение логина"
+ },
+ "autoFillCard": {
+ "message": "Автозаполнение карты"
+ },
+ "autoFillIdentity": {
+ "message": "Автозаполнение личности"
+ },
"generatePasswordCopied": {
"message": "Сгенерировать пароль (с копированием)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Нет подходящих логинов."
},
+ "noCards": {
+ "message": "Нет карт"
+ },
+ "noIdentities": {
+ "message": "Нет личностей"
+ },
+ "addLoginMenu": {
+ "message": "Добавить логин"
+ },
+ "addCardMenu": {
+ "message": "Добавить карту"
+ },
+ "addIdentityMenu": {
+ "message": "Добавить личность"
+ },
"unlockVaultMenu": {
"message": "Разблокировать хранилище"
},
diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json
index 04f2a619a82..8ea364cb6d1 100644
--- a/apps/browser/src/_locales/si/messages.json
+++ b/apps/browser/src/_locales/si/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "ස්වයං-පිරවීම"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "මුරපදය ජනනය (පිටපත්)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "ගැලපෙන පිවිසුම් නොමැත."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json
index 684c677c45b..d04f2ccf05a 100644
--- a/apps/browser/src/_locales/sk/messages.json
+++ b/apps/browser/src/_locales/sk/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Automatické vypĺňanie"
},
+ "autoFillLogin": {
+ "message": "Automatické vyplnenie prihlasovacích údajov"
+ },
+ "autoFillCard": {
+ "message": "Automatické vyplnenie karty"
+ },
+ "autoFillIdentity": {
+ "message": "Automatické vyplnenie identity"
+ },
"generatePasswordCopied": {
"message": "Vygenerovať heslo (skopírované)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Žiadne zodpovedajúce prihlasovacie údaje."
},
+ "noCards": {
+ "message": "Žiadne karty"
+ },
+ "noIdentities": {
+ "message": "Žiadne identity"
+ },
+ "addLoginMenu": {
+ "message": "Pridať prihlasovacie údaje"
+ },
+ "addCardMenu": {
+ "message": "Pridať kartu"
+ },
+ "addIdentityMenu": {
+ "message": "Pridať identitu"
+ },
"unlockVaultMenu": {
"message": "Odomknúť trezor"
},
diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json
index 8878c308045..5f859e9e5f3 100644
--- a/apps/browser/src/_locales/sl/messages.json
+++ b/apps/browser/src/_locales/sl/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Samodejno izpolnjevanje"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generiraj geslo (kopirano)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Ni ustreznih prijav."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Odkleni svoj trezor"
},
diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json
index 46e96c7d8df..c496e7628d9 100644
--- a/apps/browser/src/_locales/sr/messages.json
+++ b/apps/browser/src/_locales/sr/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Аутоматско допуњавање"
},
+ "autoFillLogin": {
+ "message": "Ауто-пуњење пријаве"
+ },
+ "autoFillCard": {
+ "message": "Ауто-пуњење картице"
+ },
+ "autoFillIdentity": {
+ "message": "Ауто-пуњење идентитета"
+ },
"generatePasswordCopied": {
"message": "Генериши Лозинку (копирано)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Нема одговарајућих пријављивања."
},
+ "noCards": {
+ "message": "Нема карте"
+ },
+ "noIdentities": {
+ "message": "Нема идентитета"
+ },
+ "addLoginMenu": {
+ "message": "Нема пријаве"
+ },
+ "addCardMenu": {
+ "message": "Додати картицу"
+ },
+ "addIdentityMenu": {
+ "message": "Додати идентитет"
+ },
"unlockVaultMenu": {
"message": "Откључај свој сеф"
},
@@ -2408,7 +2432,7 @@
"description": "Toggling an expand/collapse state."
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "Домен алијаса"
},
"passwordRepromptDisabledAutofillOnPageLoad": {
"message": "Ставке са упитом за поновно постављање главне лозинке не могу се ауто-попунити при учитавању странице. Ауто-попуњавање при учитавању странице је искључено.",
diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json
index 680a3aac0bd..283665f4977 100644
--- a/apps/browser/src/_locales/sv/messages.json
+++ b/apps/browser/src/_locales/sv/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Fyll i automatiskt"
},
+ "autoFillLogin": {
+ "message": "Autofyll inloggning"
+ },
+ "autoFillCard": {
+ "message": "Autofyll kort"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Skapa lösenord (kopierad)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Inga matchande inloggningar"
},
+ "noCards": {
+ "message": "Inga kort"
+ },
+ "noIdentities": {
+ "message": "Inga identiteter"
+ },
+ "addLoginMenu": {
+ "message": "Lägg till inloggning"
+ },
+ "addCardMenu": {
+ "message": "Lägg till kort"
+ },
+ "addIdentityMenu": {
+ "message": "Lägg till identitet"
+ },
"unlockVaultMenu": {
"message": "Lås upp ditt valv"
},
diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json
index f8ffeff747e..22330901579 100644
--- a/apps/browser/src/_locales/te/messages.json
+++ b/apps/browser/src/_locales/te/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Auto-fill"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "No matching logins"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Unlock your vault"
},
diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json
index 0db240ea797..20702a1de4a 100644
--- a/apps/browser/src/_locales/th/messages.json
+++ b/apps/browser/src/_locales/th/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "กรอกข้อมูลอัตโนมัติ"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Generate Password (copied)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "ไม่พบข้อมูลล็อกอินที่ตรงกัน"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "ปลดล็อกกตู้นิรภัยของคุณ"
},
diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json
index e52a2f59f26..e9763386aa6 100644
--- a/apps/browser/src/_locales/tr/messages.json
+++ b/apps/browser/src/_locales/tr/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Otomatik doldur"
},
+ "autoFillLogin": {
+ "message": "Hesabı otomatik doldur"
+ },
+ "autoFillCard": {
+ "message": "Kartı otomatik doldur"
+ },
+ "autoFillIdentity": {
+ "message": "Kimliği otomatik doldur"
+ },
"generatePasswordCopied": {
"message": "Parola oluştur (ve kopyala)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Eşleşen hesap yok"
},
+ "noCards": {
+ "message": "Kart yok"
+ },
+ "noIdentities": {
+ "message": "Kimlik yok"
+ },
+ "addLoginMenu": {
+ "message": "Hesap ekle"
+ },
+ "addCardMenu": {
+ "message": "Kart ekle"
+ },
+ "addIdentityMenu": {
+ "message": "Kimlik ekle"
+ },
"unlockVaultMenu": {
"message": "Kasanızın kilidini açın"
},
@@ -1609,7 +1633,7 @@
"message": "Biyometri doğrulanamadı"
},
"biometricsFailedDesc": {
- "message": "Biometrics cannot be completed, consider using a master password or logging out. If this persists, please contact Bitwarden support."
+ "message": "Biyometri doğrulaması tamamlanamadı. Ana parolanızı kullanabilir veya çıkış yapabilirsiniz. Sorun devam ederse Bitwarden destek ekibiyle iletişime geçin."
},
"nativeMessaginPermissionErrorTitle": {
"message": "İzin verilmedi"
diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json
index 6cb70bd76bd..666870146d4 100644
--- a/apps/browser/src/_locales/uk/messages.json
+++ b/apps/browser/src/_locales/uk/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Автозаповнення"
},
+ "autoFillLogin": {
+ "message": "Автозаповнення входу"
+ },
+ "autoFillCard": {
+ "message": "Автозаповнення картки"
+ },
+ "autoFillIdentity": {
+ "message": "Автозаповнення особистих даних"
+ },
"generatePasswordCopied": {
"message": "Генерувати пароль (з копіюванням)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Немає відповідних записів"
},
+ "noCards": {
+ "message": "Немає карток"
+ },
+ "noIdentities": {
+ "message": "Немає особистих даних"
+ },
+ "addLoginMenu": {
+ "message": "Додати запис входу"
+ },
+ "addCardMenu": {
+ "message": "Додати картку"
+ },
+ "addIdentityMenu": {
+ "message": "Додати особисті дані"
+ },
"unlockVaultMenu": {
"message": "Розблокуйте сховище"
},
@@ -2408,18 +2432,18 @@
"description": "Toggling an expand/collapse state."
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "Псевдонім домену"
},
"passwordRepromptDisabledAutofillOnPageLoad": {
- "message": "Items with master password re-prompt cannot be auto-filled on page load. Auto-fill on page load turned off.",
+ "message": "Записи з повторним запитом головного пароля не можна автоматично заповнювати під час завантаження сторінки. Автозаповнення на сторінці вимкнено.",
"description": "Toast message for describing that master password re-prompt cannot be auto-filled on page load."
},
"autofillOnPageLoadSetToDefault": {
- "message": "Auto-fill on page load set to use default setting.",
+ "message": "Автозаповнення на сторінці налаштовано з типовими параметрами.",
"description": "Toast message for informing the user that auto-fill on page load has been set to the default setting."
},
"turnOffMasterPasswordPromptToEditField": {
- "message": "Turn off master password re-prompt to edit this field",
+ "message": "Вимкніть повторний запит головного пароля, щоб редагувати це поле",
"description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item."
}
}
diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json
index e562a0b5d5d..caedbb8b917 100644
--- a/apps/browser/src/_locales/vi/messages.json
+++ b/apps/browser/src/_locales/vi/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "Tự động điền"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "Tạo mật khẩu (đã sao chép)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "Không có thông tin đăng nhập phù hợp."
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "Mở khoá kho lưu trữ của bạn"
},
diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json
index b1d0aac7e4a..5331208af82 100644
--- a/apps/browser/src/_locales/zh_CN/messages.json
+++ b/apps/browser/src/_locales/zh_CN/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "自动填充"
},
+ "autoFillLogin": {
+ "message": "自动填充登录"
+ },
+ "autoFillCard": {
+ "message": "自动填充支付卡"
+ },
+ "autoFillIdentity": {
+ "message": "自动填充身份"
+ },
"generatePasswordCopied": {
"message": "生成密码(并复制)"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "无匹配的登录项目"
},
+ "noCards": {
+ "message": "无支付卡"
+ },
+ "noIdentities": {
+ "message": "无身份"
+ },
+ "addLoginMenu": {
+ "message": "添加登录项目"
+ },
+ "addCardMenu": {
+ "message": "添加支付卡"
+ },
+ "addIdentityMenu": {
+ "message": "添加身份"
+ },
"unlockVaultMenu": {
"message": "解锁您的密码库"
},
@@ -850,7 +874,7 @@
"message": "使用此功能需要高级会员资格。"
},
"enterVerificationCodeApp": {
- "message": "请输入您的验证器应用中的 6 位验证码。"
+ "message": "请输入您的验证器应用中的 6 位数验证码。"
},
"enterVerificationCodeEmail": {
"message": "请输入发送给电子邮件 $EMAIL$ 的 6 位数验证码。",
@@ -2117,7 +2141,7 @@
}
},
"loginWithMasterPassword": {
- "message": "主密码登录"
+ "message": "使用主密码登录"
},
"loggingInAs": {
"message": "正登录为"
@@ -2132,7 +2156,7 @@
"message": "记住电子邮件地址"
},
"loginWithDevice": {
- "message": "设备登录"
+ "message": "使用设备登录"
},
"loginWithDeviceEnabledInfo": {
"message": "设备登录必须在 Bitwarden 应用程序的设置中启用。需要其他登录选项吗?"
diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json
index 58ca526bc68..b3368beb188 100644
--- a/apps/browser/src/_locales/zh_TW/messages.json
+++ b/apps/browser/src/_locales/zh_TW/messages.json
@@ -91,6 +91,15 @@
"autoFill": {
"message": "自動填入"
},
+ "autoFillLogin": {
+ "message": "Auto-fill login"
+ },
+ "autoFillCard": {
+ "message": "Auto-fill card"
+ },
+ "autoFillIdentity": {
+ "message": "Auto-fill identity"
+ },
"generatePasswordCopied": {
"message": "產生及複製密碼"
},
@@ -100,6 +109,21 @@
"noMatchingLogins": {
"message": "無符合的登入資料"
},
+ "noCards": {
+ "message": "No cards"
+ },
+ "noIdentities": {
+ "message": "No identities"
+ },
+ "addLoginMenu": {
+ "message": "Add login"
+ },
+ "addCardMenu": {
+ "message": "Add card"
+ },
+ "addIdentityMenu": {
+ "message": "Add identity"
+ },
"unlockVaultMenu": {
"message": "解鎖您的密碼庫"
},
diff --git a/apps/browser/src/auth/popup/two-factor.component.html b/apps/browser/src/auth/popup/two-factor.component.html
index 7fec67378cc..d03c675abdc 100644
--- a/apps/browser/src/auth/popup/two-factor.component.html
+++ b/apps/browser/src/auth/popup/two-factor.component.html
@@ -113,7 +113,10 @@
"
>
-
+
diff --git a/apps/browser/src/autofill/content/autofill.js b/apps/browser/src/autofill/content/autofill.js
index 2f3857d3fa8..ef0fb73408b 100644
--- a/apps/browser/src/autofill/content/autofill.js
+++ b/apps/browser/src/autofill/content/autofill.js
@@ -993,11 +993,6 @@
function fillTheElement(el, op) {
var shouldCheck;
if (el && null !== op && void 0 !== op && !(el.disabled || el.a || el.readOnly)) {
- const tabURLChanged = !fillScript.savedUrls?.some(url => url.startsWith(window.location.origin))
- // Check to make sure the page location didn't change
- if (tabURLChanged) {
- return;
- }
switch (markTheFilling && el.form && !el.form.opfilled && (el.form.opfilled = true),
el.type ? el.type.toLowerCase() : null) {
case 'checkbox':
diff --git a/apps/browser/src/autofill/services/autofill.service.ts b/apps/browser/src/autofill/services/autofill.service.ts
index ee233c42524..aca72562287 100644
--- a/apps/browser/src/autofill/services/autofill.service.ts
+++ b/apps/browser/src/autofill/services/autofill.service.ts
@@ -148,7 +148,7 @@ export default class AutofillService implements AutofillServiceInterface {
throw new Error("Nothing to auto-fill.");
}
- let totpPromise: Promise
= null;
+ let totp: string | null = null;
const canAccessPremium = await this.stateService.getCanAccessPremium();
const defaultUriMatch = (await this.stateService.getDefaultUriMatch()) ?? UriMatchType.Domain;
@@ -205,15 +205,14 @@ export default class AutofillService implements AutofillServiceInterface {
if (
options.cipher.type !== CipherType.Login ||
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
- totpPromise ||
+ totp !== null ||
!options.cipher.login.totp ||
(!canAccessPremium && !options.cipher.organizationUseTotp)
) {
return;
}
- totpPromise = this.stateService.getDisableAutoTotpCopy().then((disabled) => {
+ totp = await this.stateService.getDisableAutoTotpCopy().then((disabled) => {
if (!disabled) {
return this.totpService.getCode(options.cipher.login.totp);
}
@@ -224,8 +223,8 @@ export default class AutofillService implements AutofillServiceInterface {
if (didAutofill) {
this.eventCollectionService.collect(EventType.Cipher_ClientAutofilled, options.cipher.id);
- if (totpPromise != null) {
- return await totpPromise;
+ if (totp !== null) {
+ return totp;
} else {
return null;
}
diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts
index 0ab74875fbf..828d768ca25 100644
--- a/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts
+++ b/apps/browser/src/autofill/services/insert-autofill-content.service.spec.ts
@@ -108,7 +108,6 @@ describe("InsertAutofillContentService", () => {
jest.spyOn(insertAutofillContentService as any, "fillingWithinSandboxedIframe");
jest.spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill");
jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill");
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged");
jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
insertAutofillContentService.fillForm(fillScript);
@@ -120,7 +119,6 @@ describe("InsertAutofillContentService", () => {
expect(
insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
).not.toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled();
expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled();
});
@@ -130,7 +128,6 @@ describe("InsertAutofillContentService", () => {
.mockReturnValue(true);
jest.spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill");
jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill");
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged");
jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
insertAutofillContentService.fillForm(fillScript);
@@ -142,7 +139,6 @@ describe("InsertAutofillContentService", () => {
expect(
insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
).not.toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled();
expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled();
});
@@ -154,7 +150,6 @@ describe("InsertAutofillContentService", () => {
.spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill")
.mockReturnValue(true);
jest.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill");
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged");
jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
insertAutofillContentService.fillForm(fillScript);
@@ -164,7 +159,6 @@ describe("InsertAutofillContentService", () => {
expect(
insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
).not.toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled();
expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled();
});
@@ -178,7 +172,6 @@ describe("InsertAutofillContentService", () => {
jest
.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill")
.mockReturnValue(true);
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(false);
jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
insertAutofillContentService.fillForm(fillScript);
@@ -188,31 +181,6 @@ describe("InsertAutofillContentService", () => {
expect(
insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
).toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).not.toHaveBeenCalled();
- expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled();
- });
-
- it("returns early if the page location origin does not match against any of the cipher saved URLs", () => {
- jest
- .spyOn(insertAutofillContentService as any, "fillingWithinSandboxedIframe")
- .mockReturnValue(false);
- jest
- .spyOn(insertAutofillContentService as any, "userCancelledInsecureUrlAutofill")
- .mockReturnValue(false);
- jest
- .spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill")
- .mockReturnValue(false);
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(true);
- jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
-
- insertAutofillContentService.fillForm(fillScript);
-
- expect(insertAutofillContentService["fillingWithinSandboxedIframe"]).toHaveBeenCalled();
- expect(insertAutofillContentService["userCancelledInsecureUrlAutofill"]).toHaveBeenCalled();
- expect(
- insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
- ).toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).toHaveBeenCalled();
expect(insertAutofillContentService["runFillScriptAction"]).not.toHaveBeenCalled();
});
@@ -226,7 +194,6 @@ describe("InsertAutofillContentService", () => {
jest
.spyOn(insertAutofillContentService as any, "userCancelledUntrustedIframeAutofill")
.mockReturnValue(false);
- jest.spyOn(insertAutofillContentService as any, "tabURLChanged").mockReturnValue(false);
jest.spyOn(insertAutofillContentService as any, "runFillScriptAction");
insertAutofillContentService.fillForm(fillScript);
@@ -236,7 +203,6 @@ describe("InsertAutofillContentService", () => {
expect(
insertAutofillContentService["userCancelledUntrustedIframeAutofill"]
).toHaveBeenCalled();
- expect(insertAutofillContentService["tabURLChanged"]).toHaveBeenCalled();
expect(insertAutofillContentService["runFillScriptAction"]).toHaveBeenCalledTimes(3);
expect(insertAutofillContentService["runFillScriptAction"]).toHaveBeenNthCalledWith(
1,
diff --git a/apps/browser/src/autofill/services/insert-autofill-content.service.ts b/apps/browser/src/autofill/services/insert-autofill-content.service.ts
index ad40b76fbcd..46cb53d4f59 100644
--- a/apps/browser/src/autofill/services/insert-autofill-content.service.ts
+++ b/apps/browser/src/autofill/services/insert-autofill-content.service.ts
@@ -38,8 +38,7 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
!fillScript.script?.length ||
this.fillingWithinSandboxedIframe() ||
this.userCancelledInsecureUrlAutofill(fillScript.savedUrls) ||
- this.userCancelledUntrustedIframeAutofill(fillScript) ||
- this.tabURLChanged(fillScript.savedUrls)
+ this.userCancelledUntrustedIframeAutofill(fillScript)
) {
return;
}
@@ -47,16 +46,6 @@ class InsertAutofillContentService implements InsertAutofillContentServiceInterf
fillScript.script.forEach(this.runFillScriptAction);
}
- /**
- * Determines if the page URL no longer matches one of the cipher's savedURL domains
- * @param {string[] | null} savedUrls
- * @returns {boolean}
- * @private
- */
- private tabURLChanged(savedUrls?: AutofillScript["savedUrls"]): boolean {
- return savedUrls && !savedUrls.some((url) => url.startsWith(window.location.origin));
- }
-
/**
* Identifies if the execution of this script is happening
* within a sandboxed iframe.
diff --git a/apps/browser/src/platform/browser/browser-api.ts b/apps/browser/src/platform/browser/browser-api.ts
index b71b8b80b6c..5d0c2f1a519 100644
--- a/apps/browser/src/platform/browser/browser-api.ts
+++ b/apps/browser/src/platform/browser/browser-api.ts
@@ -208,6 +208,7 @@ export class BrowserApi {
name: string,
callback: (message: any, sender: chrome.runtime.MessageSender, response: any) => void
) {
+ // eslint-disable-next-line no-restricted-syntax
chrome.runtime.onMessage.addListener(callback);
if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) {
@@ -219,6 +220,7 @@ export class BrowserApi {
static storageChangeListener(
callback: Parameters[0]
) {
+ // eslint-disable-next-line no-restricted-syntax
chrome.storage.onChanged.addListener(callback);
if (BrowserApi.isSafariApi && !BrowserApi.isBackgroundPage(window)) {
diff --git a/apps/browser/src/popup/app.module.ts b/apps/browser/src/popup/app.module.ts
index 32eb7670f3c..9dbd87cff57 100644
--- a/apps/browser/src/popup/app.module.ts
+++ b/apps/browser/src/popup/app.module.ts
@@ -39,7 +39,6 @@ import { SendTypeComponent } from "../tools/popup/send/send-type.component";
import { ExportComponent } from "../tools/popup/settings/export.component";
import { ActionButtonsComponent } from "../vault/popup/components/action-buttons.component";
import { CipherRowComponent } from "../vault/popup/components/cipher-row.component";
-import { PasswordRepromptComponent } from "../vault/popup/components/password-reprompt.component";
import { AddEditCustomFieldsComponent } from "../vault/popup/components/vault/add-edit-custom-fields.component";
import { AddEditComponent } from "../vault/popup/components/vault/add-edit.component";
import { AttachmentsComponent } from "../vault/popup/components/vault/attachments.component";
@@ -125,7 +124,6 @@ import "../platform/popup/locales";
GeneratorComponent,
PasswordGeneratorHistoryComponent,
PasswordHistoryComponent,
- PasswordRepromptComponent,
PopOutComponent,
PremiumComponent,
PrivateModeWarningComponent,
diff --git a/apps/browser/src/popup/services/services.module.ts b/apps/browser/src/popup/services/services.module.ts
index c0597e29e44..6770e152504 100644
--- a/apps/browser/src/popup/services/services.module.ts
+++ b/apps/browser/src/popup/services/services.module.ts
@@ -80,7 +80,6 @@ import {
FolderService,
InternalFolderService,
} from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
-import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
import { DialogService } from "@bitwarden/components";
@@ -104,7 +103,6 @@ import BrowserMessagingService from "../../platform/services/browser-messaging.s
import { BrowserStateService } from "../../platform/services/browser-state.service";
import { BrowserSendService } from "../../services/browser-send.service";
import { BrowserSettingsService } from "../../services/browser-settings.service";
-import { PasswordRepromptService } from "../../vault/popup/services/password-reprompt.service";
import { BrowserFolderService } from "../../vault/services/browser-folder.service";
import { VaultFilterService } from "../../vault/services/vault-filter.service";
@@ -409,7 +407,6 @@ function getBgService(service: keyof MainBackground) {
useFactory: getBgService("logService"),
deps: [],
},
- { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
{
provide: OrganizationService,
useFactory: (stateService: StateServiceAbstraction) => {
diff --git a/apps/browser/src/vault/popup/components/action-buttons.component.ts b/apps/browser/src/vault/popup/components/action-buttons.component.ts
index 110e4ef32a5..ff8b7cab0d1 100644
--- a/apps/browser/src/vault/popup/components/action-buttons.component.ts
+++ b/apps/browser/src/vault/popup/components/action-buttons.component.ts
@@ -6,10 +6,10 @@ import { EventType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
@Component({
selector: "app-action-buttons",
diff --git a/apps/browser/src/vault/popup/components/password-reprompt.component.html b/apps/browser/src/vault/popup/components/password-reprompt.component.html
deleted file mode 100644
index 730e96fab96..00000000000
--- a/apps/browser/src/vault/popup/components/password-reprompt.component.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
diff --git a/apps/browser/src/vault/popup/components/password-reprompt.component.ts b/apps/browser/src/vault/popup/components/password-reprompt.component.ts
deleted file mode 100644
index f63da5ed48e..00000000000
--- a/apps/browser/src/vault/popup/components/password-reprompt.component.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Component } from "@angular/core";
-
-import { PasswordRepromptComponent as BasePasswordRepromptComponent } from "@bitwarden/angular/vault/components/password-reprompt.component";
-
-@Component({
- templateUrl: "password-reprompt.component.html",
-})
-export class PasswordRepromptComponent extends BasePasswordRepromptComponent {}
diff --git a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts
index f4e9fad5634..fd75b2e8c58 100644
--- a/apps/browser/src/vault/popup/components/vault/add-edit.component.ts
+++ b/apps/browser/src/vault/popup/components/vault/add-edit.component.ts
@@ -17,10 +17,10 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
import { DialogService } from "@bitwarden/components";
+import { PasswordRepromptService } from "@bitwarden/vault";
import { BrowserApi } from "../../../../platform/browser/browser-api";
import { PopupUtilsService } from "../../../../popup/services/popup-utils.service";
diff --git a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts
index 4b2c62a0e0d..4f1ceb466de 100644
--- a/apps/browser/src/vault/popup/components/vault/current-tab.component.ts
+++ b/apps/browser/src/vault/popup/components/vault/current-tab.component.ts
@@ -11,11 +11,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service";
import { BrowserApi } from "../../../../platform/browser/browser-api";
diff --git a/apps/browser/src/vault/popup/components/vault/view.component.ts b/apps/browser/src/vault/popup/components/vault/view.component.ts
index 19c37fc985e..29027b33505 100644
--- a/apps/browser/src/vault/popup/components/vault/view.component.ts
+++ b/apps/browser/src/vault/popup/components/vault/view.component.ts
@@ -20,11 +20,11 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
import { DialogService } from "@bitwarden/components";
+import { PasswordRepromptService } from "@bitwarden/vault";
import { AutofillService } from "../../../../autofill/services/abstractions/autofill.service";
import { BrowserApi } from "../../../../platform/browser/browser-api";
@@ -331,11 +331,21 @@ export class ViewComponent extends BaseViewComponent {
}
private async doAutofill() {
+ const originalTabURL = this.tab.url?.length && new URL(this.tab.url);
+
if (!(await this.promptPassword())) {
return false;
}
- if (this.pageDetails == null || this.pageDetails.length === 0) {
+ const currentTabURL = this.tab.url?.length && new URL(this.tab.url);
+
+ const originalTabHostPath =
+ originalTabURL && `${originalTabURL.origin}${originalTabURL.pathname}`;
+ const currentTabHostPath = currentTabURL && `${currentTabURL.origin}${currentTabURL.pathname}`;
+
+ const tabUrlChanged = originalTabHostPath !== currentTabHostPath;
+
+ if (this.pageDetails == null || this.pageDetails.length === 0 || tabUrlChanged) {
this.platformUtilsService.showToast("error", null, this.i18nService.t("autofillError"));
return false;
}
diff --git a/apps/browser/src/vault/popup/services/password-reprompt.service.ts b/apps/browser/src/vault/popup/services/password-reprompt.service.ts
deleted file mode 100644
index 22bbcf44d7f..00000000000
--- a/apps/browser/src/vault/popup/services/password-reprompt.service.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Injectable } from "@angular/core";
-
-import { PasswordRepromptService as BasePasswordRepromptService } from "@bitwarden/angular/vault/services/password-reprompt.service";
-
-import { PasswordRepromptComponent } from "../components/password-reprompt.component";
-
-@Injectable()
-export class PasswordRepromptService extends BasePasswordRepromptService {
- component = PasswordRepromptComponent;
-}
diff --git a/apps/browser/store/locales/az/copy.resx b/apps/browser/store/locales/az/copy.resx
index 677ad41b6bc..cb05f8e5d9e 100644
--- a/apps/browser/store/locales/az/copy.resx
+++ b/apps/browser/store/locales/az/copy.resx
@@ -139,7 +139,7 @@ Bitwarden, parolları iş yoldaşlarınızla təhlükəsiz paylaşa bilməyiniz
Nəyə görə Bitwarden-i seçməliyik:
Yüksək səviyyə şifrələmə
-Parollarınız qabaqcıl bir ucdan digərinə kimi şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləcə verilənlərinizin güvənli və gizli qalmasını təmin edir.
+Parollarınız qabaqcıl ucdan-uca şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləcə datanızın güvənli və gizli qalmasını təmin edir.
Daxili parol yaradıcı
Çox istifadə etdiyiniz hər veb sayt üçün təhlükəsizlik tələblərinə görə güclü, unikal və təsadüfi şifrələr yaradın.
diff --git a/apps/browser/tsconfig.json b/apps/browser/tsconfig.json
index ecb2f996e55..357be6c5281 100644
--- a/apps/browser/tsconfig.json
+++ b/apps/browser/tsconfig.json
@@ -16,7 +16,7 @@
"@bitwarden/components": ["../../libs/components/src"],
"@bitwarden/exporter/*": ["../../libs/exporter/src/*"],
"@bitwarden/importer": ["../../libs/importer/src"],
- "@bitwarden/vault": ["../../libs/auth/src"]
+ "@bitwarden/vault": ["../../libs/vault/src"]
},
"useDefineForClassFields": false
},
diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json
index 6f760ef2b1e..69d1c0074fa 100644
--- a/apps/desktop/electron-builder.json
+++ b/apps/desktop/electron-builder.json
@@ -19,7 +19,7 @@
"**/node_modules/@bitwarden/desktop-native/index.js",
"**/node_modules/@bitwarden/desktop-native/desktop_native.${platform}-${arch}*.node"
],
- "electronVersion": "24.8.5",
+ "electronVersion": "25.9.1",
"generateUpdatesFilesForAllChannels": true,
"publish": {
"provider": "generic",
diff --git a/apps/desktop/package.json b/apps/desktop/package.json
index 444753e9206..68d2cc0f87f 100644
--- a/apps/desktop/package.json
+++ b/apps/desktop/package.json
@@ -1,7 +1,7 @@
{
"name": "@bitwarden/desktop",
"description": "A secure and free password manager for all of your devices.",
- "version": "2023.9.2",
+ "version": "2023.9.3",
"keywords": [
"bitwarden",
"password",
@@ -19,8 +19,10 @@
"postinstall": "electron-rebuild",
"start": "cross-env ELECTRON_IS_DEV=0 ELECTRON_NO_UPDATER=1 electron ./build",
"build-native": "cd desktop_native && npm run build",
- "build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"",
+ "build": "concurrently -n Main,Rend,Prel -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\" \"npm run build:preload\"",
"build:dev": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main:dev\" \"npm run build:renderer:dev\"",
+ "build:preload": "cross-env NODE_ENV=production webpack --config webpack.preload.js",
+ "build:preload:watch": "cross-env NODE_ENV=production webpack --config webpack.preload.js --watch",
"build:main": "cross-env NODE_ENV=production webpack --config webpack.main.js",
"build:main:dev": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.main.js",
"build:main:watch": "npm run build-native && cross-env NODE_ENV=development webpack --config webpack.main.js --watch",
diff --git a/apps/desktop/scripts/start.js b/apps/desktop/scripts/start.js
index 19b11125061..388bf09405c 100644
--- a/apps/desktop/scripts/start.js
+++ b/apps/desktop/scripts/start.js
@@ -13,6 +13,11 @@ concurrently(
command: "npm run build:main:watch",
prefixColor: "yellow",
},
+ {
+ name: "Prel",
+ command: "npm run build:preload:watch",
+ prefixColor: "magenta",
+ },
{
name: "Rend",
command: "npm run build:renderer:watch",
diff --git a/apps/desktop/src/app/accounts/settings.component.ts b/apps/desktop/src/app/accounts/settings.component.ts
index 7ccf4aca770..a2a9e71a32b 100644
--- a/apps/desktop/src/app/accounts/settings.component.ts
+++ b/apps/desktop/src/app/accounts/settings.component.ts
@@ -21,7 +21,6 @@ import { DialogService } from "@bitwarden/components";
import { flagEnabled } from "../../platform/flags";
import { ElectronStateService } from "../../platform/services/electron-state.service.abstraction";
-import { isWindowsStore } from "../../utils";
import { SetPinComponent } from "../components/set-pin.component";
@Component({
selector: "app-settings",
@@ -589,7 +588,7 @@ export class SettingsComponent implements OnInit {
this.form.controls.enableBrowserIntegration.setValue(false);
return;
- } else if (isWindowsStore()) {
+ } else if (ipc.platform.isWindowsStore) {
await this.dialogService.openSimpleDialog({
title: { key: "browserIntegrationUnsupportedTitle" },
content: { key: "browserIntegrationWindowsStoreDesc" },
diff --git a/apps/desktop/src/app/app.component.ts b/apps/desktop/src/app/app.component.ts
index 34262c3a309..65ac83b59fd 100644
--- a/apps/desktop/src/app/app.component.ts
+++ b/apps/desktop/src/app/app.component.ts
@@ -10,7 +10,6 @@ import {
} from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { Router } from "@angular/router";
-import { ipcRenderer } from "electron";
import { IndividualConfig, ToastrService } from "ngx-toastr";
import { firstValueFrom, Subject, takeUntil } from "rxjs";
@@ -227,7 +226,7 @@ export class AppComponent implements OnInit, OnDestroy {
this.systemService.cancelProcessReload();
break;
case "reloadProcess":
- ipcRenderer.send("reload-process");
+ ipc.platform.reloadProcess();
break;
case "syncStarted":
break;
diff --git a/apps/desktop/src/app/app.module.ts b/apps/desktop/src/app/app.module.ts
index d14c40854cc..172447822c9 100644
--- a/apps/desktop/src/app/app.module.ts
+++ b/apps/desktop/src/app/app.module.ts
@@ -24,7 +24,6 @@ import { TwoFactorOptionsComponent } from "../auth/two-factor-options.component"
import { TwoFactorComponent } from "../auth/two-factor.component";
import { UpdateTempPasswordComponent } from "../auth/update-temp-password.component";
import { PremiumComponent } from "../vault/app/accounts/premium.component";
-import { PasswordRepromptComponent } from "../vault/app/components/password-reprompt.component";
import { AddEditCustomFieldsComponent } from "../vault/app/vault/add-edit-custom-fields.component";
import { AddEditComponent } from "../vault/app/vault/add-edit.component";
import { AttachmentsComponent } from "../vault/app/vault/attachments.component";
@@ -79,7 +78,6 @@ import { SendComponent } from "./tools/send/send.component";
GeneratorComponent,
PasswordGeneratorHistoryComponent,
PasswordHistoryComponent,
- PasswordRepromptComponent,
PremiumComponent,
RegisterComponent,
RemovePasswordComponent,
diff --git a/apps/desktop/src/app/main.ts b/apps/desktop/src/app/main.ts
index 7d99e48ea22..c22d4eb9e10 100644
--- a/apps/desktop/src/app/main.ts
+++ b/apps/desktop/src/app/main.ts
@@ -1,8 +1,12 @@
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
+import { ipc } from "../preload";
import { isDev } from "../utils";
+// Temporary polyfill for preload script
+(window as any).ipc = ipc;
+
require("../scss/styles.scss");
require("../scss/tailwind.css");
diff --git a/apps/desktop/src/app/services/desktop-theming.service.ts b/apps/desktop/src/app/services/desktop-theming.service.ts
index 21277dfd736..3157ad9f661 100644
--- a/apps/desktop/src/app/services/desktop-theming.service.ts
+++ b/apps/desktop/src/app/services/desktop-theming.service.ts
@@ -1,5 +1,4 @@
import { Injectable } from "@angular/core";
-import { ipcRenderer } from "electron";
import { ThemingService } from "@bitwarden/angular/services/theming/theming.service";
import { ThemeType } from "@bitwarden/common/enums";
@@ -7,12 +6,10 @@ import { ThemeType } from "@bitwarden/common/enums";
@Injectable()
export class DesktopThemingService extends ThemingService {
protected async getSystemTheme(): Promise {
- return await ipcRenderer.invoke("systemTheme");
+ return await ipc.platform.getSystemTheme();
}
protected monitorSystemThemeChanges(): void {
- ipcRenderer.on("systemThemeUpdated", (_event, theme: ThemeType) =>
- this.updateSystemTheme(theme)
- );
+ ipc.platform.onSystemThemeUpdated((theme: ThemeType) => this.updateSystemTheme(theme));
}
}
diff --git a/apps/desktop/src/app/services/services.module.ts b/apps/desktop/src/app/services/services.module.ts
index c6fd0049901..f4841073c9c 100644
--- a/apps/desktop/src/app/services/services.module.ts
+++ b/apps/desktop/src/app/services/services.module.ts
@@ -35,7 +35,6 @@ import { MemoryStorageService } from "@bitwarden/common/platform/services/memory
import { SystemService } from "@bitwarden/common/platform/services/system.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { DialogService } from "@bitwarden/components";
import { LoginGuard } from "../../auth/guards/login.guard";
@@ -52,7 +51,6 @@ import { I18nService } from "../../platform/services/i18n.service";
import { EncryptedMessageHandlerService } from "../../services/encrypted-message-handler.service";
import { NativeMessageHandlerService } from "../../services/native-message-handler.service";
import { NativeMessagingService } from "../../services/native-messaging.service";
-import { PasswordRepromptService } from "../../vault/services/password-reprompt.service";
import { SearchBarService } from "../layout/search/search-bar.service";
import { DesktopFileDownloadService } from "./desktop-file-download.service";
@@ -113,7 +111,6 @@ const RELOAD_CALLBACK = new InjectionToken<() => any>("RELOAD_CALLBACK");
StateServiceAbstraction,
],
},
- { provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService },
{
provide: StateServiceAbstraction,
useClass: ElectronStateService,
diff --git a/apps/desktop/src/auth/two-factor.component.html b/apps/desktop/src/auth/two-factor.component.html
index cd21f91f59e..2b9a1722ee0 100644
--- a/apps/desktop/src/auth/two-factor.component.html
+++ b/apps/desktop/src/auth/two-factor.component.html
@@ -83,7 +83,10 @@ {{ title }}
"
>
-
+
diff --git a/apps/desktop/src/global.d.ts b/apps/desktop/src/global.d.ts
index 1b85bb1b6b1..4d103b2cdef 100644
--- a/apps/desktop/src/global.d.ts
+++ b/apps/desktop/src/global.d.ts
@@ -1 +1,2 @@
declare module "forcefocus";
+declare const ipc: typeof import("./preload").ipc;
diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json
index dad420ca1d1..363159ecbdd 100644
--- a/apps/desktop/src/locales/fa/messages.json
+++ b/apps/desktop/src/locales/fa/messages.json
@@ -476,7 +476,7 @@
"message": "بیشترین حجم پرونده ۵۰۰ مگابایت است."
},
"encryptionKeyMigrationRequired": {
- "message": "Encryption key migration required. Please login through the web vault to update your encryption key."
+ "message": "انتقال کلید رمزگذاری مورد نیاز است. لطفاً از طریق گاوصندوق وب وارد شوید تا کلید رمزگذاری خود را به روز کنید."
},
"editedFolder": {
"message": "پوشه ذخیره شد"
@@ -1078,7 +1078,7 @@
"message": "۱ گیگابایت فضای ذخیرهسازی رمزنگاری شده برای پروندههای پیوست."
},
"premiumSignUpTwoStepOptions": {
- "message": "Proprietary two-step login options such as YubiKey and Duo."
+ "message": "گزینه های ورود اضافی دو مرحله ای مانند YubiKey و Duo."
},
"premiumSignUpReports": {
"message": "گزارشهای بهداشت رمز عبور، سلامت حساب و نقض دادهها برای ایمن نگهداشتن گاوصندوق شما."
@@ -1493,7 +1493,7 @@
"message": "یک گاوصندوق خارج شده درخواست احراز هویت مجدد را برای دسترسی آن میدهد."
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
- "message": "Set up an unlock method to change your vault timeout action."
+ "message": "یک روش بازگشایی برای پایان زمان مجاز تنظیم کنید."
},
"lock": {
"message": "قفل",
@@ -1985,7 +1985,7 @@
"message": "برون ریزی گاوصندوق شخصی"
},
"exportingIndividualVaultDescription": {
- "message": "Only the individual vault items associated with $EMAIL$ will be exported. Organization vault items will not be included. Only vault item information will be exported and will not include associated attachments.",
+ "message": "فقط موارد شخصی گاوصندوق مرتبط با $EMAIL$ برون ریزی خواهند شد. موارد گاوصندوق سازمان شامل نخواهد شد. فقط اطلاعات مورد گاوصندوق برون ریزی خواهد شد و شامل تاریخچه کلمه عبور مرتبط یا پیوست نمیشود.",
"placeholders": {
"email": {
"content": "$1",
@@ -2110,7 +2110,7 @@
"message": "با دستگاه دیگری وارد شوید"
},
"loginInitiated": {
- "message": "Login initiated"
+ "message": "ورود به سیستم آغاز شد"
},
"notificationSentDevice": {
"message": "یک اعلان به دستگاه شما ارسال شده است."
@@ -2250,35 +2250,35 @@
"message": "بهروز رسانی تنظیمات توصیه شده"
},
"deviceApprovalRequired": {
- "message": "Device approval required. Select an approval option below:"
+ "message": "تأیید دستگاه لازم است. یک روش تأیید انتخاب کنید:"
},
"rememberThisDevice": {
- "message": "Remember this device"
+ "message": "این دستگاه را به خاطر بسپار"
},
"uncheckIfPublicDevice": {
- "message": "Uncheck if using a public device"
+ "message": "اگر از دستگاه عمومی استفاده میکنید علامت را بردارید"
},
"approveFromYourOtherDevice": {
- "message": "Approve from your other device"
+ "message": "تأیید با دستگاه دیگرتان"
},
"requestAdminApproval": {
- "message": "Request admin approval"
+ "message": "درخواست تأیید مدیر"
},
"approveWithMasterPassword": {
- "message": "Approve with master password"
+ "message": "تأیید با کلمه عبور اصلی"
},
"region": {
- "message": "Region"
+ "message": "منطقه"
},
"ssoIdentifierRequired": {
- "message": "Organization SSO identifier is required."
+ "message": "شناسه سازمان SSO مورد نیاز است."
},
"eu": {
- "message": "EU",
+ "message": "اروپا",
"description": "European Union"
},
"loggingInOn": {
- "message": "Logging in on"
+ "message": "ورود با"
},
"usDomain": {
"message": "bitwarden.com"
@@ -2287,46 +2287,46 @@
"message": "bitwarden.eu"
},
"selfHostedServer": {
- "message": "self-hosted"
+ "message": "خود میزبان"
},
"accessDenied": {
"message": "دسترسی رد شد. شما اجازه مشاهده این صفحه را ندارید."
},
"accountSuccessfullyCreated": {
- "message": "Account successfully created!"
+ "message": "حساب کاربری با موفقیت ایجاد شد!"
},
"adminApprovalRequested": {
- "message": "Admin approval requested"
+ "message": "تأیید مدیر درخواست شد"
},
"adminApprovalRequestSentToAdmins": {
- "message": "Your request has been sent to your admin."
+ "message": "درخواست شما به مدیرتان فرستاده شد."
},
"youWillBeNotifiedOnceApproved": {
- "message": "You will be notified once approved."
+ "message": "به محض تأیید مطلع خواهید شد."
},
"troubleLoggingIn": {
- "message": "Trouble logging in?"
+ "message": "در ورود مشکلی دارید؟"
},
"loginApproved": {
- "message": "Login approved"
+ "message": "ورود تأیید شد"
},
"userEmailMissing": {
- "message": "User email missing"
+ "message": "ایمیل کاربر وجود ندارد"
},
"deviceTrusted": {
- "message": "Device trusted"
+ "message": "دستگاه مورد اعتماد است"
},
"inputRequired": {
- "message": "Input is required."
+ "message": "ورودی ضروری است."
},
"required": {
- "message": "required"
+ "message": "ضروری"
},
"search": {
- "message": "Search"
+ "message": "جستجو"
},
"inputMinLength": {
- "message": "Input must be at least $COUNT$ characters long.",
+ "message": "ورودی باید حداقل $COUNT$ کاراکتر داشته باشد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2335,7 +2335,7 @@
}
},
"inputMaxLength": {
- "message": "Input must not exceed $COUNT$ characters in length.",
+ "message": "طول ورودی نباید بیش از $COUNT$ کاراکتر باشد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2344,7 +2344,7 @@
}
},
"inputForbiddenCharacters": {
- "message": "The following characters are not allowed: $CHARACTERS$",
+ "message": "کاراکترهای زیر مجاز نیستند: $CHARACTERS$",
"placeholders": {
"characters": {
"content": "$1",
@@ -2353,7 +2353,7 @@
}
},
"inputMinValue": {
- "message": "Input value must be at least $MIN$.",
+ "message": "مقدار ورودی باید حداقل $MIN$ باشد.",
"placeholders": {
"min": {
"content": "$1",
@@ -2362,7 +2362,7 @@
}
},
"inputMaxValue": {
- "message": "Input value must not exceed $MAX$.",
+ "message": "مقدار ورودی نباید از $MAX$ تجاوز کند.",
"placeholders": {
"max": {
"content": "$1",
@@ -2371,17 +2371,17 @@
}
},
"multipleInputEmails": {
- "message": "1 or more emails are invalid"
+ "message": "یک یا چند ایمیل نامعتبر است"
},
"inputTrimValidator": {
- "message": "Input must not contain only whitespace.",
+ "message": "ورودی نباید فقط حاوی فضای خالی باشد.",
"description": "Notification to inform the user that a form's input can't contain only whitespace."
},
"inputEmail": {
- "message": "Input is not an email address."
+ "message": "ورودی یک نشانی ایمیل نیست."
},
"fieldsNeedAttention": {
- "message": "$COUNT$ field(s) above need your attention.",
+ "message": "فیلد $COUNT$ در بالا به توجه شما نیاز دارد.",
"placeholders": {
"count": {
"content": "$1",
@@ -2390,22 +2390,22 @@
}
},
"selectPlaceholder": {
- "message": "-- Select --"
+ "message": "-- انتخاب --"
},
"multiSelectPlaceholder": {
- "message": "-- Type to filter --"
+ "message": "-- برای فیلتر تایپ کنید --"
},
"multiSelectLoading": {
- "message": "Retrieving options..."
+ "message": "در حال بازیابی گزینهها..."
},
"multiSelectNotFound": {
- "message": "No items found"
+ "message": "موردی یافت نشد"
},
"multiSelectClearAll": {
- "message": "Clear all"
+ "message": "پاککردن همه"
},
"plusNMore": {
- "message": "+ $QUANTITY$ more",
+ "message": "+ $QUANTITY$ بیشتر",
"placeholders": {
"quantity": {
"content": "$1",
@@ -2414,9 +2414,9 @@
}
},
"submenu": {
- "message": "Submenu"
+ "message": "زیرمنو"
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "دامنه مستعار"
}
}
diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json
index 7ce3fe92ab4..392dbe4a141 100644
--- a/apps/desktop/src/locales/sr/messages.json
+++ b/apps/desktop/src/locales/sr/messages.json
@@ -2417,6 +2417,6 @@
"message": "Под-мени"
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "Домен алијаса"
}
}
diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json
index 61e50fb0e44..a3489dce44e 100644
--- a/apps/desktop/src/locales/uk/messages.json
+++ b/apps/desktop/src/locales/uk/messages.json
@@ -2417,6 +2417,6 @@
"message": "Підменю"
},
"aliasDomain": {
- "message": "Alias domain"
+ "message": "Псевдонім домену"
}
}
diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json
index 2e24b4d9080..f656607fe60 100644
--- a/apps/desktop/src/locales/zh_CN/messages.json
+++ b/apps/desktop/src/locales/zh_CN/messages.json
@@ -594,7 +594,7 @@
"message": "继续"
},
"enterVerificationCodeApp": {
- "message": "请输入您的身份验证器应用中的 6 位验证码。"
+ "message": "请输入您的验证器应用中的 6 位数验证码。"
},
"enterVerificationCodeEmail": {
"message": "请输入发送给电子邮件 $EMAIL$ 的 6 位数验证码。",
@@ -2083,7 +2083,7 @@
"message": "密码库"
},
"loginWithMasterPassword": {
- "message": "主密码登录"
+ "message": "使用主密码登录"
},
"loggingInAs": {
"message": "正登录为"
diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json
index 819e81b91f5..3e8cf00867b 100644
--- a/apps/desktop/src/locales/zh_TW/messages.json
+++ b/apps/desktop/src/locales/zh_TW/messages.json
@@ -2119,7 +2119,7 @@
"message": "Please make sure your vault is unlocked and Fingerprint phrase matches the other device."
},
"fingerprintPhraseHeader": {
- "message": "Fingerprint phrase"
+ "message": "指紋短語"
},
"needAnotherOption": {
"message": "Log in with device must be set up in the settings of the Bitwarden app. Need another option?"
diff --git a/apps/desktop/src/main/window.main.ts b/apps/desktop/src/main/window.main.ts
index 4ea28c74c5f..e326b9e9e1d 100644
--- a/apps/desktop/src/main/window.main.ts
+++ b/apps/desktop/src/main/window.main.ts
@@ -143,6 +143,7 @@ export class WindowMain {
backgroundColor: await this.getBackgroundColor(),
alwaysOnTop: this.enableAlwaysOnTop,
webPreferences: {
+ // preload: path.join(__dirname, "preload.js"),
spellcheck: false,
nodeIntegration: true,
backgroundThrottling: false,
diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json
index 6112806d32a..bf2744cd873 100644
--- a/apps/desktop/src/package-lock.json
+++ b/apps/desktop/src/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@bitwarden/desktop",
- "version": "2023.9.2",
+ "version": "2023.9.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@bitwarden/desktop",
- "version": "2023.9.2",
+ "version": "2023.9.3",
"license": "GPL-3.0",
"dependencies": {
"@bitwarden/desktop-native": "file:../desktop_native"
diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json
index 3f4163c160a..9421f7a5277 100644
--- a/apps/desktop/src/package.json
+++ b/apps/desktop/src/package.json
@@ -2,7 +2,7 @@
"name": "@bitwarden/desktop",
"productName": "Bitwarden",
"description": "A secure and free password manager for all of your devices.",
- "version": "2023.9.2",
+ "version": "2023.9.3",
"author": "Bitwarden Inc.
(https://bitwarden.com)",
"homepage": "https://bitwarden.com",
"license": "GPL-3.0",
diff --git a/apps/desktop/src/platform/preload.ts b/apps/desktop/src/platform/preload.ts
new file mode 100644
index 00000000000..1ea4f3b91b4
--- /dev/null
+++ b/apps/desktop/src/platform/preload.ts
@@ -0,0 +1,31 @@
+import { ipcRenderer } from "electron";
+
+import { DeviceType, ThemeType } from "@bitwarden/common/enums";
+
+import { isDev, isWindowsStore } from "../utils";
+
+export default {
+ versions: {
+ app: (): Promise => ipcRenderer.invoke("appVersion"),
+ },
+ deviceType: deviceType(),
+ isDev: isDev(),
+ isWindowsStore: isWindowsStore(),
+ reloadProcess: () => ipcRenderer.send("reload-process"),
+
+ getSystemTheme: (): Promise => ipcRenderer.invoke("systemTheme"),
+ onSystemThemeUpdated: (callback: (theme: ThemeType) => void) => {
+ ipcRenderer.on("systemThemeUpdated", (_event, theme: ThemeType) => callback(theme));
+ },
+};
+
+function deviceType(): DeviceType {
+ switch (process.platform) {
+ case "win32":
+ return DeviceType.WindowsDesktop;
+ case "darwin":
+ return DeviceType.MacOsDesktop;
+ default:
+ return DeviceType.LinuxDesktop;
+ }
+}
diff --git a/apps/desktop/src/platform/services/electron-platform-utils.service.ts b/apps/desktop/src/platform/services/electron-platform-utils.service.ts
index dbc35de9311..6c99507b12b 100644
--- a/apps/desktop/src/platform/services/electron-platform-utils.service.ts
+++ b/apps/desktop/src/platform/services/electron-platform-utils.service.ts
@@ -9,31 +9,14 @@ import {
} from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { BiometricMessage, BiometricStorageAction } from "../../types/biometric-message";
-import { isDev, isMacAppStore } from "../../utils";
+import { isMacAppStore } from "../../utils";
import { ClipboardWriteMessage } from "../types/clipboard";
export class ElectronPlatformUtilsService implements PlatformUtilsService {
- private deviceCache: DeviceType = null;
-
constructor(protected i18nService: I18nService, private messagingService: MessagingService) {}
getDevice(): DeviceType {
- if (!this.deviceCache) {
- switch (process.platform) {
- case "win32":
- this.deviceCache = DeviceType.WindowsDesktop;
- break;
- case "darwin":
- this.deviceCache = DeviceType.MacOsDesktop;
- break;
- case "linux":
- default:
- this.deviceCache = DeviceType.LinuxDesktop;
- break;
- }
- }
-
- return this.deviceCache;
+ return ipc.platform.deviceType;
}
getDeviceString(): string {
@@ -82,7 +65,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
}
getApplicationVersion(): Promise {
- return ipcRenderer.invoke("appVersion");
+ return ipc.platform.versions.app();
}
async getApplicationVersionNumber(): Promise {
@@ -92,7 +75,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
// Temporarily restricted to only Windows until https://github.com/electron/electron/pull/28349
// has been merged and an updated electron build is available.
supportsWebAuthn(win: Window): boolean {
- return process.platform === "win32";
+ return this.getDevice() === DeviceType.WindowsDesktop;
}
supportsDuo(): boolean {
@@ -114,7 +97,7 @@ export class ElectronPlatformUtilsService implements PlatformUtilsService {
}
isDev(): boolean {
- return isDev();
+ return ipc.platform.isDev;
}
isSelfHost(): boolean {
diff --git a/apps/desktop/src/preload.ts b/apps/desktop/src/preload.ts
new file mode 100644
index 00000000000..a6ddfdefca5
--- /dev/null
+++ b/apps/desktop/src/preload.ts
@@ -0,0 +1,19 @@
+// import { contextBridge } from "electron";
+import platform from "./platform/preload";
+
+/**
+ * Bitwarden Preload script.
+ *
+ * This file contains the "glue" between the main process and the renderer process. Please ensure
+ * that you have read through the following articles before modifying any preload script.
+ *
+ * https://www.electronjs.org/docs/latest/tutorial/tutorial-preload
+ * https://www.electronjs.org/docs/latest/api/context-bridge
+ */
+
+// Each team owns a subspace of the `ipc` global variable in the renderer.
+export const ipc = {
+ platform,
+};
+
+// contextBridge.exposeInMainWorld("ipc", ipc);
diff --git a/apps/desktop/src/scss/list.scss b/apps/desktop/src/scss/list.scss
index ec56eaa6c88..39e520f7d89 100644
--- a/apps/desktop/src/scss/list.scss
+++ b/apps/desktop/src/scss/list.scss
@@ -120,8 +120,12 @@
.item-content {
display: block;
+ overflow-x: hidden;
.item-title {
display: block;
+ overflow-x: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
.title-badges {
@include themify($themes) {
color: themed("mutedColor");
diff --git a/apps/desktop/src/vault/app/components/password-reprompt.component.html b/apps/desktop/src/vault/app/components/password-reprompt.component.html
deleted file mode 100644
index 1ff853c278c..00000000000
--- a/apps/desktop/src/vault/app/components/password-reprompt.component.html
+++ /dev/null
@@ -1,57 +0,0 @@
-
diff --git a/apps/desktop/src/vault/app/components/password-reprompt.component.ts b/apps/desktop/src/vault/app/components/password-reprompt.component.ts
deleted file mode 100644
index f63da5ed48e..00000000000
--- a/apps/desktop/src/vault/app/components/password-reprompt.component.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { Component } from "@angular/core";
-
-import { PasswordRepromptComponent as BasePasswordRepromptComponent } from "@bitwarden/angular/vault/components/password-reprompt.component";
-
-@Component({
- templateUrl: "password-reprompt.component.html",
-})
-export class PasswordRepromptComponent extends BasePasswordRepromptComponent {}
diff --git a/apps/desktop/src/vault/app/vault/add-edit.component.ts b/apps/desktop/src/vault/app/vault/add-edit.component.ts
index 8a90d6a7e1a..00ae8022b16 100644
--- a/apps/desktop/src/vault/app/vault/add-edit.component.ts
+++ b/apps/desktop/src/vault/app/vault/add-edit.component.ts
@@ -16,8 +16,8 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { DialogService } from "@bitwarden/components";
+import { PasswordRepromptService } from "@bitwarden/vault";
const BroadcasterSubscriptionId = "AddEditComponent";
diff --git a/apps/desktop/src/vault/app/vault/vault.component.ts b/apps/desktop/src/vault/app/vault/vault.component.ts
index 0b419b5088f..7930663499d 100644
--- a/apps/desktop/src/vault/app/vault/vault.component.ts
+++ b/apps/desktop/src/vault/app/vault/vault.component.ts
@@ -22,13 +22,13 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
import { CipherRepromptType } from "@bitwarden/common/vault/enums/cipher-reprompt-type";
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { DialogService } from "@bitwarden/components";
+import { PasswordRepromptService } from "@bitwarden/vault";
import { SearchBarService } from "../../../app/layout/search/search-bar.service";
import { GeneratorComponent } from "../../../app/tools/generator.component";
diff --git a/apps/desktop/src/vault/app/vault/view.component.ts b/apps/desktop/src/vault/app/vault/view.component.ts
index b6bf63d6e64..adb72dbfe33 100644
--- a/apps/desktop/src/vault/app/vault/view.component.ts
+++ b/apps/desktop/src/vault/app/vault/view.component.ts
@@ -23,9 +23,9 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { DialogService } from "@bitwarden/components";
+import { PasswordRepromptService } from "@bitwarden/vault";
const BroadcasterSubscriptionId = "ViewComponent";
diff --git a/apps/desktop/src/vault/services/password-reprompt.service.ts b/apps/desktop/src/vault/services/password-reprompt.service.ts
deleted file mode 100644
index ebff838d5ca..00000000000
--- a/apps/desktop/src/vault/services/password-reprompt.service.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Injectable } from "@angular/core";
-
-import { PasswordRepromptService as BasePasswordRepromptService } from "@bitwarden/angular/vault/services/password-reprompt.service";
-
-import { PasswordRepromptComponent } from "../app/components/password-reprompt.component";
-
-@Injectable()
-export class PasswordRepromptService extends BasePasswordRepromptService {
- component = PasswordRepromptComponent;
-}
diff --git a/apps/desktop/webpack.main.js b/apps/desktop/webpack.main.js
index efd1de20d13..59e043fa12e 100644
--- a/apps/desktop/webpack.main.js
+++ b/apps/desktop/webpack.main.js
@@ -67,7 +67,6 @@ const main = {
],
},
plugins: [
- new CleanWebpackPlugin(),
new CopyWebpackPlugin({
patterns: [
"./src/package.json",
diff --git a/apps/desktop/webpack.preload.js b/apps/desktop/webpack.preload.js
new file mode 100644
index 00000000000..721d0567ca4
--- /dev/null
+++ b/apps/desktop/webpack.preload.js
@@ -0,0 +1,63 @@
+const path = require("path");
+const { merge } = require("webpack-merge");
+const CopyWebpackPlugin = require("copy-webpack-plugin");
+const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");
+const configurator = require("./config/config");
+const { EnvironmentPlugin } = require("webpack");
+
+const NODE_ENV = process.env.NODE_ENV == null ? "development" : process.env.NODE_ENV;
+
+console.log("Preload process config");
+const envConfig = configurator.load(NODE_ENV);
+configurator.log(envConfig);
+
+const common = {
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: "ts-loader",
+ exclude: /node_modules\/(?!(@bitwarden)\/).*/,
+ },
+ ],
+ },
+ plugins: [],
+ resolve: {
+ extensions: [".tsx", ".ts", ".js"],
+ plugins: [new TsconfigPathsPlugin({ configFile: "./tsconfig.json" })],
+ },
+};
+
+const prod = {
+ output: {
+ filename: "[name].js",
+ path: path.resolve(__dirname, "build"),
+ },
+};
+
+const dev = {
+ output: {
+ filename: "[name].js",
+ path: path.resolve(__dirname, "build"),
+ devtoolModuleFilenameTemplate: "[absolute-resource-path]",
+ },
+ devtool: "cheap-source-map",
+};
+
+const main = {
+ mode: NODE_ENV,
+ target: "electron-preload",
+ node: {
+ __dirname: false,
+ __filename: false,
+ },
+ entry: {
+ preload: "./src/preload.ts",
+ },
+ optimization: {
+ minimize: false,
+ },
+};
+
+module.exports = merge(common, NODE_ENV === "development" ? dev : prod, main);
diff --git a/apps/desktop/webpack.renderer.js b/apps/desktop/webpack.renderer.js
index 64eef5729f6..ea1c350c389 100644
--- a/apps/desktop/webpack.renderer.js
+++ b/apps/desktop/webpack.renderer.js
@@ -62,6 +62,8 @@ const common = {
const renderer = {
mode: NODE_ENV,
devtool: "source-map",
+ // TODO: Replace this with web.
+ // target: "web",
target: "electron-renderer",
node: {
__dirname: false,
diff --git a/apps/web/config/selfhosted.json b/apps/web/config/selfhosted.json
index 6b290baa6b5..e16df20ad50 100644
--- a/apps/web/config/selfhosted.json
+++ b/apps/web/config/selfhosted.json
@@ -7,7 +7,7 @@
"port": 8081
},
"flags": {
- "secretsManager": false,
+ "secretsManager": true,
"showPasswordless": true,
"enableCipherKeyEncryption": false
}
diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts
index 7feda23f5cf..1606d86497c 100644
--- a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts
+++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts
@@ -45,10 +45,20 @@ const routes: Routes = [
},
{
path: "tools",
- loadChildren: () =>
- import("../tools/import-export/org-import-export.module").then(
- (m) => m.OrganizationImportExportModule
- ),
+ children: [
+ {
+ path: "import",
+ loadChildren: () =>
+ import("../tools/import/org-import.module").then((m) => m.OrganizationImportModule),
+ },
+ {
+ path: "export",
+ loadChildren: () =>
+ import("../tools/vault-export/org-vault-export.module").then(
+ (m) => m.OrganizationVaultExportModule
+ ),
+ },
+ ],
},
],
},
diff --git a/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts
index cf721098a2c..415bd6516c2 100644
--- a/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/exposed-passwords-report.component.ts
@@ -6,9 +6,9 @@ import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
// eslint-disable-next-line no-restricted-imports
import { ExposedPasswordsReportComponent as BaseExposedPasswordsReportComponent } from "../../../reports/pages/exposed-passwords-report.component";
diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts
similarity index 53%
rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts
rename to apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts
index c0430ab2e07..9b4b4b5c787 100644
--- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export-routing.module.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import-routing.module.ts
@@ -3,14 +3,13 @@ import { RouterModule, Routes } from "@angular/router";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
-import { OrganizationPermissionsGuard } from "../../../../admin-console/organizations/guards/org-permissions.guard";
+import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard";
-import { OrganizationExportComponent } from "./org-export.component";
import { OrganizationImportComponent } from "./org-import.component";
const routes: Routes = [
{
- path: "import",
+ path: "",
component: OrganizationImportComponent,
canActivate: [OrganizationPermissionsGuard],
data: {
@@ -18,18 +17,9 @@ const routes: Routes = [
organizationPermissions: (org: Organization) => org.canAccessImportExport,
},
},
- {
- path: "export",
- component: OrganizationExportComponent,
- canActivate: [OrganizationPermissionsGuard],
- data: {
- titleId: "exportVault",
- organizationPermissions: (org: Organization) => org.canAccessImportExport,
- },
- },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
})
-export class OrganizationImportExportRoutingModule {}
+export class OrganizationImportRoutingModule {}
diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts
similarity index 95%
rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts
rename to apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts
index e8dad8baf41..b514f2bcf38 100644
--- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import.component.ts
@@ -18,11 +18,11 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv
import { DialogService } from "@bitwarden/components";
import { ImportServiceAbstraction } from "@bitwarden/importer";
-import { ImportComponent } from "../../../../tools/import-export/import.component";
+import { ImportComponent } from "../../../../tools/import/import.component";
@Component({
selector: "app-org-import",
- templateUrl: "../../../../tools/import-export/import.component.html",
+ templateUrl: "../../../../tools/import/import.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
export class OrganizationImportComponent extends ImportComponent {
diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts b/apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts
similarity index 81%
rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts
rename to apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts
index e40e961ac98..66a22158e20 100644
--- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-import-export.module.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/import/org-import.module.ts
@@ -15,13 +15,12 @@ import {
import { LooseComponentsModule, SharedModule } from "../../../../shared";
-import { OrganizationExportComponent } from "./org-export.component";
-import { OrganizationImportExportRoutingModule } from "./org-import-export-routing.module";
+import { OrganizationImportRoutingModule } from "./org-import-routing.module";
import { OrganizationImportComponent } from "./org-import.component";
@NgModule({
- imports: [SharedModule, LooseComponentsModule, OrganizationImportExportRoutingModule],
- declarations: [OrganizationImportComponent, OrganizationExportComponent],
+ imports: [SharedModule, LooseComponentsModule, OrganizationImportRoutingModule],
+ declarations: [OrganizationImportComponent],
providers: [
{
provide: ImportApiServiceAbstraction,
@@ -42,4 +41,4 @@ import { OrganizationImportComponent } from "./org-import.component";
},
],
})
-export class OrganizationImportExportModule {}
+export class OrganizationImportModule {}
diff --git a/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts
index 9d62073e066..4cc68b1f9d0 100644
--- a/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/inactive-two-factor-report.component.ts
@@ -6,8 +6,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
// eslint-disable-next-line no-restricted-imports
import { InactiveTwoFactorReportComponent as BaseInactiveTwoFactorReportComponent } from "../../../reports/pages/inactive-two-factor-report.component";
diff --git a/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts
index b410b63e0ff..93652239a11 100644
--- a/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/reused-passwords-report.component.ts
@@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
// eslint-disable-next-line no-restricted-imports
import { ReusedPasswordsReportComponent as BaseReusedPasswordsReportComponent } from "../../../reports/pages/reused-passwords-report.component";
diff --git a/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts
index 53ce0304507..e8fbc0ed5e6 100644
--- a/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/unsecured-websites-report.component.ts
@@ -5,8 +5,8 @@ import { ModalService } from "@bitwarden/angular/services/modal.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
// eslint-disable-next-line no-restricted-imports
import { UnsecuredWebsitesReportComponent as BaseUnsecuredWebsitesReportComponent } from "../../../reports/pages/unsecured-websites-report.component";
diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts
new file mode 100644
index 00000000000..e3e809a550d
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export-routing.module.ts
@@ -0,0 +1,25 @@
+import { NgModule } from "@angular/core";
+import { RouterModule, Routes } from "@angular/router";
+
+import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
+
+import { OrganizationPermissionsGuard } from "../../guards/org-permissions.guard";
+
+import { OrganizationVaultExportComponent } from "./org-vault-export.component";
+
+const routes: Routes = [
+ {
+ path: "",
+ component: OrganizationVaultExportComponent,
+ canActivate: [OrganizationPermissionsGuard],
+ data: {
+ titleId: "exportVault",
+ organizationPermissions: (org: Organization) => org.canAccessImportExport,
+ },
+ },
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+})
+export class OrganizationVaultExportRoutingModule {}
diff --git a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts
similarity index 92%
rename from apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts
rename to apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts
index 9ea1442fd13..ae91150f608 100644
--- a/apps/web/src/app/admin-console/organizations/tools/import-export/org-export.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.component.ts
@@ -14,14 +14,14 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { DialogService } from "@bitwarden/components";
import { VaultExportServiceAbstraction } from "@bitwarden/exporter/vault-export";
-import { ExportComponent } from "../../../../tools/import-export/export.component";
+import { ExportComponent } from "../../../../tools/vault-export/export.component";
@Component({
selector: "app-org-export",
- templateUrl: "../../../../tools/import-export/export.component.html",
+ templateUrl: "../../../../tools/vault-export/export.component.html",
})
// eslint-disable-next-line rxjs-angular/prefer-takeuntil
-export class OrganizationExportComponent extends ExportComponent {
+export class OrganizationVaultExportComponent extends ExportComponent {
constructor(
cryptoService: CryptoService,
i18nService: I18nService,
diff --git a/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts
new file mode 100644
index 00000000000..34b4fa4adba
--- /dev/null
+++ b/apps/web/src/app/admin-console/organizations/tools/vault-export/org-vault-export.module.ts
@@ -0,0 +1,12 @@
+import { NgModule } from "@angular/core";
+
+import { LooseComponentsModule, SharedModule } from "../../../../shared";
+
+import { OrganizationVaultExportRoutingModule } from "./org-vault-export-routing.module";
+import { OrganizationVaultExportComponent } from "./org-vault-export.component";
+
+@NgModule({
+ imports: [SharedModule, LooseComponentsModule, OrganizationVaultExportRoutingModule],
+ declarations: [OrganizationVaultExportComponent],
+})
+export class OrganizationVaultExportModule {}
diff --git a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts
index 68619b27514..540f71d91dc 100644
--- a/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts
+++ b/apps/web/src/app/admin-console/organizations/tools/weak-passwords-report.component.ts
@@ -6,9 +6,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
-import { PasswordRepromptService } from "@bitwarden/common/vault/abstractions/password-reprompt.service";
import { Cipher } from "@bitwarden/common/vault/models/domain/cipher";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
+import { PasswordRepromptService } from "@bitwarden/vault";
// eslint-disable-next-line no-restricted-imports
import { WeakPasswordsReportComponent as BaseWeakPasswordsReportComponent } from "../../../reports/pages/weak-passwords-report.component";
diff --git a/apps/web/src/app/auth/auth.module.ts b/apps/web/src/app/auth/auth.module.ts
new file mode 100644
index 00000000000..056b9f161f9
--- /dev/null
+++ b/apps/web/src/app/auth/auth.module.ts
@@ -0,0 +1,11 @@
+import { NgModule } from "@angular/core";
+
+import { AuthSettingsModule } from "./settings/settings.module";
+
+@NgModule({
+ imports: [AuthSettingsModule],
+ declarations: [],
+ providers: [],
+ exports: [AuthSettingsModule],
+})
+export class AuthModule {}
diff --git a/apps/web/src/app/auth/core/index.ts b/apps/web/src/app/auth/core/index.ts
new file mode 100644
index 00000000000..b2221a94a89
--- /dev/null
+++ b/apps/web/src/app/auth/core/index.ts
@@ -0,0 +1 @@
+export * from "./services";
diff --git a/apps/web/src/app/auth/core/services/index.ts b/apps/web/src/app/auth/core/services/index.ts
new file mode 100644
index 00000000000..4ef20f4b97d
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/index.ts
@@ -0,0 +1 @@
+export * from "./webauthn-login";
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/index.ts b/apps/web/src/app/auth/core/services/webauthn-login/index.ts
new file mode 100644
index 00000000000..10dea636b8d
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/index.ts
@@ -0,0 +1 @@
+export * from "./webauthn-login.service";
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts
new file mode 100644
index 00000000000..ffd0e6cf709
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/request/save-credential.request.ts
@@ -0,0 +1,18 @@
+import { WebauthnLoginAttestationResponseRequest } from "./webauthn-login-attestation-response.request";
+
+/**
+ * Request sent to the server to save a newly created webauthn login credential.
+ */
+export class SaveCredentialRequest {
+ /** The response recieved from the authenticator. This contains the public key */
+ deviceResponse: WebauthnLoginAttestationResponseRequest;
+
+ /** Nickname chosen by the user to identify this credential */
+ name: string;
+
+ /**
+ * Token required by the server to complete the creation.
+ * It contains encrypted information that the server needs to verify the credential.
+ */
+ token: string;
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts
new file mode 100644
index 00000000000..4b33896290c
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-attestation-response.request.ts
@@ -0,0 +1,27 @@
+import { Utils } from "@bitwarden/common/platform/misc/utils";
+
+import { WebauthnLoginAuthenticatorResponseRequest } from "./webauthn-login-authenticator-response.request";
+
+/**
+ * The response recieved from an authentiator after a successful attestation.
+ * This request is used to save newly created webauthn login credentials to the server.
+ */
+export class WebauthnLoginAttestationResponseRequest extends WebauthnLoginAuthenticatorResponseRequest {
+ response: {
+ attestationObject: string;
+ clientDataJson: string;
+ };
+
+ constructor(credential: PublicKeyCredential) {
+ super(credential);
+
+ if (!(credential.response instanceof AuthenticatorAttestationResponse)) {
+ throw new Error("Invalid authenticator response");
+ }
+
+ this.response = {
+ attestationObject: Utils.fromBufferToB64(credential.response.attestationObject),
+ clientDataJson: Utils.fromBufferToB64(credential.response.clientDataJSON),
+ };
+ }
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts
new file mode 100644
index 00000000000..9e332ad5381
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/request/webauthn-login-authenticator-response.request.ts
@@ -0,0 +1,19 @@
+import { Utils } from "@bitwarden/common/platform/misc/utils";
+
+/**
+ * An abstract class that represents responses recieved from the webauthn authenticator.
+ * It contains data that is commonly returned during different types of authenticator interactions.
+ */
+export abstract class WebauthnLoginAuthenticatorResponseRequest {
+ id: string;
+ rawId: string;
+ type: string;
+ extensions: Record;
+
+ constructor(credential: PublicKeyCredential) {
+ this.id = credential.id;
+ this.rawId = Utils.fromBufferToB64(credential.rawId);
+ this.type = credential.type;
+ this.extensions = {}; // Extensions are handled client-side
+ }
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts
new file mode 100644
index 00000000000..ce588207727
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential-create-options.response.ts
@@ -0,0 +1,22 @@
+import { ChallengeResponse } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response";
+import { BaseResponse } from "@bitwarden/common/models/response/base.response";
+
+/**
+ * Options provided by the server to be used during attestation (i.e. creation of a new webauthn credential)
+ */
+export class WebauthnLoginCredentialCreateOptionsResponse extends BaseResponse {
+ /** Options to be provided to the webauthn authenticator */
+ options: ChallengeResponse;
+
+ /**
+ * Contains an encrypted version of the {@link options}.
+ * Used by the server to validate the attestation response of newly created credentials.
+ */
+ token: string;
+
+ constructor(response: unknown) {
+ super(response);
+ this.options = new ChallengeResponse(this.getResponseProperty("options"));
+ this.token = this.getResponseProperty("token");
+ }
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts
new file mode 100644
index 00000000000..7a7f5199e7c
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/response/webauthn-login-credential.response.ts
@@ -0,0 +1,17 @@
+import { BaseResponse } from "@bitwarden/common/models/response/base.response";
+
+/**
+ * A webauthn login credential recieved from the server.
+ */
+export class WebauthnLoginCredentialResponse extends BaseResponse {
+ id: string;
+ name: string;
+ prfSupport: boolean;
+
+ constructor(response: unknown) {
+ super(response);
+ this.id = this.getResponseProperty("id");
+ this.name = this.getResponseProperty("name");
+ this.prfSupport = this.getResponseProperty("prfSupport");
+ }
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts
new file mode 100644
index 00000000000..6dc61563491
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-api.service.ts
@@ -0,0 +1,34 @@
+import { Injectable } from "@angular/core";
+
+import { ApiService } from "@bitwarden/common/abstractions/api.service";
+import { SecretVerificationRequest } from "@bitwarden/common/auth/models/request/secret-verification.request";
+import { ListResponse } from "@bitwarden/common/models/response/list.response";
+
+import { SaveCredentialRequest } from "./request/save-credential.request";
+import { WebauthnLoginCredentialCreateOptionsResponse } from "./response/webauthn-login-credential-create-options.response";
+import { WebauthnLoginCredentialResponse } from "./response/webauthn-login-credential.response";
+
+@Injectable({ providedIn: "root" })
+export class WebauthnLoginApiService {
+ constructor(private apiService: ApiService) {}
+
+ async getCredentialCreateOptions(
+ request: SecretVerificationRequest
+ ): Promise {
+ const response = await this.apiService.send("POST", "/webauthn/options", request, true, true);
+ return new WebauthnLoginCredentialCreateOptionsResponse(response);
+ }
+
+ async saveCredential(request: SaveCredentialRequest): Promise {
+ await this.apiService.send("POST", "/webauthn", request, true, true);
+ return true;
+ }
+
+ getCredentials(): Promise> {
+ return this.apiService.send("GET", "/webauthn", null, true, true);
+ }
+
+ async deleteCredential(credentialId: string, request: SecretVerificationRequest): Promise {
+ await this.apiService.send("POST", `/webauthn/${credentialId}/delete`, request, true, true);
+ }
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts
new file mode 100644
index 00000000000..1e4f1fa7717
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.spec.ts
@@ -0,0 +1,67 @@
+import { mock, MockProxy } from "jest-mock-extended";
+
+import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
+
+import { CredentialCreateOptionsView } from "../../views/credential-create-options.view";
+
+import { WebauthnLoginApiService } from "./webauthn-login-api.service";
+import { WebauthnLoginService } from "./webauthn-login.service";
+
+describe("WebauthnService", () => {
+ let apiService!: MockProxy;
+ let userVerificationService!: MockProxy;
+ let credentials: MockProxy;
+ let webauthnService!: WebauthnLoginService;
+
+ beforeAll(() => {
+ // Polyfill missing class
+ window.PublicKeyCredential = class {} as any;
+ window.AuthenticatorAttestationResponse = class {} as any;
+ apiService = mock();
+ userVerificationService = mock();
+ credentials = mock();
+ webauthnService = new WebauthnLoginService(apiService, userVerificationService, credentials);
+ });
+
+ describe("createCredential", () => {
+ it("should return undefined when navigator.credentials throws", async () => {
+ credentials.create.mockRejectedValue(new Error("Mocked error"));
+ const options = createCredentialCreateOptions();
+
+ const result = await webauthnService.createCredential(options);
+
+ expect(result).toBeUndefined();
+ });
+
+ it("should return credential when navigator.credentials does not throw", async () => {
+ const credential = createDeviceResponse();
+ credentials.create.mockResolvedValue(credential as PublicKeyCredential);
+ const options = createCredentialCreateOptions();
+
+ const result = await webauthnService.createCredential(options);
+
+ expect(result).toBe(credential);
+ });
+ });
+});
+
+function createCredentialCreateOptions(): CredentialCreateOptionsView {
+ return new CredentialCreateOptionsView(Symbol() as any, Symbol() as any);
+}
+
+function createDeviceResponse(): PublicKeyCredential {
+ const credential = {
+ id: "dGVzdA==",
+ rawId: new Uint8Array([0x74, 0x65, 0x73, 0x74]),
+ type: "public-key",
+ response: {
+ attestationObject: new Uint8Array([0, 0, 0]),
+ clientDataJSON: "eyJ0ZXN0IjoidGVzdCJ9",
+ },
+ } as any;
+
+ Object.setPrototypeOf(credential, PublicKeyCredential.prototype);
+ Object.setPrototypeOf(credential.response, AuthenticatorAttestationResponse.prototype);
+
+ return credential;
+}
diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts
new file mode 100644
index 00000000000..c5979f08c61
--- /dev/null
+++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login.service.ts
@@ -0,0 +1,115 @@
+import { Injectable, Optional } from "@angular/core";
+import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, tap } from "rxjs";
+
+import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
+import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
+import { Verification } from "@bitwarden/common/types/verification";
+
+import { CredentialCreateOptionsView } from "../../views/credential-create-options.view";
+import { WebauthnCredentialView } from "../../views/webauth-credential.view";
+
+import { SaveCredentialRequest } from "./request/save-credential.request";
+import { WebauthnLoginAttestationResponseRequest } from "./request/webauthn-login-attestation-response.request";
+import { WebauthnLoginApiService } from "./webauthn-login-api.service";
+
+@Injectable({ providedIn: "root" })
+export class WebauthnLoginService {
+ static readonly MaxCredentialCount = 5;
+
+ private navigatorCredentials: CredentialsContainer;
+ private _refresh$ = new BehaviorSubject(undefined);
+ private _loading$ = new BehaviorSubject(true);
+ private readonly credentials$ = this._refresh$.pipe(
+ tap(() => this._loading$.next(true)),
+ switchMap(() => this.fetchCredentials$()),
+ tap(() => this._loading$.next(false)),
+ shareReplay({ bufferSize: 1, refCount: true })
+ );
+
+ readonly loading$ = this._loading$.asObservable();
+
+ constructor(
+ private apiService: WebauthnLoginApiService,
+ private userVerificationService: UserVerificationService,
+ @Optional() navigatorCredentials?: CredentialsContainer,
+ @Optional() private logService?: LogService
+ ) {
+ // Default parameters don't work when used with Angular DI
+ this.navigatorCredentials = navigatorCredentials ?? navigator.credentials;
+ }
+
+ async getCredentialCreateOptions(
+ verification: Verification
+ ): Promise {
+ const request = await this.userVerificationService.buildRequest(verification);
+ const response = await this.apiService.getCredentialCreateOptions(request);
+ return new CredentialCreateOptionsView(response.options, response.token);
+ }
+
+ async createCredential(
+ credentialOptions: CredentialCreateOptionsView
+ ): Promise {
+ const nativeOptions: CredentialCreationOptions = {
+ publicKey: credentialOptions.options,
+ };
+
+ try {
+ const response = await this.navigatorCredentials.create(nativeOptions);
+ if (!(response instanceof PublicKeyCredential)) {
+ return undefined;
+ }
+ return response;
+ } catch (error) {
+ this.logService?.error(error);
+ return undefined;
+ }
+ }
+
+ async saveCredential(
+ credentialOptions: CredentialCreateOptionsView,
+ deviceResponse: PublicKeyCredential,
+ name: string
+ ) {
+ const request = new SaveCredentialRequest();
+ request.deviceResponse = new WebauthnLoginAttestationResponseRequest(deviceResponse);
+ request.token = credentialOptions.token;
+ request.name = name;
+ await this.apiService.saveCredential(request);
+ this.refresh();
+ }
+
+ /**
+ * List of webauthn credentials saved on the server.
+ *
+ * **Note:**
+ * - Subscribing might trigger a network request if the credentials haven't been fetched yet.
+ * - The observable is shared and will not create unnecessary duplicate requests.
+ * - The observable will automatically re-fetch if the user adds or removes a credential.
+ * - The observable is lazy and will only fetch credentials when subscribed to.
+ * - Don't subscribe to this in the constructor of a long-running service, as it will keep the observable alive.
+ */
+ getCredentials$(): Observable {
+ return this.credentials$;
+ }
+
+ getCredential$(credentialId: string): Observable {
+ return this.credentials$.pipe(
+ map((credentials) => credentials.find((c) => c.id === credentialId)),
+ filter((c) => c !== undefined)
+ );
+ }
+
+ async deleteCredential(credentialId: string, verification: Verification): Promise {
+ const request = await this.userVerificationService.buildRequest(verification);
+ await this.apiService.deleteCredential(credentialId, request);
+ this.refresh();
+ }
+
+ private fetchCredentials$(): Observable {
+ return from(this.apiService.getCredentials()).pipe(map((response) => response.data));
+ }
+
+ private refresh() {
+ this._refresh$.next();
+ }
+}
diff --git a/apps/web/src/app/auth/core/views/credential-create-options.view.ts b/apps/web/src/app/auth/core/views/credential-create-options.view.ts
new file mode 100644
index 00000000000..29efdef5ee6
--- /dev/null
+++ b/apps/web/src/app/auth/core/views/credential-create-options.view.ts
@@ -0,0 +1,5 @@
+import { ChallengeResponse } from "@bitwarden/common/auth/models/response/two-factor-web-authn.response";
+
+export class CredentialCreateOptionsView {
+ constructor(readonly options: ChallengeResponse, readonly token: string) {}
+}
diff --git a/apps/web/src/app/auth/core/views/webauth-credential.view.ts b/apps/web/src/app/auth/core/views/webauth-credential.view.ts
new file mode 100644
index 00000000000..ff5a9c692df
--- /dev/null
+++ b/apps/web/src/app/auth/core/views/webauth-credential.view.ts
@@ -0,0 +1,5 @@
+export class WebauthnCredentialView {
+ id: string;
+ name: string;
+ prfSupport: boolean;
+}
diff --git a/apps/web/src/app/auth/index.ts b/apps/web/src/app/auth/index.ts
new file mode 100644
index 00000000000..fb09223bd9e
--- /dev/null
+++ b/apps/web/src/app/auth/index.ts
@@ -0,0 +1,2 @@
+export * from "./auth.module";
+export * from "./core";
diff --git a/apps/web/src/app/auth/settings/change-password.component.html b/apps/web/src/app/auth/settings/change-password.component.html
index b3ad78168d9..37a4ad5b59a 100644
--- a/apps/web/src/app/auth/settings/change-password.component.html
+++ b/apps/web/src/app/auth/settings/change-password.component.html
@@ -6,7 +6,14 @@ {{ "changeMasterPassword" | i18n }}
-