From b35b89bb668e8bb818dea631563d3848718f7664 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:46:28 +0000 Subject: [PATCH 01/31] Autosync the updated translations (#9685) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/web/src/locales/af/messages.json | 61 +++++++++++++---- apps/web/src/locales/ar/messages.json | 37 +++++++++++ apps/web/src/locales/az/messages.json | 37 +++++++++++ apps/web/src/locales/be/messages.json | 37 +++++++++++ apps/web/src/locales/bg/messages.json | 37 +++++++++++ apps/web/src/locales/bn/messages.json | 37 +++++++++++ apps/web/src/locales/bs/messages.json | 37 +++++++++++ apps/web/src/locales/ca/messages.json | 37 +++++++++++ apps/web/src/locales/cs/messages.json | 37 +++++++++++ apps/web/src/locales/cy/messages.json | 37 +++++++++++ apps/web/src/locales/da/messages.json | 37 +++++++++++ apps/web/src/locales/de/messages.json | 37 +++++++++++ apps/web/src/locales/el/messages.json | 37 +++++++++++ apps/web/src/locales/en_GB/messages.json | 37 +++++++++++ apps/web/src/locales/en_IN/messages.json | 37 +++++++++++ apps/web/src/locales/eo/messages.json | 37 +++++++++++ apps/web/src/locales/es/messages.json | 37 +++++++++++ apps/web/src/locales/et/messages.json | 37 +++++++++++ apps/web/src/locales/eu/messages.json | 37 +++++++++++ apps/web/src/locales/fa/messages.json | 37 +++++++++++ apps/web/src/locales/fi/messages.json | 37 +++++++++++ apps/web/src/locales/fil/messages.json | 37 +++++++++++ apps/web/src/locales/fr/messages.json | 37 +++++++++++ apps/web/src/locales/gl/messages.json | 37 +++++++++++ apps/web/src/locales/he/messages.json | 37 +++++++++++ apps/web/src/locales/hi/messages.json | 37 +++++++++++ apps/web/src/locales/hr/messages.json | 37 +++++++++++ apps/web/src/locales/hu/messages.json | 37 +++++++++++ apps/web/src/locales/id/messages.json | 37 +++++++++++ apps/web/src/locales/it/messages.json | 37 +++++++++++ apps/web/src/locales/ja/messages.json | 37 +++++++++++ apps/web/src/locales/ka/messages.json | 37 +++++++++++ apps/web/src/locales/km/messages.json | 37 +++++++++++ apps/web/src/locales/kn/messages.json | 37 +++++++++++ apps/web/src/locales/ko/messages.json | 37 +++++++++++ apps/web/src/locales/lv/messages.json | 37 +++++++++++ apps/web/src/locales/ml/messages.json | 37 +++++++++++ apps/web/src/locales/mr/messages.json | 37 +++++++++++ apps/web/src/locales/my/messages.json | 37 +++++++++++ apps/web/src/locales/nb/messages.json | 37 +++++++++++ apps/web/src/locales/ne/messages.json | 37 +++++++++++ apps/web/src/locales/nl/messages.json | 37 +++++++++++ apps/web/src/locales/nn/messages.json | 37 +++++++++++ apps/web/src/locales/or/messages.json | 37 +++++++++++ apps/web/src/locales/pl/messages.json | 37 +++++++++++ apps/web/src/locales/pt_BR/messages.json | 85 +++++++++++++++++------- apps/web/src/locales/pt_PT/messages.json | 37 +++++++++++ apps/web/src/locales/ro/messages.json | 37 +++++++++++ apps/web/src/locales/ru/messages.json | 37 +++++++++++ apps/web/src/locales/si/messages.json | 37 +++++++++++ apps/web/src/locales/sk/messages.json | 37 +++++++++++ apps/web/src/locales/sl/messages.json | 37 +++++++++++ apps/web/src/locales/sr/messages.json | 45 +++++++++++-- apps/web/src/locales/sr_CS/messages.json | 37 +++++++++++ apps/web/src/locales/sv/messages.json | 37 +++++++++++ apps/web/src/locales/te/messages.json | 37 +++++++++++ apps/web/src/locales/th/messages.json | 37 +++++++++++ apps/web/src/locales/tr/messages.json | 37 +++++++++++ apps/web/src/locales/uk/messages.json | 37 +++++++++++ apps/web/src/locales/vi/messages.json | 37 +++++++++++ apps/web/src/locales/zh_CN/messages.json | 37 +++++++++++ apps/web/src/locales/zh_TW/messages.json | 37 +++++++++++ 62 files changed, 2334 insertions(+), 40 deletions(-) diff --git a/apps/web/src/locales/af/messages.json b/apps/web/src/locales/af/messages.json index d33f916966..de2e0ceea8 100644 --- a/apps/web/src/locales/af/messages.json +++ b/apps/web/src/locales/af/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Skep rekening" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Nuut hier rond?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "U het niks gekies nie." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Deur hierdie kassie af te merk stem u in tot die volgende:" }, @@ -4267,7 +4288,7 @@ "message": "Gedeaktiveer" }, "revoked": { - "message": "Revoked" + "message": "Herroep" }, "sendLink": { "message": "Send-skakel", @@ -4323,7 +4344,7 @@ "description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated." }, "downloadAttachments": { - "message": "Download attachments" + "message": "Laai aanhegsels af" }, "sendAccessUnavailable": { "message": "The Send you are trying to access does not exist or is no longer available.", @@ -4937,10 +4958,10 @@ "message": "Verwyder gebruikers" }, "revokeUsers": { - "message": "Revoke users" + "message": "Herroep gebruikers" }, "restoreUsers": { - "message": "Restore users" + "message": "Stel gebruikers terug" }, "error": { "message": "Fout" @@ -5016,7 +5037,7 @@ "message": "Voeg bestaande organisasie toe" }, "addNewOrganization": { - "message": "Add new organization" + "message": "Voeg nuwe organisasie toe" }, "myProvider": { "message": "My aanbieder" @@ -5089,7 +5110,7 @@ "message": "U hoofwagwoord voldoen nie aan hierdie organisasie se beleidsvereistes nie. Om by die organisasie aan te sluit moet u u hoofwagwoord nóú bywerk. Deur voort te gaan word u uit u huidige sessie geteken, waarna u weer sal moet aanteken. Aktiewe sessies op ander toestelle kan vir tot ’n uur steeds aktief bly." }, "updateWeakMasterPasswordWarning": { - "message": "Your master password does not meet one or more of your organization policies. In order to access the vault, you must update your master password now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." + "message": "U hoofwagwoord voldoen nie aan een of meer van die organisasiebeleide nie. Om toegang tot die kluis te kry, moet u nou u hoofwagwoord bywerk. Deur voort te gaan sal u van u huidige sessie afgeteken word, en u sal weer moet aanteken. Aktiewe sessies op ander toestelle kan vir tot een uur aktief bly." }, "maximumVaultTimeout": { "message": "Kluis-uittel" @@ -5140,7 +5161,7 @@ } }, "vaultTimeoutActionPolicyInEffect": { - "message": "Your organization policies have set your vault timeout action to $ACTION$.", + "message": "U organisasie se beleid het u kluisuittelaksie na $ACTION$ gestel.", "placeholders": { "action": { "content": "$1", @@ -5149,16 +5170,16 @@ } }, "customVaultTimeout": { - "message": "Custom vault timeout" + "message": "Pasgemaakte kluisuittel" }, "vaultTimeoutToLarge": { "message": "U kluisuittelling oorskry die beperking wat deur u organisasie daargestel is." }, "vaultCustomTimeoutMinimum": { - "message": "Minimum custom timeout is 1 minute." + "message": "Minimum pasgemaakte uittel is 1 minuut." }, "vaultTimeoutRangeError": { - "message": "Vault timeout is not within allowed range." + "message": "Kluisuittel is nie binne toegelate omvang nie." }, "disablePersonalVaultExport": { "message": "Deaktiveer uitstuur van persoonlike kluis" @@ -5937,7 +5958,7 @@ } }, "forwarderNoDomain": { - "message": "Invalid $SERVICENAME$ domain.", + "message": "Ongeldige $SERVICENAME$-domein.", "description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.", "placeholders": { "servicename": { @@ -5947,7 +5968,7 @@ } }, "forwarderNoUrl": { - "message": "Invalid $SERVICENAME$ url.", + "message": "Ongeldige $SERVICENAME$-url.", "description": "Displayed when the url of the forwarding service wasn't supplied.", "placeholders": { "servicename": { @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Stel Github Actions op" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Stel GitLab CI/CD op" }, "setUpAnsible": { "message": "Stel Ansible op" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ar/messages.json b/apps/web/src/locales/ar/messages.json index 0d083802d6..9a0be0f558 100644 --- a/apps/web/src/locales/ar/messages.json +++ b/apps/web/src/locales/ar/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "إنشاء حساب" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "هل أنت جديد هنا؟" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/az/messages.json b/apps/web/src/locales/az/messages.json index ac30934a40..c302571ab8 100644 --- a/apps/web/src/locales/az/messages.json +++ b/apps/web/src/locales/az/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Hesab yarat" }, + "setAStrongPassword": { + "message": "Güclü bir parol təyin et" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Bir parol təyin edərək hesabınızı yaratmağı başa çatdırın" + }, "newAroundHere": { "message": "Burada yenisiniz?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Heç nə seçmədiniz." }, + "receiveMarketingEmails": { + "message": "Elanlar, məsləhətlər və araşdırma fürsətləri üçün Bitwarden-dən e-poçt alın." + }, + "unsubscribe": { + "message": "Abunəlikdən çıx" + }, + "atAnyTime": { + "message": "istənilən vaxt." + }, + "byContinuingYouAgreeToThe": { + "message": "Davam edərək, bunlarla razılaşırsınız" + }, + "and": { + "message": "və" + }, "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Github Actions qur" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "GitLab CI/CD qur" }, "setUpAnsible": { "message": "Ansible qur" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "C# repozitoriyasına bax" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Bu e-poçt ünvanı, bu provayderə aid bütün fakturaları alacaq", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Tarix" + }, + "exportClientReport": { + "message": "Müştəri hesabatını xaricə köçür" + }, + "invoiceNumberHeader": { + "message": "Faktura nömrəsi", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/be/messages.json b/apps/web/src/locales/be/messages.json index 42c4c49649..794acdf1a3 100644 --- a/apps/web/src/locales/be/messages.json +++ b/apps/web/src/locales/be/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Стварыць уліковы запіс" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Упершыню тут?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Вы пакуль нічога не выбралі." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ставячы гэты сцяжок, вы пагаджаецеся з наступным:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/bg/messages.json b/apps/web/src/locales/bg/messages.json index 9de52f8744..17a14e0f40 100644 --- a/apps/web/src/locales/bg/messages.json +++ b/apps/web/src/locales/bg/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Създаване на абонамент" }, + "setAStrongPassword": { + "message": "Използвайте сложна парола" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завършете регистрацията си като зададете парола" + }, "newAroundHere": { "message": "За пръв път ли сте тук?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Не сте избрали нищо." }, + "receiveMarketingEmails": { + "message": "Получавайте е-писма от Битоурден за новини, съвети и възможности за проучвания." + }, + "unsubscribe": { + "message": "Отписване" + }, + "atAnyTime": { + "message": "по всяко време." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако продължите, Вие се съгласявате с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следните:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Настройка на действия в Github" }, + "setUpKubernetes": { + "message": "Настройка на Kubernetes" + }, "setUpGitlabCICD": { "message": "Настройка на GitLab CI/CD" }, "setUpAnsible": { "message": "Настройка на Ansible" }, + "rustSDKRepo": { + "message": "Преглед на хранилището за Rust" + }, "cSharpSDKRepo": { "message": "Преглед на хранилището за C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "На този адрес ще бъдат изпращани всички фактури свързани с този доставчик", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Дата" + }, + "exportClientReport": { + "message": "Изнасяне на клиентската справка" + }, + "invoiceNumberHeader": { + "message": "Номер на фактура", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/bn/messages.json b/apps/web/src/locales/bn/messages.json index d23a4fe90a..d2a29c6c55 100644 --- a/apps/web/src/locales/bn/messages.json +++ b/apps/web/src/locales/bn/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "অ্যাকাউন্ট তৈরি" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/bs/messages.json b/apps/web/src/locales/bs/messages.json index a18b4afce8..2a9539dd20 100644 --- a/apps/web/src/locales/bs/messages.json +++ b/apps/web/src/locales/bs/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ca/messages.json b/apps/web/src/locales/ca/messages.json index 8a6337f952..d44250b2d3 100644 --- a/apps/web/src/locales/ca/messages.json +++ b/apps/web/src/locales/ca/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Crea un compte" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Nou per ací?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "No heu seleccionat res." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Configura les accions de Github" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Configura GitLab CI/CD" }, "setUpAnsible": { "message": "Configura Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "Veure el repositori C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/cs/messages.json b/apps/web/src/locales/cs/messages.json index bdfc78b078..ce0c8dce97 100644 --- a/apps/web/src/locales/cs/messages.json +++ b/apps/web/src/locales/cs/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Vytvořit účet" }, + "setAStrongPassword": { + "message": "Nastavit hlavní heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Dokončete vytváření účtu nastavením hesla" + }, "newAroundHere": { "message": "Jste tu noví?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nevybrali jste žádné položky." }, + "receiveMarketingEmails": { + "message": "Získejte e-maily od Bitwardenu pro oznámení, poradenství a výzkumné příležitosti." + }, + "unsubscribe": { + "message": "Odhlásit odběr" + }, + "atAnyTime": { + "message": "kdykoli." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračováním souhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasíte s následujícím:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Nastavit akce GitHubu" }, + "setUpKubernetes": { + "message": "Nastavit Kubernetes" + }, "setUpGitlabCICD": { "message": "Nastavit GitLab CI/CD" }, "setUpAnsible": { "message": "Nastavit Ansible" }, + "rustSDKRepo": { + "message": "Zobrazit repozitář Rust" + }, "cSharpSDKRepo": { "message": "Zobrazit repozitář C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Tato e-mailová adresa obdrží všechny faktury vztahující se k tomuto poskytovateli", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Datum" + }, + "exportClientReport": { + "message": "Exportovat hlášení klienta" + }, + "invoiceNumberHeader": { + "message": "Číslo faktury", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/cy/messages.json b/apps/web/src/locales/cy/messages.json index 47560c8661..303601ce0c 100644 --- a/apps/web/src/locales/cy/messages.json +++ b/apps/web/src/locales/cy/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/da/messages.json b/apps/web/src/locales/da/messages.json index 2027f4a64b..be798150ef 100644 --- a/apps/web/src/locales/da/messages.json +++ b/apps/web/src/locales/da/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Opret konto" }, + "setAStrongPassword": { + "message": "Indstil en stærk adgangskode" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Afslut kontooprettelsen med at indstille en adgangskode" + }, "newAroundHere": { "message": "Ny her?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Du har ikke valgt noget." }, + "receiveMarketingEmails": { + "message": "Få e-mails fra Bitwarden om annonceringer, råd og forskningsmuligheder." + }, + "unsubscribe": { + "message": "Afmeld" + }, + "atAnyTime": { + "message": "til enhver tid." + }, + "byContinuingYouAgreeToThe": { + "message": "Ved at fortsætte, accepterer du" + }, + "and": { + "message": "og" + }, "acceptPolicies": { "message": "Ved at markere dette felt accepterer du følgende:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Opsæt Github-handlinger" }, + "setUpKubernetes": { + "message": "Opsæt Kubernetes" + }, "setUpGitlabCICD": { "message": "Opsæt GitLab CI/CD" }, "setUpAnsible": { "message": "Opsæt Ansible" }, + "rustSDKRepo": { + "message": "Vis Ruby-repo" + }, "cSharpSDKRepo": { "message": "Vis C#-repo" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Denne e-mailadresse vil modtage alle fakturaer vedr. denne udbyder", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Dato" + }, + "exportClientReport": { + "message": "Eksportér klientrapport" + }, + "invoiceNumberHeader": { + "message": "Fakturanummer", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/de/messages.json b/apps/web/src/locales/de/messages.json index aa7c3d8dae..ea4dc4d292 100644 --- a/apps/web/src/locales/de/messages.json +++ b/apps/web/src/locales/de/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Konto erstellen" }, + "setAStrongPassword": { + "message": "Ein starkes Passwort festlegen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Schließe die Erstellung deines Kontos ab, indem du ein Passwort festlegst" + }, "newAroundHere": { "message": "Neu hier?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Sie haben keine Auswahl getroffen." }, + "receiveMarketingEmails": { + "message": "Erhalte E-Mails von Bitwarden für Ankündigungen, Ratschläge und Forschungsmöglichkeiten." + }, + "unsubscribe": { + "message": "Deabonnieren" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklärst du dich mit Folgendem einverstanden:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "GitHub Actions einrichten" }, + "setUpKubernetes": { + "message": "Kubernetes einrichten" + }, "setUpGitlabCICD": { "message": "GitLab CI/CD einrichten" }, "setUpAnsible": { "message": "Ansible einrichten" }, + "rustSDKRepo": { + "message": "Rust-Repository anzeigen" + }, "cSharpSDKRepo": { "message": "C#-Repository anzeigen" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Diese E-Mail-Adresse wird alle Rechnungen erhalten, die diesen Anbieter betreffen", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Datum" + }, + "exportClientReport": { + "message": "Kundenbericht exportieren" + }, + "invoiceNumberHeader": { + "message": "Rechnungsnummer", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/el/messages.json b/apps/web/src/locales/el/messages.json index 80465e702e..b22ae542dc 100644 --- a/apps/web/src/locales/el/messages.json +++ b/apps/web/src/locales/el/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Δημιουργία Λογαριασμού" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Νέος/α στα μέρη μας;" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Δεν έχετε επιλέξει τίποτα." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/en_GB/messages.json b/apps/web/src/locales/en_GB/messages.json index f817bc1358..f88aece65a 100644 --- a/apps/web/src/locales/en_GB/messages.json +++ b/apps/web/src/locales/en_GB/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/en_IN/messages.json b/apps/web/src/locales/en_IN/messages.json index 9d2d8ed7b3..fb6fe9f79c 100644 --- a/apps/web/src/locales/en_IN/messages.json +++ b/apps/web/src/locales/en_IN/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/eo/messages.json b/apps/web/src/locales/eo/messages.json index 26c230a38d..5bef89b7dd 100644 --- a/apps/web/src/locales/eo/messages.json +++ b/apps/web/src/locales/eo/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Krei konton" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Vi elektis nenion." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Markante ĉi tiun keston vi konsentas pri jeno:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/es/messages.json b/apps/web/src/locales/es/messages.json index b0d6cbc70a..13ebcc0562 100644 --- a/apps/web/src/locales/es/messages.json +++ b/apps/web/src/locales/es/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Crear cuenta" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "¿Nuevo por aquí?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "No has seleccionado nada." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Al seleccionar esta casilla, acepta lo siguiente:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/et/messages.json b/apps/web/src/locales/et/messages.json index d19188f1ac..19ad2e8d03 100644 --- a/apps/web/src/locales/et/messages.json +++ b/apps/web/src/locales/et/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Konto loomine" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Midagi pole valitud." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/eu/messages.json b/apps/web/src/locales/eu/messages.json index fa334f5aba..e6a46bf090 100644 --- a/apps/web/src/locales/eu/messages.json +++ b/apps/web/src/locales/eu/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Sortu kontua" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Berria hemendik?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Ez duzu ezer aukeratu." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Laukitxo hau markatzean, honakoa onartzen duzu:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/fa/messages.json b/apps/web/src/locales/fa/messages.json index ec60759974..511cf05e91 100644 --- a/apps/web/src/locales/fa/messages.json +++ b/apps/web/src/locales/fa/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "ایجاد حساب کاربری" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "اینجا تازه واردی؟" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "شما چیزی را انتخاب نکرده اید." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "با علامت زدن این کادر با موارد زیر موافقت می‌کنید:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/fi/messages.json b/apps/web/src/locales/fi/messages.json index 162f436b20..fde4ebfd4e 100644 --- a/apps/web/src/locales/fi/messages.json +++ b/apps/web/src/locales/fi/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Luo uusi tili" }, + "setAStrongPassword": { + "message": "Aseta vahva salasana" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Viimeistele tilin luonti asettamalla salasana" + }, "newAroundHere": { "message": "Oletko uusi täällä?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Et ole valinnut mitään." }, + "receiveMarketingEmails": { + "message": "Vastaanota Bitwardenilta uutiskirjeitä julkaisuista, tukiresursseista ja tutkimusmahdollisuuksista." + }, + "unsubscribe": { + "message": "Lopeta tilaus" + }, + "atAnyTime": { + "message": "milloin tahansa." + }, + "byContinuingYouAgreeToThe": { + "message": "Jatkaessasi hyväksyt" + }, + "and": { + "message": "ja" + }, "acceptPolicies": { "message": "Valitsemalla tämän hyväksyt seuraavat:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Määritä GitHub Actions" }, + "setUpKubernetes": { + "message": "Määritä Kubernetes" + }, "setUpGitlabCICD": { "message": "Määritä GitLab CI/CD" }, "setUpAnsible": { "message": "Määritä Ansible" }, + "rustSDKRepo": { + "message": "Näytä Rust-arkisto" + }, "cSharpSDKRepo": { "message": "Näytä C#-arkisto" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Tämä sähköpostiosoite vastaanottaa kaikki tähän palveluntarjoajaan liittyvät laskut", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Päiväys" + }, + "exportClientReport": { + "message": "Vie pääteraportti" + }, + "invoiceNumberHeader": { + "message": "Laskun numero", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/fil/messages.json b/apps/web/src/locales/fil/messages.json index 197dd34d3a..ec72cb7de6 100644 --- a/apps/web/src/locales/fil/messages.json +++ b/apps/web/src/locales/fil/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Gumawa ng account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Bago rito?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Wala kang pinili." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Sa pamamagitan ng pag-tsek sa kahon na ito ay sumasang-ayon ka sa sumusunod:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/fr/messages.json b/apps/web/src/locales/fr/messages.json index ecf1d323f3..ba9c2ba8dd 100644 --- a/apps/web/src/locales/fr/messages.json +++ b/apps/web/src/locales/fr/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Créez un compte" }, + "setAStrongPassword": { + "message": "Définir un mot de passe fort" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Terminer la création de votre compte en définissant un mot de passe" + }, "newAroundHere": { "message": "Vous êtes nouveau ici ?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Vous n'avez rien sélectionné." }, + "receiveMarketingEmails": { + "message": "Recevez des courriels de Bitwarden pour des annonces, des conseils et des opportunités de recherche." + }, + "unsubscribe": { + "message": "Désabonnez-vous" + }, + "atAnyTime": { + "message": "à tout moment." + }, + "byContinuingYouAgreeToThe": { + "message": "En continuant, vous acceptez les" + }, + "and": { + "message": "et" + }, "acceptPolicies": { "message": "En cochant cette case vous acceptez ce qui suit :" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Configurer Github Actions" }, + "setUpKubernetes": { + "message": "Configurer Kubernetes" + }, "setUpGitlabCICD": { "message": "Configurer GitLab CI/CD" }, "setUpAnsible": { "message": "Configurer Ansible" }, + "rustSDKRepo": { + "message": "Afficher le dépôt Rust" + }, "cSharpSDKRepo": { "message": "Afficher le dépôt C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Cette adresse courriel recevra toutes les factures relatives à ce fournisseur", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Exporter le rapport client" + }, + "invoiceNumberHeader": { + "message": "Numéro de facture", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/gl/messages.json b/apps/web/src/locales/gl/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/gl/messages.json +++ b/apps/web/src/locales/gl/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/he/messages.json b/apps/web/src/locales/he/messages.json index a10ee46547..fd2e1e9935 100644 --- a/apps/web/src/locales/he/messages.json +++ b/apps/web/src/locales/he/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "צור חשבון" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "לא בחרת כלום." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/hi/messages.json b/apps/web/src/locales/hi/messages.json index 01a719bfb3..35f1a76ec4 100644 --- a/apps/web/src/locales/hi/messages.json +++ b/apps/web/src/locales/hi/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "खाता बनाएँ" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/hr/messages.json b/apps/web/src/locales/hr/messages.json index df6f3aa738..fcb2fd8ec2 100644 --- a/apps/web/src/locales/hr/messages.json +++ b/apps/web/src/locales/hr/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Stvori račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Novi korisnik?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Ništa nije odabrano." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/hu/messages.json b/apps/web/src/locales/hu/messages.json index 05f4221ab1..dccce14fa7 100644 --- a/apps/web/src/locales/hu/messages.json +++ b/apps/web/src/locales/hu/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Fiók létrehozása" }, + "setAStrongPassword": { + "message": "Erős jelszó beállítása" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "A fiók létrehozásának befejezése jelszó beállításával" + }, "newAroundHere": { "message": "Új felhasználó vagyunk?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nincs kiválasztva semmi." }, + "receiveMarketingEmails": { + "message": "Emaileket kaphatunk a Bitwardentől bejelentésekről, tanácsokról és kutatási lehetőségekről." + }, + "unsubscribe": { + "message": "Leiratkozás" + }, + "atAnyTime": { + "message": "bármikor." + }, + "byContinuingYouAgreeToThe": { + "message": "A folytatással elfogadjuk" + }, + "and": { + "message": "és" + }, "acceptPolicies": { "message": "A doboz bejelölésével elfogadjuk a következőket:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Kubernetes beüzemelése" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "Rust tár megtekintése" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Erre az email címre érkezik az ehhez a szolgáltatóhoz kapcsolódó összes számla.", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Dátum" + }, + "exportClientReport": { + "message": "Ügyfél jelentés exportálás" + }, + "invoiceNumberHeader": { + "message": "Számlaszám", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/id/messages.json b/apps/web/src/locales/id/messages.json index bdb5d731d7..64032b48fa 100644 --- a/apps/web/src/locales/id/messages.json +++ b/apps/web/src/locales/id/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Buat Akun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Pengguna baru?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Anda belum memilih apa pun." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dengan mencentang kotak ini, anda menyetujui yang berikut:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/it/messages.json b/apps/web/src/locales/it/messages.json index 05bb5c7a2d..00ae095c3e 100644 --- a/apps/web/src/locales/it/messages.json +++ b/apps/web/src/locales/it/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Crea account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Nuovo da queste parti?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Non hai selezionato nulla." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Selezionando la casella accetti quanto segue:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Configura GitHub Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Configura GitLab CI/CD" }, "setUpAnsible": { "message": "Configura Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "Visualizza la repository C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ja/messages.json b/apps/web/src/locales/ja/messages.json index 8634304a93..3b5645cc82 100644 --- a/apps/web/src/locales/ja/messages.json +++ b/apps/web/src/locales/ja/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "アカウントの作成" }, + "setAStrongPassword": { + "message": "強力なパスワードを設定する" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "パスワードを設定してアカウントの作成を完了してください" + }, "newAroundHere": { "message": "初めてですか?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "何も選択されていません。" }, + "receiveMarketingEmails": { + "message": "Bitwarden からのお知らせ、アドバイス、アンケート調査等のメールを受信します。" + }, + "unsubscribe": { + "message": "配信停止" + }, + "atAnyTime": { + "message": "はいつでもできます。" + }, + "byContinuingYouAgreeToThe": { + "message": "続行すると以下に同意したものとみなします:" + }, + "and": { + "message": "と" + }, "acceptPolicies": { "message": "以下に同意しチェックします:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Github アクションを設定" }, + "setUpKubernetes": { + "message": "Kubernetes を設定" + }, "setUpGitlabCICD": { "message": "GitLab CI/CD の設定" }, "setUpAnsible": { "message": "Ansible を設定" }, + "rustSDKRepo": { + "message": "Rust リポジトリを表示" + }, "cSharpSDKRepo": { "message": "C# リポジトリを表示" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "このメールアドレスは、このプロバイダに関連するすべての請求書を受信します", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "日付" + }, + "exportClientReport": { + "message": "クライアントレポートをエクスポート" + }, + "invoiceNumberHeader": { + "message": "請求書番号", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ka/messages.json b/apps/web/src/locales/ka/messages.json index db176fa8bb..a7db624733 100644 --- a/apps/web/src/locales/ka/messages.json +++ b/apps/web/src/locales/ka/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "ანგარიშის შექმნა" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "ახალი ხართ აქა?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/km/messages.json b/apps/web/src/locales/km/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/km/messages.json +++ b/apps/web/src/locales/km/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/kn/messages.json b/apps/web/src/locales/kn/messages.json index fdb5c19ce7..f360bc0a32 100644 --- a/apps/web/src/locales/kn/messages.json +++ b/apps/web/src/locales/kn/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "ಖಾತೆ ತೆರೆ" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "ನೀವು ಯಾವುದನ್ನೂ ಆಯ್ಕೆ ಮಾಡಿಲ್ಲ." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ko/messages.json b/apps/web/src/locales/ko/messages.json index c91fe4f7d2..ab14ff1d6c 100644 --- a/apps/web/src/locales/ko/messages.json +++ b/apps/web/src/locales/ko/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "계정 만들기" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "새로 찾아오셨나요?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "아무것도 선택하지 않았습니다." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/lv/messages.json b/apps/web/src/locales/lv/messages.json index 333a655ab9..268c033079 100644 --- a/apps/web/src/locales/lv/messages.json +++ b/apps/web/src/locales/lv/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Izveidot kontu" }, + "setAStrongPassword": { + "message": "Jāiestata droša parole" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Jāpabeidz sava konta izveida ar paroles iestatīšanu" + }, "newAroundHere": { "message": "Jauns šeit?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nekas nav atlasīts." }, + "receiveMarketingEmails": { + "message": "Saņemt e-pasta ziņojumus no Bitwarden par paziņojumiem, padomiem un izpētes iespējām." + }, + "unsubscribe": { + "message": "Atteikt abonēšanu" + }, + "atAnyTime": { + "message": "jebkurā laikā." + }, + "byContinuingYouAgreeToThe": { + "message": "Turpinot tiek sniegta piekrišana" + }, + "and": { + "message": "un" + }, "acceptPolicies": { "message": "Ar šīs rūtiņas atzīmēšanu tiek piekrists sekojošajam:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Iestatīt GitHub darbības" }, + "setUpKubernetes": { + "message": "Iestatīt Kubernetes" + }, "setUpGitlabCICD": { "message": "Iestatīt GitLab CI/CD" }, "setUpAnsible": { "message": "Iestatīt Ansible" }, + "rustSDKRepo": { + "message": "Skatīt Rust glabātavu" + }, "cSharpSDKRepo": { "message": "Skatīt C# glabātavu" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Uz šo e-pasta adresi tiks nosūtīti visi ar šo nodrošinātāju saistītie rēķini", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Datums" + }, + "exportClientReport": { + "message": "Izgūt klienta atskaiti" + }, + "invoiceNumberHeader": { + "message": "Rēķina numurs", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ml/messages.json b/apps/web/src/locales/ml/messages.json index dd27f78c2a..dd35d88780 100644 --- a/apps/web/src/locales/ml/messages.json +++ b/apps/web/src/locales/ml/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "അക്കൗണ്ട് സൃഷ്ടിക്കുക" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "നിങ്ങൾ ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/mr/messages.json b/apps/web/src/locales/mr/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/mr/messages.json +++ b/apps/web/src/locales/mr/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/my/messages.json b/apps/web/src/locales/my/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/my/messages.json +++ b/apps/web/src/locales/my/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/nb/messages.json b/apps/web/src/locales/nb/messages.json index a3cdec7bcd..0c3f3b2cba 100644 --- a/apps/web/src/locales/nb/messages.json +++ b/apps/web/src/locales/nb/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Opprett en konto" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Er du ny her?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Du har ikke valgt noe." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ved å huke av denne boksen sier du deg enig i følgende:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ne/messages.json b/apps/web/src/locales/ne/messages.json index 4d8dfbbb10..64eadf17a5 100644 --- a/apps/web/src/locales/ne/messages.json +++ b/apps/web/src/locales/ne/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/nl/messages.json b/apps/web/src/locales/nl/messages.json index bb64a2fe2a..f300701348 100644 --- a/apps/web/src/locales/nl/messages.json +++ b/apps/web/src/locales/nl/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Account aanmaken" }, + "setAStrongPassword": { + "message": "Sterk wachtwoord instellen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Rond het aanmaken van je account af met het instellen van een wachtwoord" + }, "newAroundHere": { "message": "Nieuw hier?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Je hebt niets geselecteerd." }, + "receiveMarketingEmails": { + "message": "Ontvang e-mailberichten van Bitwarden voor aankondigingen, advies en onderzoeksmogelijkheden." + }, + "unsubscribe": { + "message": "Afmelden" + }, + "atAnyTime": { + "message": "op ieder moment." + }, + "byContinuingYouAgreeToThe": { + "message": "Door verder te gaan, ga je akkoord met de" + }, + "and": { + "message": "en" + }, "acceptPolicies": { "message": "Door dit vakje aan te vinken ga je akkoord met het volgende:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "GitHub Actions instellen" }, + "setUpKubernetes": { + "message": "Kubernetes inrichten" + }, "setUpGitlabCICD": { "message": "GitLab CI/CD instellen" }, "setUpAnsible": { "message": "Ansibel instellen" }, + "rustSDKRepo": { + "message": "Ruby-repository bekijken" + }, "cSharpSDKRepo": { "message": "C#-repository bekijken" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Dit e-mailadres ontvangt alle facturen van deze provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Datum" + }, + "exportClientReport": { + "message": "Klantenrapport exporteren" + }, + "invoiceNumberHeader": { + "message": "Factuurnummer", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/nn/messages.json b/apps/web/src/locales/nn/messages.json index 206989208d..70b69b8b92 100644 --- a/apps/web/src/locales/nn/messages.json +++ b/apps/web/src/locales/nn/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/or/messages.json b/apps/web/src/locales/or/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/or/messages.json +++ b/apps/web/src/locales/or/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/pl/messages.json b/apps/web/src/locales/pl/messages.json index 4709a5686f..ad05f5e5ed 100644 --- a/apps/web/src/locales/pl/messages.json +++ b/apps/web/src/locales/pl/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Utwórz konto" }, + "setAStrongPassword": { + "message": "Ustaw silne hasło" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Ukończ tworzenie konta poprzez ustawienie hasła" + }, "newAroundHere": { "message": "Nowy użytkownik?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nie zaznaczyłeś żadnych elementów." }, + "receiveMarketingEmails": { + "message": "Otrzymuj e-maile od Bitwarden z ogłoszeniami, poradami i badaniami." + }, + "unsubscribe": { + "message": "Anuluj subskrypcję" + }, + "atAnyTime": { + "message": "w każdej chwili." + }, + "byContinuingYouAgreeToThe": { + "message": "Kontynuując, zgadzasz się na" + }, + "and": { + "message": "i" + }, "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Skonfiguruj Github Actions" }, + "setUpKubernetes": { + "message": "Skonfiguruj Kubernetes" + }, "setUpGitlabCICD": { "message": "Skonfiguruj GitLab CI/CD" }, "setUpAnsible": { "message": "Skonfiguruj Ansible" }, + "rustSDKRepo": { + "message": "Zobacz repozytorium Rust" + }, "cSharpSDKRepo": { "message": "Zobacz repozytorium C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Ten adres e-mail otrzyma wszystkie faktury dotyczące tego dostawcy", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Data" + }, + "exportClientReport": { + "message": "Eksportuj raport klienta" + }, + "invoiceNumberHeader": { + "message": "Numer faktury", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/pt_BR/messages.json b/apps/web/src/locales/pt_BR/messages.json index dd962b3311..5d27f11e6c 100644 --- a/apps/web/src/locales/pt_BR/messages.json +++ b/apps/web/src/locales/pt_BR/messages.json @@ -582,13 +582,13 @@ "message": "Nível de acesso" }, "accessing": { - "message": "Accessing" + "message": "Acessando" }, "loggedOut": { "message": "Sessão encerrada" }, "loggedOutDesc": { - "message": "You have been logged out of your account." + "message": "Você foi desconectado de sua conta." }, "loginExpired": { "message": "A sua sessão expirou." @@ -713,6 +713,12 @@ "createAccount": { "message": "Criar conta" }, + "setAStrongPassword": { + "message": "Defina uma senha forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine de criar a sua conta definindo uma senha" + }, "newAroundHere": { "message": "Novo por aqui?" }, @@ -723,7 +729,7 @@ "message": "Iniciar sessão" }, "verifyIdentity": { - "message": "Verify your Identity" + "message": "Verifique sua identidade" }, "logInInitiated": { "message": "Login iniciado" @@ -1057,10 +1063,10 @@ "message": "Copiar URL" }, "errorRefreshingAccessToken": { - "message": "Access Token Refresh Error" + "message": "Erro ao Atualizar Token" }, "errorRefreshingAccessTokenDesc": { - "message": "No refresh token or API keys found. Please try logging out and logging back in." + "message": "Nenhum token de atualização ou chave de API foi encontrado. Tente sair e entrar novamente." }, "warning": { "message": "Aviso" @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Você selecionou nada." }, + "receiveMarketingEmails": { + "message": "Obtenha e-mails do Bitwarden para anúncios, conselhos e oportunidades de pesquisa." + }, + "unsubscribe": { + "message": "Cancelar subscrição" + }, + "atAnyTime": { + "message": "a qualquer momento." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, você concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, @@ -5584,37 +5605,37 @@ "message": "Renovar o Token de Sincronização de Cobrança invalidará o token anterior." }, "selfHostedServer": { - "message": "self-hosted" + "message": "auto-hospedado" }, "customEnvironment": { - "message": "Custom environment" + "message": "Ambiente personalizado" }, "selfHostedBaseUrlHint": { - "message": "Specify the base URL of your on-premises hosted Bitwarden installation. Example: https://bitwarden.company.com" + "message": "Especifique a URL de base da sua instalação local do Bitwarden. Exemplo: https://bitwarden.company.com" }, "selfHostedCustomEnvHeader": { - "message": "For advanced configuration, you can specify the base URL of each service independently." + "message": "Para usuários avançados. Você pode especificar a URL de base de cada serviço independentemente." }, "selfHostedEnvFormInvalid": { - "message": "You must add either the base Server URL or at least one custom environment." + "message": "Você deve adicionar um URL do servidor de base ou pelo menos um ambiente personalizado." }, "apiUrl": { - "message": "API server URL" + "message": "URL do servidor API" }, "webVaultUrl": { - "message": "Web vault server URL" + "message": "URL do servidor do Cofre Web" }, "identityUrl": { - "message": "Identity server URL" + "message": "URL do servidor de identidade" }, "notificationsUrl": { - "message": "Notifications server URL" + "message": "URL do servidor notificações" }, "iconsUrl": { - "message": "Icons server URL" + "message": "URL do Servidor de Ícones" }, "environmentSaved": { - "message": "Environment URLs saved" + "message": "URLs para ambiente salvo" }, "selfHostingTitle": { "message": "Auto-hospedado" @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Configurar ações do Github" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Configurar GitLab CI/CD" }, "setUpAnsible": { "message": "Configurar Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "Visualizar repositório C#" }, @@ -8311,10 +8338,10 @@ "message": "Fique à frente das vulnerabilidades de segurança atualizando para um plano pago para um monitoramento melhorado." }, "approveAllRequests": { - "message": "Approve all requests" + "message": "Aprovar todas as solicitações" }, "allLoginRequestsApproved": { - "message": "All login requests approved" + "message": "Todas as solicitações de login aprovadas" }, "payPal": { "message": "PayPal" @@ -8323,22 +8350,32 @@ "message": "Bitcoin" }, "updatedTaxInformation": { - "message": "Updated tax information" + "message": "Informações fiscais atualizadas" }, "unverified": { - "message": "Unverified" + "message": "Não verificado" }, "verified": { - "message": "Verified" + "message": "Verificado" }, "viewSecret": { - "message": "View secret" + "message": "Ver segredo" }, "noClients": { - "message": "There are no clients to list" + "message": "Não há clientes para listar" }, "providerBillingEmailHint": { - "message": "This email address will receive all invoices pertaining to this provider", + "message": "Este endereço de e-mail receberá todas as faturas referentes a este provedor", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Data" + }, + "exportClientReport": { + "message": "Exportar relatório do cliente" + }, + "invoiceNumberHeader": { + "message": "Número da fatura", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/pt_PT/messages.json b/apps/web/src/locales/pt_PT/messages.json index c286b8ee0b..cbaa7990f2 100644 --- a/apps/web/src/locales/pt_PT/messages.json +++ b/apps/web/src/locales/pt_PT/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Criar conta" }, + "setAStrongPassword": { + "message": "Defina uma palavra-passe forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine a criação da sua conta definindo uma palavra-passe" + }, "newAroundHere": { "message": "É novo por cá?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Não selecionou nada." }, + "receiveMarketingEmails": { + "message": "Receba e-mails do Bitwarden com anúncios, conselhos e oportunidades de investigação." + }, + "unsubscribe": { + "message": "Anular subscrição" + }, + "atAnyTime": { + "message": "a qualquer altura." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao selecionar esta caixa, concorda com o seguinte:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Configurar ações do Github" }, + "setUpKubernetes": { + "message": "Configurar o Kubernetes" + }, "setUpGitlabCICD": { "message": "Configurar o GitLab CI/CD" }, "setUpAnsible": { "message": "Configurar o Ansible" }, + "rustSDKRepo": { + "message": "Ver o repositório Rust" + }, "cSharpSDKRepo": { "message": "Ver repositório de C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Este endereço de e-mail receberá todas as faturas relativas a este fornecedor", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Data" + }, + "exportClientReport": { + "message": "Exportar o relatório do cliente" + }, + "invoiceNumberHeader": { + "message": "Número da fatura", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ro/messages.json b/apps/web/src/locales/ro/messages.json index 282428e7cb..fd00d273a0 100644 --- a/apps/web/src/locales/ro/messages.json +++ b/apps/web/src/locales/ro/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Creare cont" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Sunteți nou pe aici?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nu ați selectat nimic." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/ru/messages.json b/apps/web/src/locales/ru/messages.json index 6b74ddfbcf..30b7c5dc84 100644 --- a/apps/web/src/locales/ru/messages.json +++ b/apps/web/src/locales/ru/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Создать аккаунт" }, + "setAStrongPassword": { + "message": "Задайте надежный пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершите создание аккаунта, задав пароль" + }, "newAroundHere": { "message": "Вы здесь впервые?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Вы ничего не выбрали." }, + "receiveMarketingEmails": { + "message": "Получайте электронные письма от Bitwarden с анонсами, советами и возможностями для исследований." + }, + "unsubscribe": { + "message": "Отписаться" + }, + "atAnyTime": { + "message": "в любое время." + }, + "byContinuingYouAgreeToThe": { + "message": "Продолжая, вы соглашаетесь с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Настроить Github Actions" }, + "setUpKubernetes": { + "message": "Настроить Kubernetes" + }, "setUpGitlabCICD": { "message": "Настроить GitLab CI/CD" }, "setUpAnsible": { "message": "Настроить Ansible" }, + "rustSDKRepo": { + "message": "Просмотр репозитория Rust" + }, "cSharpSDKRepo": { "message": "Просмотр репозитория C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "На этот адрес email будут приходить все счета, относящиеся к данному провайдеру", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Дата" + }, + "exportClientReport": { + "message": "Экспорт отчета клиента" + }, + "invoiceNumberHeader": { + "message": "Номер счета", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/si/messages.json b/apps/web/src/locales/si/messages.json index 8e3c04cf62..bef76feac2 100644 --- a/apps/web/src/locales/si/messages.json +++ b/apps/web/src/locales/si/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "ගිණුමක් සාදන්න" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/sk/messages.json b/apps/web/src/locales/sk/messages.json index 93c03e6f50..cbf3b26349 100644 --- a/apps/web/src/locales/sk/messages.json +++ b/apps/web/src/locales/sk/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Vytvoriť účet" }, + "setAStrongPassword": { + "message": "Nastavte silné heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Zdadajte heslo na vytvorenie účtu" + }, "newAroundHere": { "message": "Ste tu nový?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Nič ste nevybrali." }, + "receiveMarketingEmails": { + "message": "Dostávať e-maily od Bitwardenu s oznámeniami, radami a možnosťami výskumu." + }, + "unsubscribe": { + "message": "Odhlásiť sa z odberu" + }, + "atAnyTime": { + "message": "môžete kedykoľvek." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračovaním súhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Nastaviť Github Actions" }, + "setUpKubernetes": { + "message": "Nastaviť Kubernetes" + }, "setUpGitlabCICD": { "message": "Nastaviť GitLab CI/CD" }, "setUpAnsible": { "message": "Nastaviť Ansible" }, + "rustSDKRepo": { + "message": "Zobraziť Rust repozitár" + }, "cSharpSDKRepo": { "message": "Zobraziť C# repozitár" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "Na túto e-mailovú adresu budú zasielané všetky faktúry týkajúce sa tohto poskytovateľa", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Dátum" + }, + "exportClientReport": { + "message": "Exportovať klientský report" + }, + "invoiceNumberHeader": { + "message": "Číslo faktúry", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/sl/messages.json b/apps/web/src/locales/sl/messages.json index 9648610d39..3010554b54 100644 --- a/apps/web/src/locales/sl/messages.json +++ b/apps/web/src/locales/sl/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Ustvarite si račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Ste novi tukaj?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Strinjam se z naslednjim:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/sr/messages.json b/apps/web/src/locales/sr/messages.json index 2379d2561a..af50223ee4 100644 --- a/apps/web/src/locales/sr/messages.json +++ b/apps/web/src/locales/sr/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Креирај налог" }, + "setAStrongPassword": { + "message": "Поставите јаку лозинку" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завршите креирање налога постављањем лозинке" + }, "newAroundHere": { "message": "Нов овде?" }, @@ -723,7 +729,7 @@ "message": "Пријавите се" }, "verifyIdentity": { - "message": "Verify your Identity" + "message": "Потврдите идентитет" }, "logInInitiated": { "message": "Пријава је покренута" @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Нисте ништа изабрали." }, + "receiveMarketingEmails": { + "message": "Добијајте е-пошту од Bitwarden-а за најаве, савете и могућности истраживања." + }, + "unsubscribe": { + "message": "Одјави се" + }, + "atAnyTime": { + "message": "било када." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако наставите, слажете се са" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Подесити акције GitHub-а" }, + "setUpKubernetes": { + "message": "Подесите Kubernetes" + }, "setUpGitlabCICD": { "message": "Подесити GitLab CI/CD" }, "setUpAnsible": { "message": "Подесити Ansible" }, + "rustSDKRepo": { + "message": "Преглед Rust спремишта" + }, "cSharpSDKRepo": { "message": "Преглед C# спремишта" }, @@ -8332,13 +8359,23 @@ "message": "Проверено" }, "viewSecret": { - "message": "View secret" + "message": "Види тајну" }, "noClients": { - "message": "There are no clients to list" + "message": "Нема клијената за попис" }, "providerBillingEmailHint": { - "message": "This email address will receive all invoices pertaining to this provider", + "message": "Овај имејл ће примати све фактуре које се односе на овог провајдера", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Датум" + }, + "exportClientReport": { + "message": "Извези извештај клијента" + }, + "invoiceNumberHeader": { + "message": "Број фактуре", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/sr_CS/messages.json b/apps/web/src/locales/sr_CS/messages.json index 3211c0d1b7..82304ef792 100644 --- a/apps/web/src/locales/sr_CS/messages.json +++ b/apps/web/src/locales/sr_CS/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Napravi Nalog" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/sv/messages.json b/apps/web/src/locales/sv/messages.json index 56b4506cae..38ca7f4f4e 100644 --- a/apps/web/src/locales/sv/messages.json +++ b/apps/web/src/locales/sv/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Skapa konto" }, + "setAStrongPassword": { + "message": "Ställ in ett starkt lösenord" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Är du ny här?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Du har inte markerat något." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "och" + }, "acceptPolicies": { "message": "Genom att kryssa i denna ruta godkänner du följande:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Ställ in GitLab CI/CD" }, "setUpAnsible": { "message": "Ställ in Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Datum" + }, + "exportClientReport": { + "message": "Exportera klientrapport" + }, + "invoiceNumberHeader": { + "message": "Fakturanummer", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/te/messages.json b/apps/web/src/locales/te/messages.json index 9363c432ca..300c100d6e 100644 --- a/apps/web/src/locales/te/messages.json +++ b/apps/web/src/locales/te/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/th/messages.json b/apps/web/src/locales/th/messages.json index aa854e62a2..f498a32d5f 100644 --- a/apps/web/src/locales/th/messages.json +++ b/apps/web/src/locales/th/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "สร้างบัญชีผู้ใช้" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "New around here?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/tr/messages.json b/apps/web/src/locales/tr/messages.json index 4607e0a037..73f90cab5a 100644 --- a/apps/web/src/locales/tr/messages.json +++ b/apps/web/src/locales/tr/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Hesap aç" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Buralarda yeni misiniz?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Hiçbir şey seçmediniz." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/uk/messages.json b/apps/web/src/locales/uk/messages.json index 1c3ff1e861..3f5b773dae 100644 --- a/apps/web/src/locales/uk/messages.json +++ b/apps/web/src/locales/uk/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Створити обліковий запис" }, + "setAStrongPassword": { + "message": "Встановіть надійний пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершіть створення облікового запису, встановивши пароль" + }, "newAroundHere": { "message": "Виконуєте вхід вперше?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "Ви нічого не обрали." }, + "receiveMarketingEmails": { + "message": "Отримуйте електронні листи від Bitwarden з оголошеннями, порадами та інформацією про нові можливості." + }, + "unsubscribe": { + "message": "Відписатися" + }, + "atAnyTime": { + "message": "можна будь-коли." + }, + "byContinuingYouAgreeToThe": { + "message": "Продовжуючи, ви погоджуєтеся з" + }, + "and": { + "message": "і" + }, "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Налаштувати дії для Github" }, + "setUpKubernetes": { + "message": "Налаштувати Kubernetes" + }, "setUpGitlabCICD": { "message": "Налаштувати GitLab CI/CD" }, "setUpAnsible": { "message": "Налаштувати Ansible" }, + "rustSDKRepo": { + "message": "Переглянути репозиторій Rust" + }, "cSharpSDKRepo": { "message": "Перегляд репозиторію C#" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "На цю адресу електронної пошти надсилатимуться всі рахунки, які стосуються цього провайдера", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Дата" + }, + "exportClientReport": { + "message": "Експортувати звіт клієнта" + }, + "invoiceNumberHeader": { + "message": "Номер рахунку", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/vi/messages.json b/apps/web/src/locales/vi/messages.json index eca409b21e..6654a74040 100644 --- a/apps/web/src/locales/vi/messages.json +++ b/apps/web/src/locales/vi/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "Tạo tài khoản" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "Bạn mới dùng?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "You have not selected anything." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "Set up Github Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "Set up GitLab CI/CD" }, "setUpAnsible": { "message": "Set up Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "View C# repository" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/zh_CN/messages.json b/apps/web/src/locales/zh_CN/messages.json index 5f5fd05e36..ec9ed72d6e 100644 --- a/apps/web/src/locales/zh_CN/messages.json +++ b/apps/web/src/locales/zh_CN/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "创建账户" }, + "setAStrongPassword": { + "message": "设置强密码" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "通过设置密码完成账户的创建" + }, "newAroundHere": { "message": "初来乍到吗?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "您尚未选择任何内容。" }, + "receiveMarketingEmails": { + "message": "接收来自 Bitwarden 的电子邮件,以获取公告、建议和调研。" + }, + "unsubscribe": { + "message": "取消订阅" + }, + "atAnyTime": { + "message": "随时。" + }, + "byContinuingYouAgreeToThe": { + "message": "若继续,代表您同意" + }, + "and": { + "message": "以及" + }, "acceptPolicies": { "message": "选中此框表示您同意:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "设置 Github Actions" }, + "setUpKubernetes": { + "message": "设置 Kubernetes" + }, "setUpGitlabCICD": { "message": "设置 GitLab CI/CD" }, "setUpAnsible": { "message": "设置 Ansible" }, + "rustSDKRepo": { + "message": "查看 Rust 存储库" + }, "cSharpSDKRepo": { "message": "查看 C# 存储库" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "此电子邮件地址将用于接收与此供应商相关的所有账单", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "日期" + }, + "exportClientReport": { + "message": "导出客户报告" + }, + "invoiceNumberHeader": { + "message": "账单编号", + "description": "A table header for an invoice's number" } } diff --git a/apps/web/src/locales/zh_TW/messages.json b/apps/web/src/locales/zh_TW/messages.json index 04a2e7f3ba..e8ae38dcd4 100644 --- a/apps/web/src/locales/zh_TW/messages.json +++ b/apps/web/src/locales/zh_TW/messages.json @@ -713,6 +713,12 @@ "createAccount": { "message": "建立帳戶" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "newAroundHere": { "message": "第一次使用?" }, @@ -3724,6 +3730,21 @@ "nothingSelected": { "message": "您未選取任何内容。" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "選中此選取框,即表示您同意下列條款:" }, @@ -8159,12 +8180,18 @@ "setUpGithubActions": { "message": "設定 GitHub Actions" }, + "setUpKubernetes": { + "message": "Set up Kubernetes" + }, "setUpGitlabCICD": { "message": "設定 GitLab CI/CD" }, "setUpAnsible": { "message": "設定 Ansible" }, + "rustSDKRepo": { + "message": "View Rust repository" + }, "cSharpSDKRepo": { "message": "檢視 C# 儲存庫" }, @@ -8340,5 +8367,15 @@ "providerBillingEmailHint": { "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." + }, + "date": { + "message": "Date" + }, + "exportClientReport": { + "message": "Export client report" + }, + "invoiceNumberHeader": { + "message": "Invoice number", + "description": "A table header for an invoice's number" } } From 94dcc89747a0001eb0863c8bf8633cbdbdfab3a4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:49:04 +0000 Subject: [PATCH 02/31] Autosync the updated translations (#9686) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/browser/src/_locales/ar/messages.json | 21 +++++ apps/browser/src/_locales/az/messages.json | 21 +++++ apps/browser/src/_locales/be/messages.json | 21 +++++ apps/browser/src/_locales/bg/messages.json | 21 +++++ apps/browser/src/_locales/bn/messages.json | 21 +++++ apps/browser/src/_locales/bs/messages.json | 21 +++++ apps/browser/src/_locales/ca/messages.json | 21 +++++ apps/browser/src/_locales/cs/messages.json | 21 +++++ apps/browser/src/_locales/cy/messages.json | 21 +++++ apps/browser/src/_locales/da/messages.json | 21 +++++ apps/browser/src/_locales/de/messages.json | 21 +++++ apps/browser/src/_locales/el/messages.json | 21 +++++ apps/browser/src/_locales/en_GB/messages.json | 21 +++++ apps/browser/src/_locales/en_IN/messages.json | 21 +++++ apps/browser/src/_locales/es/messages.json | 21 +++++ apps/browser/src/_locales/et/messages.json | 21 +++++ apps/browser/src/_locales/eu/messages.json | 21 +++++ apps/browser/src/_locales/fa/messages.json | 21 +++++ apps/browser/src/_locales/fi/messages.json | 25 +++++- apps/browser/src/_locales/fil/messages.json | 21 +++++ apps/browser/src/_locales/fr/messages.json | 21 +++++ apps/browser/src/_locales/gl/messages.json | 21 +++++ apps/browser/src/_locales/he/messages.json | 21 +++++ apps/browser/src/_locales/hi/messages.json | 21 +++++ apps/browser/src/_locales/hr/messages.json | 21 +++++ apps/browser/src/_locales/hu/messages.json | 21 +++++ apps/browser/src/_locales/id/messages.json | 21 +++++ apps/browser/src/_locales/it/messages.json | 21 +++++ apps/browser/src/_locales/ja/messages.json | 21 +++++ apps/browser/src/_locales/ka/messages.json | 21 +++++ apps/browser/src/_locales/km/messages.json | 21 +++++ apps/browser/src/_locales/kn/messages.json | 21 +++++ apps/browser/src/_locales/ko/messages.json | 21 +++++ apps/browser/src/_locales/lt/messages.json | 25 +++++- apps/browser/src/_locales/lv/messages.json | 21 +++++ apps/browser/src/_locales/ml/messages.json | 21 +++++ apps/browser/src/_locales/mr/messages.json | 21 +++++ apps/browser/src/_locales/my/messages.json | 21 +++++ apps/browser/src/_locales/nb/messages.json | 21 +++++ apps/browser/src/_locales/ne/messages.json | 21 +++++ apps/browser/src/_locales/nl/messages.json | 21 +++++ apps/browser/src/_locales/nn/messages.json | 21 +++++ apps/browser/src/_locales/or/messages.json | 21 +++++ apps/browser/src/_locales/pl/messages.json | 23 ++++- apps/browser/src/_locales/pt_BR/messages.json | 85 ++++++++++++------- apps/browser/src/_locales/pt_PT/messages.json | 21 +++++ apps/browser/src/_locales/ro/messages.json | 21 +++++ apps/browser/src/_locales/ru/messages.json | 21 +++++ apps/browser/src/_locales/si/messages.json | 21 +++++ apps/browser/src/_locales/sk/messages.json | 21 +++++ apps/browser/src/_locales/sl/messages.json | 21 +++++ apps/browser/src/_locales/sr/messages.json | 31 +++++-- apps/browser/src/_locales/sv/messages.json | 21 +++++ apps/browser/src/_locales/te/messages.json | 21 +++++ apps/browser/src/_locales/th/messages.json | 21 +++++ apps/browser/src/_locales/tr/messages.json | 23 ++++- apps/browser/src/_locales/uk/messages.json | 21 +++++ apps/browser/src/_locales/vi/messages.json | 21 +++++ apps/browser/src/_locales/zh_CN/messages.json | 21 +++++ apps/browser/src/_locales/zh_TW/messages.json | 21 +++++ 60 files changed, 1303 insertions(+), 43 deletions(-) diff --git a/apps/browser/src/_locales/ar/messages.json b/apps/browser/src/_locales/ar/messages.json index 4232a0bbc8..28c13b3d87 100644 --- a/apps/browser/src/_locales/ar/messages.json +++ b/apps/browser/src/_locales/ar/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "إنشاء حساب" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "تسجيل الدخول" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "كلمة المرور الرئيسية الجديدة لا تفي بمتطلبات السياسة العامة." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "من خلال تحديد هذا المربع فإنك توافق على ما يلي:" }, diff --git a/apps/browser/src/_locales/az/messages.json b/apps/browser/src/_locales/az/messages.json index d109aa0e79..e1247aa438 100644 --- a/apps/browser/src/_locales/az/messages.json +++ b/apps/browser/src/_locales/az/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Hesab yarat" }, + "setAStrongPassword": { + "message": "Güclü bir parol təyin et" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Bir parol təyin edərək hesabınızı yaratmağı başa çatdırın" + }, "login": { "message": "Giriş et" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Yeni ana parolunuz siyasət tələblərini qarşılamır." }, + "receiveMarketingEmails": { + "message": "Elanlar, məsləhətlər və araşdırma fürsətləri üçün Bitwarden-dən e-poçt alın." + }, + "unsubscribe": { + "message": "Abunəlikdən çıx" + }, + "atAnyTime": { + "message": "istənilən vaxt." + }, + "byContinuingYouAgreeToThe": { + "message": "Davam edərək, bunlarla razılaşırsınız" + }, + "and": { + "message": "və" + }, "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, diff --git a/apps/browser/src/_locales/be/messages.json b/apps/browser/src/_locales/be/messages.json index e8d3e04864..a024d39b73 100644 --- a/apps/browser/src/_locales/be/messages.json +++ b/apps/browser/src/_locales/be/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Стварыць уліковы запіс" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Увайсці" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новы асноўны пароль не адпавядае патрабаванням палітыкі." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ставячы гэты сцяжок, вы пагаджаецеся з наступным:" }, diff --git a/apps/browser/src/_locales/bg/messages.json b/apps/browser/src/_locales/bg/messages.json index 9071ac7cad..6a73a88d9f 100644 --- a/apps/browser/src/_locales/bg/messages.json +++ b/apps/browser/src/_locales/bg/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Създаване на акаунт" }, + "setAStrongPassword": { + "message": "Използвайте сложна парола" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завършете регистрацията си като зададете парола" + }, "login": { "message": "Вписване" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Паролата ви не отговаря на политиките." }, + "receiveMarketingEmails": { + "message": "Получавайте е-писма от Битоурден за новини, съвети и възможности за проучвания." + }, + "unsubscribe": { + "message": "Отписване" + }, + "atAnyTime": { + "message": "по всяко време." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако продължите, Вие се съгласявате с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следното:" }, diff --git a/apps/browser/src/_locales/bn/messages.json b/apps/browser/src/_locales/bn/messages.json index 6bc79efd4d..9abcc863ec 100644 --- a/apps/browser/src/_locales/bn/messages.json +++ b/apps/browser/src/_locales/bn/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "অ্যাকাউন্ট তৈরি করুন" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "প্রবেশ করুন" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "আপনার নতুন মূল পাসওয়ার্ড নীতির প্রয়োজনীয়তা পূরণ করে না।" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, diff --git a/apps/browser/src/_locales/bs/messages.json b/apps/browser/src/_locales/bs/messages.json index a3cc4ea496..33091fd7c4 100644 --- a/apps/browser/src/_locales/bs/messages.json +++ b/apps/browser/src/_locales/bs/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Napravi račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Prijavite se" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/ca/messages.json b/apps/browser/src/_locales/ca/messages.json index 40e9ca8844..6fef1e6ed4 100644 --- a/apps/browser/src/_locales/ca/messages.json +++ b/apps/browser/src/_locales/ca/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Crea un compte" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Inicia sessió" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "La nova contrasenya principal no compleix els requisits de la política." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, diff --git a/apps/browser/src/_locales/cs/messages.json b/apps/browser/src/_locales/cs/messages.json index 4ebf0d3901..2448936d45 100644 --- a/apps/browser/src/_locales/cs/messages.json +++ b/apps/browser/src/_locales/cs/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Vytvořit účet" }, + "setAStrongPassword": { + "message": "Nastavit hlavní heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Dokončete vytváření účtu nastavením hesla" + }, "login": { "message": "Přihlásit se" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Vaše nové hlavní heslo nesplňuje požadavky zásad organizace." }, + "receiveMarketingEmails": { + "message": "Získejte e-maily od Bitwardenu pro oznámení, poradenství a výzkumné příležitosti." + }, + "unsubscribe": { + "message": "Odhlásit odběr" + }, + "atAnyTime": { + "message": "kdykoli." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračováním souhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasíte s následujícím:" }, diff --git a/apps/browser/src/_locales/cy/messages.json b/apps/browser/src/_locales/cy/messages.json index e43d33ceb4..109e6253b4 100644 --- a/apps/browser/src/_locales/cy/messages.json +++ b/apps/browser/src/_locales/cy/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Creu cyfrif" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Mewngofnodi" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Drwy dicio'r blwch hwn, rydych yn cytuno i'r canlynol:" }, diff --git a/apps/browser/src/_locales/da/messages.json b/apps/browser/src/_locales/da/messages.json index f3248376fd..7ff5c01fb0 100644 --- a/apps/browser/src/_locales/da/messages.json +++ b/apps/browser/src/_locales/da/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Opret konto" }, + "setAStrongPassword": { + "message": "Indstil en stærk adgangskode" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Afslut kontooprettelsen med at indstille en adgangskode" + }, "login": { "message": "Log ind" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Din nye hovedadgangskode opfylder ikke politikkravene." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Afmeld" + }, + "atAnyTime": { + "message": "til enhver tid." + }, + "byContinuingYouAgreeToThe": { + "message": "Ved at fortsætte, accepterer du" + }, + "and": { + "message": "og" + }, "acceptPolicies": { "message": "Ved at markere dette felt accepterer du følgende:" }, diff --git a/apps/browser/src/_locales/de/messages.json b/apps/browser/src/_locales/de/messages.json index e38a307df2..99ef7bc338 100644 --- a/apps/browser/src/_locales/de/messages.json +++ b/apps/browser/src/_locales/de/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Konto erstellen" }, + "setAStrongPassword": { + "message": "Ein starkes Passwort festlegen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Schließe die Erstellung deines Kontos ab, indem du ein Passwort festlegst" + }, "login": { "message": "Anmelden" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ihr neues Master-Passwort entspricht nicht den Anforderungen der Richtlinie." }, + "receiveMarketingEmails": { + "message": "Erhalte E-Mails von Bitwarden für Ankündigungen, Ratschläge und Forschungsmöglichkeiten." + }, + "unsubscribe": { + "message": "Deabonnieren" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklärst du dich mit Folgendem einverstanden:" }, diff --git a/apps/browser/src/_locales/el/messages.json b/apps/browser/src/_locales/el/messages.json index 9c9a49ee1c..6e18ee7f2e 100644 --- a/apps/browser/src/_locales/el/messages.json +++ b/apps/browser/src/_locales/el/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Δημιουργία λογαριασμού" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Σύνδεση" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ο νέος κύριος κωδικός δεν πληροί τις απαιτήσεις πολιτικής." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, diff --git a/apps/browser/src/_locales/en_GB/messages.json b/apps/browser/src/_locales/en_GB/messages.json index c73f26a284..23ac98d3c1 100644 --- a/apps/browser/src/_locales/en_GB/messages.json +++ b/apps/browser/src/_locales/en_GB/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/en_IN/messages.json b/apps/browser/src/_locales/en_IN/messages.json index 6a301b57e4..fb00af402d 100644 --- a/apps/browser/src/_locales/en_IN/messages.json +++ b/apps/browser/src/_locales/en_IN/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/es/messages.json b/apps/browser/src/_locales/es/messages.json index 64b8fdcedc..1f8ba3c8b4 100644 --- a/apps/browser/src/_locales/es/messages.json +++ b/apps/browser/src/_locales/es/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Crear cuenta" }, + "setAStrongPassword": { + "message": "Establece una contraseña fuerte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termina de crear tu cuenta estableciendo una contraseña" + }, "login": { "message": "Iniciar sesión" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Su nueva contraseña maestra no cumple con los requisitos de la política." }, + "receiveMarketingEmails": { + "message": "Obtén correos electrónicos de Bitwarden para anuncios, consejos y oportunidades de investigación." + }, + "unsubscribe": { + "message": "Cancelar suscripción" + }, + "atAnyTime": { + "message": "en cualquier momento." + }, + "byContinuingYouAgreeToThe": { + "message": "Continuando, aceptas los" + }, + "and": { + "message": "y" + }, "acceptPolicies": { "message": "Al seleccionar esta casilla, acepta lo siguiente:" }, diff --git a/apps/browser/src/_locales/et/messages.json b/apps/browser/src/_locales/et/messages.json index c53e8817c1..95ceaf13a8 100644 --- a/apps/browser/src/_locales/et/messages.json +++ b/apps/browser/src/_locales/et/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Loo konto" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Logi sisse" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Uus ülemparool ei vasta eeskirjades väljatoodud tingimustele." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, diff --git a/apps/browser/src/_locales/eu/messages.json b/apps/browser/src/_locales/eu/messages.json index 89386601c9..8aa375f2c9 100644 --- a/apps/browser/src/_locales/eu/messages.json +++ b/apps/browser/src/_locales/eu/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Sortu kontua" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Hasi saioa" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Zure pasahitz nagusi berriak ez ditu baldintzak betetzen." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Laukitxo hau markatzean, honakoa onartzen duzu:" }, diff --git a/apps/browser/src/_locales/fa/messages.json b/apps/browser/src/_locales/fa/messages.json index 9694a1a2a7..11a01aaaf6 100644 --- a/apps/browser/src/_locales/fa/messages.json +++ b/apps/browser/src/_locales/fa/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "ایجاد حساب کاربری" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "ورود" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "کلمه عبور اصلی جدید شما از شرایط سیاست پیروی نمی‌کند." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "با علامت زدن این کادر با موارد زیر موافقت می‌کنید:" }, diff --git a/apps/browser/src/_locales/fi/messages.json b/apps/browser/src/_locales/fi/messages.json index edc2e1e737..2df7e1ae05 100644 --- a/apps/browser/src/_locales/fi/messages.json +++ b/apps/browser/src/_locales/fi/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Luo tili" }, + "setAStrongPassword": { + "message": "Aseta vahva salasana" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Viimeistele tilin luonti asettamalla salasana" + }, "login": { "message": "Kirjaudu" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Uusi pääsalasanasi ei täytä käytännön määrittämiä vaatimuksia." }, + "receiveMarketingEmails": { + "message": "Vastaanota Bitwardenilta uutiskirjeitä julkaisuista, tukiresursseista ja tutkimusmahdollisuuksista." + }, + "unsubscribe": { + "message": "Lopeta tilaus" + }, + "atAnyTime": { + "message": "milloin tahansa." + }, + "byContinuingYouAgreeToThe": { + "message": "Jatkaessasi hyväksyt" + }, + "and": { + "message": "ja" + }, "acceptPolicies": { "message": "Valitsemalla tämän hyväksyt seuraavat:" }, @@ -3374,7 +3395,7 @@ } }, "autofillTitle": { - "message": "Auto-fill - $ITEMNAME$", + "message": "Automaattitäyttö - $ITEMNAME$", "description": "Title for a button that auto-fills a login item.", "placeholders": { "itemname": { @@ -3384,7 +3405,7 @@ } }, "noValuesToCopy": { - "message": "No values to copy" + "message": "Ei kopioitavia arvoja" }, "assignCollections": { "message": "Määritä kokoelmat" diff --git a/apps/browser/src/_locales/fil/messages.json b/apps/browser/src/_locales/fil/messages.json index 639300f789..38ada91df2 100644 --- a/apps/browser/src/_locales/fil/messages.json +++ b/apps/browser/src/_locales/fil/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Gumawa ng Account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Mag-login" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Hindi matugunan ng iyong bagong pangunahing password ang mga kinakailangan ng patakaran." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Sa pamamagitan ng pag-tsek sa kahon na ito ay sumasang-ayon ka sa sumusunod:" }, diff --git a/apps/browser/src/_locales/fr/messages.json b/apps/browser/src/_locales/fr/messages.json index fadf74c5d7..3ddb76667a 100644 --- a/apps/browser/src/_locales/fr/messages.json +++ b/apps/browser/src/_locales/fr/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Créer un compte" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Se connecter" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Votre nouveau mot de passe principal ne répond pas aux exigences de politique de sécurité." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "En cochant cette case vous acceptez ce qui suit :" }, diff --git a/apps/browser/src/_locales/gl/messages.json b/apps/browser/src/_locales/gl/messages.json index 9075adaaf6..351b865c79 100644 --- a/apps/browser/src/_locales/gl/messages.json +++ b/apps/browser/src/_locales/gl/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Crea unha conta" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Iniciar sesión" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/he/messages.json b/apps/browser/src/_locales/he/messages.json index cea1ab207a..7c427cff70 100644 --- a/apps/browser/src/_locales/he/messages.json +++ b/apps/browser/src/_locales/he/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "צור חשבון" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "התחבר" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "הסיסמה הראשית החדשה השלך לא עומדת בדרישות המדיניות." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, diff --git a/apps/browser/src/_locales/hi/messages.json b/apps/browser/src/_locales/hi/messages.json index 3232d9084e..97b6754d0d 100644 --- a/apps/browser/src/_locales/hi/messages.json +++ b/apps/browser/src/_locales/hi/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create Account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log In" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "आपका नया मास्टर पासवर्ड पॉलिसी आवश्यकताओं को पूरा नहीं करता है।" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "इस बॉक्स की जांच करके आप निम्नलिखित से सहमत हैं:" }, diff --git a/apps/browser/src/_locales/hr/messages.json b/apps/browser/src/_locales/hr/messages.json index 144a27769c..9a0a32c524 100644 --- a/apps/browser/src/_locales/hr/messages.json +++ b/apps/browser/src/_locales/hr/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Stvori račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Prijava" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Tvoja nova glavna lozinka ne ispunjava zahtjeve." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, diff --git a/apps/browser/src/_locales/hu/messages.json b/apps/browser/src/_locales/hu/messages.json index 06c3b93eac..b291d550d1 100644 --- a/apps/browser/src/_locales/hu/messages.json +++ b/apps/browser/src/_locales/hu/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Fiók létrehozása" }, + "setAStrongPassword": { + "message": "Erős jelszó beállítása" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "A fiók létrehozásának befejezése jelszó beállításával" + }, "login": { "message": "Bejelentkezés" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Az új mesterjelszó nem felel meg a szabály követelményeknek." }, + "receiveMarketingEmails": { + "message": "Emaileket kaphatunk a Bitwardentől bejelentésekről, tanácsokról és kutatási lehetőségekről." + }, + "unsubscribe": { + "message": "Leiratkozás" + }, + "atAnyTime": { + "message": "bármikor." + }, + "byContinuingYouAgreeToThe": { + "message": "A folytatással elfogadjuk" + }, + "and": { + "message": "és" + }, "acceptPolicies": { "message": "A doboz bejelölésével elfogadjuk a következőket:" }, diff --git a/apps/browser/src/_locales/id/messages.json b/apps/browser/src/_locales/id/messages.json index fab17ae40e..0dd6df9833 100644 --- a/apps/browser/src/_locales/id/messages.json +++ b/apps/browser/src/_locales/id/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Buat Akun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Masuk" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Kata sandi utama Anda yang baru tidak memenuhi persyaratan kebijakan." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dengan mencentang kotak ini, Anda menyetujui yang berikut:" }, diff --git a/apps/browser/src/_locales/it/messages.json b/apps/browser/src/_locales/it/messages.json index 9ea42bba02..7f9694e901 100644 --- a/apps/browser/src/_locales/it/messages.json +++ b/apps/browser/src/_locales/it/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Crea account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Accedi" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "La tua nuova password principale non soddisfa i requisiti di sicurezza." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Selezionando questa casella accetti quanto segue:" }, diff --git a/apps/browser/src/_locales/ja/messages.json b/apps/browser/src/_locales/ja/messages.json index 29f840ff84..efc943eaf5 100644 --- a/apps/browser/src/_locales/ja/messages.json +++ b/apps/browser/src/_locales/ja/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "アカウントの作成" }, + "setAStrongPassword": { + "message": "強力なパスワードを設定する" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "パスワードを設定してアカウントの作成を完了してください" + }, "login": { "message": "ログイン" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "新しいマスターパスワードは最低要件を満たしていません。" }, + "receiveMarketingEmails": { + "message": "Bitwarden からのお知らせ、アドバイス、アンケート調査等のメールを受信します。" + }, + "unsubscribe": { + "message": "配信停止" + }, + "atAnyTime": { + "message": "はいつでもできます。" + }, + "byContinuingYouAgreeToThe": { + "message": "続行すると以下に同意したものとみなします:" + }, + "and": { + "message": "と" + }, "acceptPolicies": { "message": "以下に同意しチェックします:" }, diff --git a/apps/browser/src/_locales/ka/messages.json b/apps/browser/src/_locales/ka/messages.json index baee54e638..ee5e4e9ae3 100644 --- a/apps/browser/src/_locales/ka/messages.json +++ b/apps/browser/src/_locales/ka/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "ანგარიშის შექმნა" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "ავტორიზაცია" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/km/messages.json b/apps/browser/src/_locales/km/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/km/messages.json +++ b/apps/browser/src/_locales/km/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/kn/messages.json b/apps/browser/src/_locales/kn/messages.json index 45fbf95858..7192f3cbcf 100644 --- a/apps/browser/src/_locales/kn/messages.json +++ b/apps/browser/src/_locales/kn/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "ಖಾತೆ ತೆರೆ" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "ಲಾಗಿನ್" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "ನಿಮ್ಮ ಹೊಸ ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ನೀತಿಯ ಅವಶ್ಯಕತೆಗಳನ್ನು ಪೂರೈಸುವುದಿಲ್ಲ." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, diff --git a/apps/browser/src/_locales/ko/messages.json b/apps/browser/src/_locales/ko/messages.json index d7f2de56bb..7253306fc4 100644 --- a/apps/browser/src/_locales/ko/messages.json +++ b/apps/browser/src/_locales/ko/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "계정 만들기" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "로그인" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "새 마스터 비밀번호가 정책 요구 사항을 따르지 않습니다." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, diff --git a/apps/browser/src/_locales/lt/messages.json b/apps/browser/src/_locales/lt/messages.json index b906e405b1..2d895f0d63 100644 --- a/apps/browser/src/_locales/lt/messages.json +++ b/apps/browser/src/_locales/lt/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Sukurti paskyrą" }, + "setAStrongPassword": { + "message": "Nustatyti stiprų slaptažodį" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Baigkite kurti paskyrą nustatydami slaptažodį" + }, "login": { "message": "Prisijungti" }, @@ -1435,7 +1441,7 @@ "message": "Tapatybė" }, "newItemHeader": { - "message": "New $TYPE$", + "message": "Naujas $TYPE$", "placeholders": { "type": { "content": "$1", @@ -1444,7 +1450,7 @@ } }, "editItemHeader": { - "message": "Edit $TYPE$", + "message": "Redaguoti $TYPE$", "placeholders": { "type": { "content": "$1", @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Tavo naujasis pagrindinis slaptažodis neatitinka politikos reikalavimų." }, + "receiveMarketingEmails": { + "message": "Gaukite „Bitwarden“ el. laiškus su skelbimais, patarimais ir tyrimų galimybėmis." + }, + "unsubscribe": { + "message": "Atsisakyti prenumeratos" + }, + "atAnyTime": { + "message": "bet kuriuo metu." + }, + "byContinuingYouAgreeToThe": { + "message": "Tęsiant sutinkate su" + }, + "and": { + "message": "ir" + }, "acceptPolicies": { "message": "Pažymėdami šį laukelį, sutinkate su šiais dalykais:" }, diff --git a/apps/browser/src/_locales/lv/messages.json b/apps/browser/src/_locales/lv/messages.json index 2da5064684..7657291049 100644 --- a/apps/browser/src/_locales/lv/messages.json +++ b/apps/browser/src/_locales/lv/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Izveidot kontu" }, + "setAStrongPassword": { + "message": "Jāiestata droša parole" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Jāpabeidz sava konta izveida ar paroles iestatīšanu" + }, "login": { "message": "Pieteikties" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Jaunā galvenā parole neatbilst nosacījumu prasībām." }, + "receiveMarketingEmails": { + "message": "Saņemt e-pasta ziņojumus no Bitwarden par paziņojumiem, padomiem un izpētes iespējām." + }, + "unsubscribe": { + "message": "Atteikt abonēšanu" + }, + "atAnyTime": { + "message": "jebkurā laikā." + }, + "byContinuingYouAgreeToThe": { + "message": "Turpinot tiek sniegta piekrišana" + }, + "and": { + "message": "un" + }, "acceptPolicies": { "message": "Ar šīs rūtiņas atzīmēšanu tiek piekrists sekojošajam:" }, diff --git a/apps/browser/src/_locales/ml/messages.json b/apps/browser/src/_locales/ml/messages.json index 5ee6029465..a8d6fb2667 100644 --- a/apps/browser/src/_locales/ml/messages.json +++ b/apps/browser/src/_locales/ml/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "അക്കൗണ്ട് സൃഷ്ടിക്കുക" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "ലോഗിൻ" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "നിങ്ങളുടെ പുതിയ മാസ്റ്റർ പാസ്‌വേഡ് നയ ആവശ്യകതകൾ നിറവേറ്റുന്നില്ല." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, diff --git a/apps/browser/src/_locales/mr/messages.json b/apps/browser/src/_locales/mr/messages.json index ce8ef907f8..53ea8bd53c 100644 --- a/apps/browser/src/_locales/mr/messages.json +++ b/apps/browser/src/_locales/mr/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "खाते तयार करा" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "प्रवेश करा" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/my/messages.json b/apps/browser/src/_locales/my/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/my/messages.json +++ b/apps/browser/src/_locales/my/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/nb/messages.json b/apps/browser/src/_locales/nb/messages.json index 79a6284fa3..83906afca8 100644 --- a/apps/browser/src/_locales/nb/messages.json +++ b/apps/browser/src/_locales/nb/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Opprett en konto" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Logg inn" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Det nye hovedpassordet ditt oppfyller ikke vilkår i virksomhetsreglene." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ved å merke av denne boksen sier du deg enig i følgende:" }, diff --git a/apps/browser/src/_locales/ne/messages.json b/apps/browser/src/_locales/ne/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/ne/messages.json +++ b/apps/browser/src/_locales/ne/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/nl/messages.json b/apps/browser/src/_locales/nl/messages.json index 93820cd208..6813cfda20 100644 --- a/apps/browser/src/_locales/nl/messages.json +++ b/apps/browser/src/_locales/nl/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Account aanmaken" }, + "setAStrongPassword": { + "message": "Sterk wachtwoord instellen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Rond het aanmaken van je account af met het instellen van een wachtwoord" + }, "login": { "message": "Inloggen" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Je nieuwe hoofdwachtwoord voldoet niet aan de beleidseisen." }, + "receiveMarketingEmails": { + "message": "Ontvang e-mailberichten van Bitwarden voor aankondigingen, advies en onderzoeksmogelijkheden." + }, + "unsubscribe": { + "message": "Afmelden" + }, + "atAnyTime": { + "message": "op ieder moment." + }, + "byContinuingYouAgreeToThe": { + "message": "Door verder te gaan, ga je akkoord met de" + }, + "and": { + "message": "en" + }, "acceptPolicies": { "message": "Door dit vakje aan te vinken, ga je akkoord met het volgende:" }, diff --git a/apps/browser/src/_locales/nn/messages.json b/apps/browser/src/_locales/nn/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/nn/messages.json +++ b/apps/browser/src/_locales/nn/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/or/messages.json b/apps/browser/src/_locales/or/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/or/messages.json +++ b/apps/browser/src/_locales/or/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/pl/messages.json b/apps/browser/src/_locales/pl/messages.json index e8c888067e..aa2e4e18e3 100644 --- a/apps/browser/src/_locales/pl/messages.json +++ b/apps/browser/src/_locales/pl/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Utwórz konto" }, + "setAStrongPassword": { + "message": "Ustaw silne hasło" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Ukończ tworzenie konta poprzez ustawienie hasła" + }, "login": { "message": "Zaloguj się" }, @@ -1462,7 +1468,7 @@ "message": "Kolekcje" }, "nCollections": { - "message": "$COUNT$ collections", + "message": "Kolekcje: $COUNT$", "placeholders": { "count": { "content": "$1", @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Nowe hasło główne nie spełnia wymaganych zasad." }, + "receiveMarketingEmails": { + "message": "Otrzymuj e-maile od Bitwarden z ogłoszeniami, poradami i badaniami." + }, + "unsubscribe": { + "message": "Anuluj subskrypcję" + }, + "atAnyTime": { + "message": "w każdej chwili." + }, + "byContinuingYouAgreeToThe": { + "message": "Kontynuując, zgadzasz się na" + }, + "and": { + "message": "i" + }, "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, diff --git a/apps/browser/src/_locales/pt_BR/messages.json b/apps/browser/src/_locales/pt_BR/messages.json index 2fd0a0a8d7..db0b88426f 100644 --- a/apps/browser/src/_locales/pt_BR/messages.json +++ b/apps/browser/src/_locales/pt_BR/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Criar Conta" }, + "setAStrongPassword": { + "message": "Defina uma senha forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine de criar a sua conta definindo uma senha" + }, "login": { "message": "Iniciar Sessão" }, @@ -393,10 +399,10 @@ "message": "Desfavoritar" }, "itemAddedToFavorites": { - "message": "Item added to favorites" + "message": "Item adicionado aos favoritos" }, "itemRemovedFromFavorites": { - "message": "Item removed from favorites" + "message": "Item removido dos favoritos" }, "notes": { "message": "Notas" @@ -836,19 +842,19 @@ "message": "Esta senha será usada para exportar e importar este arquivo" }, "accountRestrictedOptionDescription": { - "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Use sua chave criptográfica da conta, derivada do nome de usuário e Senha Mestra da sua conta, para criptografar a exportação e restringir importação para apenas a conta atual do Bitwarden." }, "passwordProtectedOptionDescription": { - "message": "Set a file password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Defina uma senha de arquivo para criptografar a exportação e importá-la para qualquer conta do Bitwarden usando a senha para descriptografia." }, "exportTypeHeading": { - "message": "Export type" + "message": "Tipo da exportação" }, "accountRestricted": { - "message": "Account restricted" + "message": "Conta restrita" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“File password” and “Confirm file password“ do not match." + "message": "\"Senha do arquivo\" e \"Confirmação de senha\" não correspondem." }, "warning": { "message": "AVISO", @@ -1123,13 +1129,13 @@ "message": "Especifique a URL de base da sua instalação local do Bitwarden." }, "selfHostedBaseUrlHint": { - "message": "Specify the base URL of your on-premises hosted Bitwarden installation. Example: https://bitwarden.company.com" + "message": "Especifique a URL de base da sua instalação local do Bitwarden. Exemplo: https://bitwarden.company.com" }, "selfHostedCustomEnvHeader": { - "message": "For advanced configuration, you can specify the base URL of each service independently." + "message": "Para usuários avançados. Você pode especificar a URL de base de cada serviço independentemente." }, "selfHostedEnvFormInvalid": { - "message": "You must add either the base Server URL or at least one custom environment." + "message": "Você deve adicionar um URL do servidor de base ou pelo menos um ambiente personalizado." }, "customEnvironment": { "message": "Ambiente Personalizado" @@ -1435,7 +1441,7 @@ "message": "Identidade" }, "newItemHeader": { - "message": "New $TYPE$", + "message": "Nova $TYPE$", "placeholders": { "type": { "content": "$1", @@ -1444,7 +1450,7 @@ } }, "editItemHeader": { - "message": "Edit $TYPE$", + "message": "Editar $TYPE$", "placeholders": { "type": { "content": "$1", @@ -1462,7 +1468,7 @@ "message": "Coleções" }, "nCollections": { - "message": "$COUNT$ collections", + "message": "Coleções $COUNT$", "placeholders": { "count": { "content": "$1", @@ -1700,7 +1706,7 @@ "message": "Autopreencher e Salvar" }, "fillAndSave": { - "message": "Fill and save" + "message": "Preencher e salvar" }, "autoFillSuccessAndSavedUri": { "message": "Item Auto-Preenchido e URI Salvo" @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "A sua nova senha mestra não cumpre aos requisitos da política." }, + "receiveMarketingEmails": { + "message": "Obtenha e-mails do Bitwarden para anúncios, conselhos e oportunidades de pesquisa." + }, + "unsubscribe": { + "message": "Cancelar subscrição" + }, + "atAnyTime": { + "message": "a qualquer momento." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, você concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, @@ -1799,10 +1820,10 @@ "message": "Ok" }, "errorRefreshingAccessToken": { - "message": "Access Token Refresh Error" + "message": "Erro ao Atualizar Token" }, "errorRefreshingAccessTokenDesc": { - "message": "No refresh token or API keys found. Please try logging out and logging back in." + "message": "Nenhum token de atualização ou chave de API foi encontrado. Tente sair e entrar novamente." }, "desktopSyncVerificationTitle": { "message": "Verificação de sincronização do Desktop" @@ -2273,10 +2294,10 @@ } }, "exportingOrganizationVaultTitle": { - "message": "Exporting organization vault" + "message": "Exportando cofre da organização" }, "exportingOrganizationVaultDesc": { - "message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Items in individual vaults or other organizations will not be included.", + "message": "Apenas o cofre da organização associado com $ORGANIZATION$ será exportado. Itens do cofre pessoal e itens de outras organizações não serão incluídos.", "placeholders": { "organization": { "content": "$1", @@ -3324,7 +3345,7 @@ "message": "Limpar filtros ou tentar outro termo de pesquisa" }, "copyInfoTitle": { - "message": "Copy info - $ITEMNAME$", + "message": "Copiar informação - $ITEMNAME$", "description": "Title for a button that opens a menu with options to copy information from an item.", "placeholders": { "itemname": { @@ -3334,7 +3355,7 @@ } }, "copyNoteTitle": { - "message": "Copy Note - $ITEMNAME$", + "message": "Copiar Nota - $ITEMNAME$", "description": "Title for a button copies a note to the clipboard.", "placeholders": { "itemname": { @@ -3344,7 +3365,7 @@ } }, "moreOptionsLabel": { - "message": "More options, $ITEMNAME$", + "message": "Mais opções, $ITEMNAME$", "description": "Aria label for a button that opens a menu with more options for an item.", "placeholders": { "itemname": { @@ -3354,7 +3375,7 @@ } }, "moreOptionsTitle": { - "message": "More options - $ITEMNAME$", + "message": "Mais opções - $ITEMNAME$", "description": "Title for a button that opens a menu with more options for an item.", "placeholders": { "itemname": { @@ -3364,7 +3385,7 @@ } }, "viewItemTitle": { - "message": "View item - $ITEMNAME$", + "message": "Visualizar item - $ITEMNAME$", "description": "Title for a link that opens a view for an item.", "placeholders": { "itemname": { @@ -3374,7 +3395,7 @@ } }, "autofillTitle": { - "message": "Auto-fill - $ITEMNAME$", + "message": "Auto-preenchimento - $ITEMNAME$", "description": "Title for a button that auto-fills a login item.", "placeholders": { "itemname": { @@ -3384,19 +3405,19 @@ } }, "noValuesToCopy": { - "message": "No values to copy" + "message": "Não há valores para copiar" }, "assignCollections": { - "message": "Assign collections" + "message": "Aplicar coleção" }, "copyEmail": { - "message": "Copy email" + "message": "Copiar e-mail" }, "copyPhone": { - "message": "Copy phone" + "message": "Copiar telefone" }, "copyAddress": { - "message": "Copy address" + "message": "Copiar endereço" }, "adminConsole": { "message": "Painel de administração" @@ -3450,12 +3471,12 @@ } }, "itemsWithNoFolder": { - "message": "Items with no folder" + "message": "Itens sem pasta" }, "organizationIsDeactivated": { - "message": "Organization is deactivated" + "message": "A organização está desativada" }, "contactYourOrgAdmin": { - "message": "Items in deactivated organizations cannot be accessed. Contact your organization owner for assistance." + "message": "Itens em organizações desativadas não podem ser acessados. Entre em contato com o proprietário da sua organização para obter assistência." } } diff --git a/apps/browser/src/_locales/pt_PT/messages.json b/apps/browser/src/_locales/pt_PT/messages.json index 81468364b7..07e82877f7 100644 --- a/apps/browser/src/_locales/pt_PT/messages.json +++ b/apps/browser/src/_locales/pt_PT/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Criar conta" }, + "setAStrongPassword": { + "message": "Defina uma palavra-passe forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine a criação da sua conta definindo uma palavra-passe" + }, "login": { "message": "Iniciar sessão" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "A sua nova palavra-passe mestra não cumpre os requisitos da política." }, + "receiveMarketingEmails": { + "message": "Receba e-mails do Bitwarden com anúncios, conselhos e oportunidades de investigação." + }, + "unsubscribe": { + "message": "Anular subscrição" + }, + "atAnyTime": { + "message": "a qualquer altura." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao marcar esta caixa concorda com o seguinte:" }, diff --git a/apps/browser/src/_locales/ro/messages.json b/apps/browser/src/_locales/ro/messages.json index f0be1aa0b0..f80747f5f0 100644 --- a/apps/browser/src/_locales/ro/messages.json +++ b/apps/browser/src/_locales/ro/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Creare cont" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Conectare" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Noua dvs. parolă principală nu îndeplinește cerințele politicii." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, diff --git a/apps/browser/src/_locales/ru/messages.json b/apps/browser/src/_locales/ru/messages.json index 86ffaa4946..7fd7ac16d4 100644 --- a/apps/browser/src/_locales/ru/messages.json +++ b/apps/browser/src/_locales/ru/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Создать аккаунт" }, + "setAStrongPassword": { + "message": "Задайте надежный пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершите создание аккаунта, задав пароль" + }, "login": { "message": "Войти" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новый мастер-пароль не соответствует требованиям политики." }, + "receiveMarketingEmails": { + "message": "Получайте электронные письма от Bitwarden с анонсами, советами и возможностями для исследований." + }, + "unsubscribe": { + "message": "Отписаться" + }, + "atAnyTime": { + "message": "в любое время." + }, + "byContinuingYouAgreeToThe": { + "message": "Продолжая, вы соглашаетесь с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, diff --git a/apps/browser/src/_locales/si/messages.json b/apps/browser/src/_locales/si/messages.json index 8e221eecab..55157abfe5 100644 --- a/apps/browser/src/_locales/si/messages.json +++ b/apps/browser/src/_locales/si/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "ගිණුමක් සාදන්න" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "පිවිසෙන්න" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "ඔබගේ නව ප්රධාන මුරපදය ප්රතිපත්ති අවශ්යතා සපුරාලන්නේ නැත." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "මෙම කොටුව පරීක්ෂා කිරීමෙන් ඔබ පහත සඳහන් දෑ වලට එකඟ වේ:" }, diff --git a/apps/browser/src/_locales/sk/messages.json b/apps/browser/src/_locales/sk/messages.json index 76d28910fe..098d940aa0 100644 --- a/apps/browser/src/_locales/sk/messages.json +++ b/apps/browser/src/_locales/sk/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Vytvoriť účet" }, + "setAStrongPassword": { + "message": "Nastavte silné heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Zdajte heslo na vytvorenie účtu" + }, "login": { "message": "Prihlásiť sa" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Vaše nové heslo nespĺňa pravidlá." }, + "receiveMarketingEmails": { + "message": "Dostávať e-maily od Bitwardenu s oznámeniami, radami a možnosťami výskumu." + }, + "unsubscribe": { + "message": "Odhlásiť sa z odberu" + }, + "atAnyTime": { + "message": "môžete kedykoľvek." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračovaním súhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, diff --git a/apps/browser/src/_locales/sl/messages.json b/apps/browser/src/_locales/sl/messages.json index 7a46d0e50f..ee828c2e69 100644 --- a/apps/browser/src/_locales/sl/messages.json +++ b/apps/browser/src/_locales/sl/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Ustvari račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Prijavi se" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Vaše novo glavno geslo ne ustreza zahtevam." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Strinjam se z naslednjim:" }, diff --git a/apps/browser/src/_locales/sr/messages.json b/apps/browser/src/_locales/sr/messages.json index 0a29c4c2e7..694d6ed1e0 100644 --- a/apps/browser/src/_locales/sr/messages.json +++ b/apps/browser/src/_locales/sr/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Креирај налог" }, + "setAStrongPassword": { + "message": "Поставите јаку лозинку" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завршите креирање налога постављањем лозинке" + }, "login": { "message": "Пријавите се" }, @@ -393,10 +399,10 @@ "message": "Скини омиљено" }, "itemAddedToFavorites": { - "message": "Item added to favorites" + "message": "Ставка је додата у фаворите" }, "itemRemovedFromFavorites": { - "message": "Item removed from favorites" + "message": "Ставка је уклоњена из фаворите" }, "notes": { "message": "Белешке" @@ -1444,7 +1450,7 @@ } }, "editItemHeader": { - "message": "Edit $TYPE$", + "message": "Уреди $TYPE$", "placeholders": { "type": { "content": "$1", @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваша нова главна лозинка не испуњава захтеве смерница." }, + "receiveMarketingEmails": { + "message": "Добијајте е-пошту од Bitwarden-а за најаве, савете и могућности истраживања." + }, + "unsubscribe": { + "message": "Одјави се" + }, + "atAnyTime": { + "message": "било када." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако наставите, слажете се са" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, @@ -3374,7 +3395,7 @@ } }, "autofillTitle": { - "message": "Auto-fill - $ITEMNAME$", + "message": "Ауто-пуњење - $ITEMNAME$", "description": "Title for a button that auto-fills a login item.", "placeholders": { "itemname": { @@ -3384,7 +3405,7 @@ } }, "noValuesToCopy": { - "message": "No values to copy" + "message": "Нема вредности за копирање" }, "assignCollections": { "message": "Додели колекције" diff --git a/apps/browser/src/_locales/sv/messages.json b/apps/browser/src/_locales/sv/messages.json index 2d1ec18341..c675124437 100644 --- a/apps/browser/src/_locales/sv/messages.json +++ b/apps/browser/src/_locales/sv/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Skapa konto" }, + "setAStrongPassword": { + "message": "Ställ in ett starkt lösenord" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Logga in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ditt nya huvudlösenord uppfyller inte kraven i policyn." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "och" + }, "acceptPolicies": { "message": "Genom att markera denna ruta godkänner du följande:" }, diff --git a/apps/browser/src/_locales/te/messages.json b/apps/browser/src/_locales/te/messages.json index 2360493fab..2063dfdca0 100644 --- a/apps/browser/src/_locales/te/messages.json +++ b/apps/browser/src/_locales/te/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Log in" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/th/messages.json b/apps/browser/src/_locales/th/messages.json index a2a64774a0..53d256ed9d 100644 --- a/apps/browser/src/_locales/th/messages.json +++ b/apps/browser/src/_locales/th/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "สร้างบัญชี" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "เข้าสู่ระบบ" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "รหัสผ่านหลักใหม่ของคุณไม่เป็นไปตามข้อกำหนดของนโยบาย" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/browser/src/_locales/tr/messages.json b/apps/browser/src/_locales/tr/messages.json index 192e27a98a..176ee1e8c4 100644 --- a/apps/browser/src/_locales/tr/messages.json +++ b/apps/browser/src/_locales/tr/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Hesap oluştur" }, + "setAStrongPassword": { + "message": "Güçlü bir parola belirleyin" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Parolanızı belirleyerek hesabınızı oluşturmayı tamamlayın" + }, "login": { "message": "Giriş yap" }, @@ -1444,7 +1450,7 @@ } }, "editItemHeader": { - "message": "Edit $TYPE$", + "message": "$TYPE$ düzenle", "placeholders": { "type": { "content": "$1", @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Yeni ana parolanız ilke gereksinimlerini karşılamıyor." }, + "receiveMarketingEmails": { + "message": "Bitwarden'dan duyurular, öneriler ve araştırmalarla ilgili e-postalar alın." + }, + "unsubscribe": { + "message": "İstediğiniz zaman" + }, + "atAnyTime": { + "message": "aboneliğinizi iptal edebilirsiniz." + }, + "byContinuingYouAgreeToThe": { + "message": "Devam ederek şunları kabul etmiş olursunuz:" + }, + "and": { + "message": "ve" + }, "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, diff --git a/apps/browser/src/_locales/uk/messages.json b/apps/browser/src/_locales/uk/messages.json index d8adaaf450..cff1a5720f 100644 --- a/apps/browser/src/_locales/uk/messages.json +++ b/apps/browser/src/_locales/uk/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Створити обліковий запис" }, + "setAStrongPassword": { + "message": "Встановіть надійний пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершіть створення облікового запису, встановивши пароль" + }, "login": { "message": "Увійти" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новий головний пароль не задовольняє вимоги політики." }, + "receiveMarketingEmails": { + "message": "Отримуйте електронні листи від Bitwarden з оголошеннями, порадами та інформацією про нові можливості." + }, + "unsubscribe": { + "message": "Відписатися" + }, + "atAnyTime": { + "message": "можна будь-коли." + }, + "byContinuingYouAgreeToThe": { + "message": "Продовжуючи, ви погоджуєтеся з" + }, + "and": { + "message": "і" + }, "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, diff --git a/apps/browser/src/_locales/vi/messages.json b/apps/browser/src/_locales/vi/messages.json index e2c6cac280..14bdf20795 100644 --- a/apps/browser/src/_locales/vi/messages.json +++ b/apps/browser/src/_locales/vi/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "Tạo tài khoản" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "Đăng nhập" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Mật khẩu chính bạn chọn không đáp ứng yêu cầu." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Bạn đồng ý với những điều sau khi nhấn chọn ô này:" }, diff --git a/apps/browser/src/_locales/zh_CN/messages.json b/apps/browser/src/_locales/zh_CN/messages.json index abe02b08b0..1954cb5bfb 100644 --- a/apps/browser/src/_locales/zh_CN/messages.json +++ b/apps/browser/src/_locales/zh_CN/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "创建账户" }, + "setAStrongPassword": { + "message": "设置强密码" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "设置密码后就能完成账户创建" + }, "login": { "message": "登录" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "您的新主密码不符合策略要求。" }, + "receiveMarketingEmails": { + "message": "接收来自 Bitwarden 的电子邮件,以获取公告、建议和调研。" + }, + "unsubscribe": { + "message": "取消订阅" + }, + "atAnyTime": { + "message": "随时" + }, + "byContinuingYouAgreeToThe": { + "message": "若继续,代表您同意" + }, + "and": { + "message": "以及" + }, "acceptPolicies": { "message": "选中此框表示您同意:" }, diff --git a/apps/browser/src/_locales/zh_TW/messages.json b/apps/browser/src/_locales/zh_TW/messages.json index a09d6750a0..1c80775d6f 100644 --- a/apps/browser/src/_locales/zh_TW/messages.json +++ b/apps/browser/src/_locales/zh_TW/messages.json @@ -16,6 +16,12 @@ "createAccount": { "message": "建立帳戶" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "login": { "message": "登入" }, @@ -1780,6 +1786,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "您新的主密碼不符合原則要求。" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "選中此選取框,即表示您同意下列條款:" }, From f2bf4322b97544960253b2b7fd6cd9064e4bc724 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:50:07 +0000 Subject: [PATCH 03/31] Autosync the updated translations (#9687) Co-authored-by: bitwarden-devops-bot <106330231+bitwarden-devops-bot@users.noreply.github.com> --- apps/desktop/src/locales/af/messages.json | 21 +++++++ apps/desktop/src/locales/ar/messages.json | 21 +++++++ apps/desktop/src/locales/az/messages.json | 21 +++++++ apps/desktop/src/locales/be/messages.json | 21 +++++++ apps/desktop/src/locales/bg/messages.json | 21 +++++++ apps/desktop/src/locales/bn/messages.json | 21 +++++++ apps/desktop/src/locales/bs/messages.json | 21 +++++++ apps/desktop/src/locales/ca/messages.json | 21 +++++++ apps/desktop/src/locales/cs/messages.json | 21 +++++++ apps/desktop/src/locales/cy/messages.json | 21 +++++++ apps/desktop/src/locales/da/messages.json | 21 +++++++ apps/desktop/src/locales/de/messages.json | 21 +++++++ apps/desktop/src/locales/el/messages.json | 21 +++++++ apps/desktop/src/locales/en_GB/messages.json | 21 +++++++ apps/desktop/src/locales/en_IN/messages.json | 21 +++++++ apps/desktop/src/locales/eo/messages.json | 21 +++++++ apps/desktop/src/locales/es/messages.json | 21 +++++++ apps/desktop/src/locales/et/messages.json | 21 +++++++ apps/desktop/src/locales/eu/messages.json | 21 +++++++ apps/desktop/src/locales/fa/messages.json | 21 +++++++ apps/desktop/src/locales/fi/messages.json | 21 +++++++ apps/desktop/src/locales/fil/messages.json | 21 +++++++ apps/desktop/src/locales/fr/messages.json | 45 +++++++++++---- apps/desktop/src/locales/gl/messages.json | 21 +++++++ apps/desktop/src/locales/he/messages.json | 21 +++++++ apps/desktop/src/locales/hi/messages.json | 21 +++++++ apps/desktop/src/locales/hr/messages.json | 21 +++++++ apps/desktop/src/locales/hu/messages.json | 21 +++++++ apps/desktop/src/locales/id/messages.json | 21 +++++++ apps/desktop/src/locales/it/messages.json | 21 +++++++ apps/desktop/src/locales/ja/messages.json | 21 +++++++ apps/desktop/src/locales/ka/messages.json | 21 +++++++ apps/desktop/src/locales/km/messages.json | 21 +++++++ apps/desktop/src/locales/kn/messages.json | 21 +++++++ apps/desktop/src/locales/ko/messages.json | 21 +++++++ apps/desktop/src/locales/lt/messages.json | 21 +++++++ apps/desktop/src/locales/lv/messages.json | 21 +++++++ apps/desktop/src/locales/me/messages.json | 21 +++++++ apps/desktop/src/locales/ml/messages.json | 21 +++++++ apps/desktop/src/locales/mr/messages.json | 21 +++++++ apps/desktop/src/locales/my/messages.json | 21 +++++++ apps/desktop/src/locales/nb/messages.json | 21 +++++++ apps/desktop/src/locales/ne/messages.json | 21 +++++++ apps/desktop/src/locales/nl/messages.json | 21 +++++++ apps/desktop/src/locales/nn/messages.json | 21 +++++++ apps/desktop/src/locales/or/messages.json | 21 +++++++ apps/desktop/src/locales/pl/messages.json | 21 +++++++ apps/desktop/src/locales/pt_BR/messages.json | 61 +++++++++++++------- apps/desktop/src/locales/pt_PT/messages.json | 21 +++++++ apps/desktop/src/locales/ro/messages.json | 21 +++++++ apps/desktop/src/locales/ru/messages.json | 21 +++++++ apps/desktop/src/locales/si/messages.json | 21 +++++++ apps/desktop/src/locales/sk/messages.json | 21 +++++++ apps/desktop/src/locales/sl/messages.json | 21 +++++++ apps/desktop/src/locales/sr/messages.json | 21 +++++++ apps/desktop/src/locales/sv/messages.json | 21 +++++++ apps/desktop/src/locales/te/messages.json | 21 +++++++ apps/desktop/src/locales/th/messages.json | 21 +++++++ apps/desktop/src/locales/tr/messages.json | 21 +++++++ apps/desktop/src/locales/uk/messages.json | 21 +++++++ apps/desktop/src/locales/vi/messages.json | 21 +++++++ apps/desktop/src/locales/zh_CN/messages.json | 21 +++++++ apps/desktop/src/locales/zh_TW/messages.json | 21 +++++++ 63 files changed, 1355 insertions(+), 32 deletions(-) diff --git a/apps/desktop/src/locales/af/messages.json b/apps/desktop/src/locales/af/messages.json index 42970d49be..af97c829f5 100644 --- a/apps/desktop/src/locales/af/messages.json +++ b/apps/desktop/src/locales/af/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Skep Rekening" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Teken Aan" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "U nuwe hoofwagwoord voldoen nie aan die beleidsvereistes nie." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Deur hierdie kassie af te merk stem u in tot die volgende:" }, diff --git a/apps/desktop/src/locales/ar/messages.json b/apps/desktop/src/locales/ar/messages.json index 32b4b48f51..13e68e0cdc 100644 --- a/apps/desktop/src/locales/ar/messages.json +++ b/apps/desktop/src/locales/ar/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "إنشاء حساب" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "تسجيل الدخول" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "كلمة المرور الرئيسية الجديدة لا تفي بمتطلبات السياسة العامة." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "من خلال تحديد هذا المربع فإنك توافق على ما يلي:" }, diff --git a/apps/desktop/src/locales/az/messages.json b/apps/desktop/src/locales/az/messages.json index 052b3ac3a9..431aa24c5a 100644 --- a/apps/desktop/src/locales/az/messages.json +++ b/apps/desktop/src/locales/az/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Hesab yarat" }, + "setAStrongPassword": { + "message": "Güclü bir parol təyin et" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Bir parol təyin edərək hesabınızı yaratmağı başa çatdırın" + }, "logIn": { "message": "Giriş et" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Yeni ana parolunuz siyasət tələblərini qarşılamır." }, + "receiveMarketingEmails": { + "message": "Elanlar, məsləhətlər və araşdırma fürsətləri üçün Bitwarden-dən e-poçt alın." + }, + "unsubscribe": { + "message": "Abunəlikdən çıx" + }, + "atAnyTime": { + "message": "istənilən vaxt." + }, + "byContinuingYouAgreeToThe": { + "message": "Davam edərək, bunlarla razılaşırsınız" + }, + "and": { + "message": "və" + }, "acceptPolicies": { "message": "Bu qutunu işarələyərək aşağıdakılarla razılaşırsınız:" }, diff --git a/apps/desktop/src/locales/be/messages.json b/apps/desktop/src/locales/be/messages.json index 075318ad60..886492794e 100644 --- a/apps/desktop/src/locales/be/messages.json +++ b/apps/desktop/src/locales/be/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Стварыць уліковы запіс" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Увайсці" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новы асноўны пароль не адпавядае патрабаванням палітыкі." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ставячы гэты сцяжок вы пагаджаецеся з наступным:" }, diff --git a/apps/desktop/src/locales/bg/messages.json b/apps/desktop/src/locales/bg/messages.json index 68e217d3d2..9936be751e 100644 --- a/apps/desktop/src/locales/bg/messages.json +++ b/apps/desktop/src/locales/bg/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Създаване на абонамент" }, + "setAStrongPassword": { + "message": "Използвайте сложна парола" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завършете регистрацията си като зададете парола" + }, "logIn": { "message": "Вписване" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Паролата ви не отговаря на политиките." }, + "receiveMarketingEmails": { + "message": "Получавайте е-писма от Битоурден за новини, съвети и възможности за проучвания." + }, + "unsubscribe": { + "message": "Отписване" + }, + "atAnyTime": { + "message": "по всяко време." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако продължите, Вие се съгласявате с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Чрез тази отметка вие се съгласявате със следното:" }, diff --git a/apps/desktop/src/locales/bn/messages.json b/apps/desktop/src/locales/bn/messages.json index fa0aa398ef..23bebe6a3c 100644 --- a/apps/desktop/src/locales/bn/messages.json +++ b/apps/desktop/src/locales/bn/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "অ্যাকাউন্ট তৈরি করুন" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "প্রবেশ করুন" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "আপনার নতুন মূল পাসওয়ার্ড নীতির প্রয়োজনীয়তা পূরণ করে না।" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "এই বাক্সটি টিক করে আপনি নিম্নলিখিতগুলিতে সম্মত হন:" }, diff --git a/apps/desktop/src/locales/bs/messages.json b/apps/desktop/src/locales/bs/messages.json index 2d9e2ebba0..8a594b1c5a 100644 --- a/apps/desktop/src/locales/bs/messages.json +++ b/apps/desktop/src/locales/bs/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Napravi račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Prijavite se" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/ca/messages.json b/apps/desktop/src/locales/ca/messages.json index 207c1e553f..3fd6046dc0 100644 --- a/apps/desktop/src/locales/ca/messages.json +++ b/apps/desktop/src/locales/ca/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Crea un compte" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Inicia sessió" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "La nova contrasenya principal no compleix els requisits de la política." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Si activeu aquesta casella, indiqueu que esteu d’acord amb el següent:" }, diff --git a/apps/desktop/src/locales/cs/messages.json b/apps/desktop/src/locales/cs/messages.json index f0990d9f9f..9b7b5af9ee 100644 --- a/apps/desktop/src/locales/cs/messages.json +++ b/apps/desktop/src/locales/cs/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Vytvořit účet" }, + "setAStrongPassword": { + "message": "Nastavit hlavní heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Dokončete vytváření účtu nastavením hesla" + }, "logIn": { "message": "Přihlásit se" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Vaše nové hlavní heslo nesplňuje požadavky zásad." }, + "receiveMarketingEmails": { + "message": "Získejte e-maily od Bitwardenu pro oznámení, poradenství a výzkumné příležitosti." + }, + "unsubscribe": { + "message": "Odhlásit odběr" + }, + "atAnyTime": { + "message": "kdykoli." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračováním souhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Zaškrtnutím tohoto políčka souhlasíte s následujícím:" }, diff --git a/apps/desktop/src/locales/cy/messages.json b/apps/desktop/src/locales/cy/messages.json index e92ffae715..41eb63f6ab 100644 --- a/apps/desktop/src/locales/cy/messages.json +++ b/apps/desktop/src/locales/cy/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/da/messages.json b/apps/desktop/src/locales/da/messages.json index 96ae76f858..d57390183e 100644 --- a/apps/desktop/src/locales/da/messages.json +++ b/apps/desktop/src/locales/da/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Opret konto" }, + "setAStrongPassword": { + "message": "Indstil en stærk adgangskode" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Afslut kontooprettelsen med at indstille en adgangskode" + }, "logIn": { "message": "Log ind" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Din nye hovedadgangskode opfylder ikke politikkravene." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Afmeld" + }, + "atAnyTime": { + "message": "til enhver tid." + }, + "byContinuingYouAgreeToThe": { + "message": "Ved at fortsætte, accepterer du" + }, + "and": { + "message": "og" + }, "acceptPolicies": { "message": "Ved at afkrydse dette felt accepterer du flg.:" }, diff --git a/apps/desktop/src/locales/de/messages.json b/apps/desktop/src/locales/de/messages.json index 7b366036e9..8d622f77b6 100644 --- a/apps/desktop/src/locales/de/messages.json +++ b/apps/desktop/src/locales/de/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Konto erstellen" }, + "setAStrongPassword": { + "message": "Ein starkes Passwort festlegen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Schließe die Erstellung deines Kontos ab, indem du ein Passwort festlegst" + }, "logIn": { "message": "Anmelden" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Dein neues Masterpasswort entspricht nicht den Anforderungen der Richtlinie." }, + "receiveMarketingEmails": { + "message": "Erhalte E-Mails von Bitwarden für Ankündigungen, Ratschläge und Forschungsmöglichkeiten." + }, + "unsubscribe": { + "message": "Deabonnieren" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Durch Anwählen dieses Kästchens erklärst du dich mit folgendem einverstanden:" }, diff --git a/apps/desktop/src/locales/el/messages.json b/apps/desktop/src/locales/el/messages.json index 21ddb65a9e..29bac770e6 100644 --- a/apps/desktop/src/locales/el/messages.json +++ b/apps/desktop/src/locales/el/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Δημιουργία Λογαριασμού" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Είσοδος" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ο νέος κύριος κωδικός δεν πληροί τις απαιτήσεις πολιτικής." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Επιλέγοντας αυτό το πλαίσιο, συμφωνείτε με τα εξής:" }, diff --git a/apps/desktop/src/locales/en_GB/messages.json b/apps/desktop/src/locales/en_GB/messages.json index f15b661034..42234c9a3b 100644 --- a/apps/desktop/src/locales/en_GB/messages.json +++ b/apps/desktop/src/locales/en_GB/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/en_IN/messages.json b/apps/desktop/src/locales/en_IN/messages.json index 1d4809c927..af23f68477 100644 --- a/apps/desktop/src/locales/en_IN/messages.json +++ b/apps/desktop/src/locales/en_IN/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/eo/messages.json b/apps/desktop/src/locales/eo/messages.json index 146a123107..caa9039582 100644 --- a/apps/desktop/src/locales/eo/messages.json +++ b/apps/desktop/src/locales/eo/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/es/messages.json b/apps/desktop/src/locales/es/messages.json index a5b352e145..ef5fb9b8e5 100644 --- a/apps/desktop/src/locales/es/messages.json +++ b/apps/desktop/src/locales/es/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Crear cuenta" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Identificarse" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Su nueva contraseña maestra no cumple con los requisitos de la política." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Al seleccionar esta casilla, acepto lo siguiente:" }, diff --git a/apps/desktop/src/locales/et/messages.json b/apps/desktop/src/locales/et/messages.json index c7d48fd399..b22fdee70d 100644 --- a/apps/desktop/src/locales/et/messages.json +++ b/apps/desktop/src/locales/et/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Konto loomine" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Logi sisse" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Uus ülemparool ei vasta eeskirjades väljatoodud tingimustele." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Märkeruudu markeerimisel nõustud järgnevaga:" }, diff --git a/apps/desktop/src/locales/eu/messages.json b/apps/desktop/src/locales/eu/messages.json index 89a63fbe91..2da04b0b40 100644 --- a/apps/desktop/src/locales/eu/messages.json +++ b/apps/desktop/src/locales/eu/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Sortu kontua" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Hasi saioa" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Zure pasahitz nagusi berriak ez ditu baldintzak betetzen." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Laukitxo hau markatzean, honakoa onartzen duzu:" }, diff --git a/apps/desktop/src/locales/fa/messages.json b/apps/desktop/src/locales/fa/messages.json index 6852f1e1ec..eb4e034825 100644 --- a/apps/desktop/src/locales/fa/messages.json +++ b/apps/desktop/src/locales/fa/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "ایجاد حساب کاربری" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "ورود" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "کلمه عبور اصلی جدید شما از شرایط سیاست پیروی نمی‌کند." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "با علامت زدن این کادر با موارد زیر موافقت می‌کنید:" }, diff --git a/apps/desktop/src/locales/fi/messages.json b/apps/desktop/src/locales/fi/messages.json index d83f6c7d4e..de3490ac9b 100644 --- a/apps/desktop/src/locales/fi/messages.json +++ b/apps/desktop/src/locales/fi/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Luo tili" }, + "setAStrongPassword": { + "message": "Aseta vahva salasana" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Viimeistele tilin luonti asettamalla salasana" + }, "logIn": { "message": "Kirjaudu" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Uusi pääsalasanasi ei täytä käytännön määrittämiä vaatimuksia." }, + "receiveMarketingEmails": { + "message": "Vastaanota Bitwardenilta uutiskirjeitä julkaisuista, tukiresursseista ja tutkimusmahdollisuuksista." + }, + "unsubscribe": { + "message": "Lopeta tilaus" + }, + "atAnyTime": { + "message": "milloin tahansa." + }, + "byContinuingYouAgreeToThe": { + "message": "Jatkaessasi hyväksyt" + }, + "and": { + "message": "ja" + }, "acceptPolicies": { "message": "Valitsemalla tämän hyväksyt seuraavat:" }, diff --git a/apps/desktop/src/locales/fil/messages.json b/apps/desktop/src/locales/fil/messages.json index fe1ef41771..bfc785ed0c 100644 --- a/apps/desktop/src/locales/fil/messages.json +++ b/apps/desktop/src/locales/fil/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Gumawa ng Account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Mag-log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ang iyong bagong master password ay hindi nakakatugon sa mga kinakailangan sa patakaran." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Sa pamamagitan ng pagsuri sa kahong ito sumasang ayon ka sa mga sumusunod:" }, diff --git a/apps/desktop/src/locales/fr/messages.json b/apps/desktop/src/locales/fr/messages.json index e971256036..b1a8037cab 100644 --- a/apps/desktop/src/locales/fr/messages.json +++ b/apps/desktop/src/locales/fr/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Créer un compte" }, + "setAStrongPassword": { + "message": "Définir un mot de passe fort" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Terminer la création de votre compte en définissant un mot de passe" + }, "logIn": { "message": "Se connecter" }, @@ -696,13 +702,13 @@ "message": "Spécifiez l'URL de base de votre installation Bitwarden auto-hébergée." }, "selfHostedBaseUrlHint": { - "message": "Specify the base URL of your on-premises hosted Bitwarden installation. Example: https://bitwarden.company.com" + "message": "Spécifiez l'URL de base de votre installation Bitwarden hébergée sur site. Exemple : https://bitwarden.company.com" }, "selfHostedCustomEnvHeader": { - "message": "For advanced configuration, you can specify the base URL of each service independently." + "message": "Pour une configuration avancée, vous pouvez spécifier l'URL de base de chaque service indépendamment." }, "selfHostedEnvFormInvalid": { - "message": "You must add either the base Server URL or at least one custom environment." + "message": "Vous devez ajouter soit l'URL du serveur de base, soit au moins un environnement personnalisé." }, "customEnvironment": { "message": "Environnement personnalisé" @@ -753,7 +759,7 @@ "message": "Déconnecté" }, "loggedOutDesc": { - "message": "You have been logged out of your account." + "message": "Vous avez été déconnecté de votre compte." }, "loginExpired": { "message": "Votre session a expiré." @@ -1225,10 +1231,10 @@ } }, "errorRefreshingAccessToken": { - "message": "Access Token Refresh Error" + "message": "Erreur d'actualisation du jeton d'accès" }, "errorRefreshingAccessTokenDesc": { - "message": "No refresh token or API keys found. Please try logging out and logging back in." + "message": "Aucun jeton d'actualisation ni clé API trouvés. Veuillez essayer de vous déconnecter et de vous reconnecter." }, "help": { "message": "Aide" @@ -1327,22 +1333,22 @@ "message": "Format de fichier" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "L'export de ce fichier sera protégé par un mot de passe qui sera nécessaire pour déchiffrer le fichier." }, "filePassword": { - "message": "File password" + "message": "Mot de passe du fichier" }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "Ce mot de passe sera utilisé pour exporter et importer ce fichier" }, "accountRestrictedOptionDescription": { - "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Utilisez la clé de chiffrement de votre compte, dérivée du nom d'utilisateur et du mot de passe principal de votre compte, pour chiffrer l'export et restreindre l'import au seul compte Bitwarden actuel." }, "passwordProtected": { - "message": "Password protected" + "message": "Protégé par mot de passe" }, "passwordProtectedOptionDescription": { - "message": "Set a file password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Définissez un mot de passe de fichier pour chiffrer l'export et déchiffrer son import sur n'importe quel compte Bitwarden." }, "exportTypeHeading": { "message": "Export type" @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Votre nouveau mot de passe principal ne répond pas aux exigences de politique de sécurité." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "En cochant cette case vous acceptez ce qui suit :" }, diff --git a/apps/desktop/src/locales/gl/messages.json b/apps/desktop/src/locales/gl/messages.json index d9b67aee6f..7124e246f3 100644 --- a/apps/desktop/src/locales/gl/messages.json +++ b/apps/desktop/src/locales/gl/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/he/messages.json b/apps/desktop/src/locales/he/messages.json index 3f3ef43c46..8839bb2e55 100644 --- a/apps/desktop/src/locales/he/messages.json +++ b/apps/desktop/src/locales/he/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "צור חשבון" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "התחבר" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "הסיסמה הראשית החדשה השלך לא עומדת בדרישות המדיניות." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "סימון תיבה זו מהווה את הסכמתך לתנאים הבאים:" }, diff --git a/apps/desktop/src/locales/hi/messages.json b/apps/desktop/src/locales/hi/messages.json index 7bd57bf691..07ff9e9f37 100644 --- a/apps/desktop/src/locales/hi/messages.json +++ b/apps/desktop/src/locales/hi/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/hr/messages.json b/apps/desktop/src/locales/hr/messages.json index 190e32d91e..6261f28cee 100644 --- a/apps/desktop/src/locales/hr/messages.json +++ b/apps/desktop/src/locales/hr/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Stvori račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Prijavi se" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Tvoja nova glavna lozinka ne ispunjava zahtjeve." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Označavanjem ove kućice slažete se sa sljedećim:" }, diff --git a/apps/desktop/src/locales/hu/messages.json b/apps/desktop/src/locales/hu/messages.json index 78c7797ff1..cd797d3da1 100644 --- a/apps/desktop/src/locales/hu/messages.json +++ b/apps/desktop/src/locales/hu/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Fiók létrehozása" }, + "setAStrongPassword": { + "message": "Erős jelszó beállítása" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "A fiók létrehozásának befejezése jelszó beállításával" + }, "logIn": { "message": "Bejelentkezés" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Az új mesterjelszó nem felel meg a szabály követelményeknek." }, + "receiveMarketingEmails": { + "message": "Emaileket kaphatunk a Bitwardentől bejelentésekről, tanácsokról és kutatási lehetőségekről." + }, + "unsubscribe": { + "message": "Leiratkozás" + }, + "atAnyTime": { + "message": "bármikor." + }, + "byContinuingYouAgreeToThe": { + "message": "A folytatással elfogadjuk" + }, + "and": { + "message": "és" + }, "acceptPolicies": { "message": "A kapcsoló bekapcsolásával egyetértünk a következőkkel:" }, diff --git a/apps/desktop/src/locales/id/messages.json b/apps/desktop/src/locales/id/messages.json index 74f3fa79f4..1002f84048 100644 --- a/apps/desktop/src/locales/id/messages.json +++ b/apps/desktop/src/locales/id/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Buat Akun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Masuk" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Kata sandi utama Anda yang baru tidak memenuhi persyaratan kebijakan." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dengan mencentang kotak ini, anda menyetujui yang berikut:" }, diff --git a/apps/desktop/src/locales/it/messages.json b/apps/desktop/src/locales/it/messages.json index dfc1f92eaa..474faaf376 100644 --- a/apps/desktop/src/locales/it/messages.json +++ b/apps/desktop/src/locales/it/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Crea account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Accedi" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "La tua nuova password principale non soddisfa i requisiti di sicurezza." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Selezionando questa casella accetti quanto segue:" }, diff --git a/apps/desktop/src/locales/ja/messages.json b/apps/desktop/src/locales/ja/messages.json index 9d9b0b28f1..da9a831490 100644 --- a/apps/desktop/src/locales/ja/messages.json +++ b/apps/desktop/src/locales/ja/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "アカウントの作成" }, + "setAStrongPassword": { + "message": "強力なパスワードを設定する" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "パスワードを設定してアカウントの作成を完了してください" + }, "logIn": { "message": "ログイン" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "新しいマスターパスワードは最低要件を満たしていません。" }, + "receiveMarketingEmails": { + "message": "Bitwarden からのお知らせ、アドバイス、アンケート調査等のメールを受信します。" + }, + "unsubscribe": { + "message": "配信停止" + }, + "atAnyTime": { + "message": "はいつでもできます。" + }, + "byContinuingYouAgreeToThe": { + "message": "続行すると以下に同意したものとみなします:" + }, + "and": { + "message": "と" + }, "acceptPolicies": { "message": "以下に同意しチェックします:" }, diff --git a/apps/desktop/src/locales/ka/messages.json b/apps/desktop/src/locales/ka/messages.json index d9b67aee6f..7124e246f3 100644 --- a/apps/desktop/src/locales/ka/messages.json +++ b/apps/desktop/src/locales/ka/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/km/messages.json b/apps/desktop/src/locales/km/messages.json index d9b67aee6f..7124e246f3 100644 --- a/apps/desktop/src/locales/km/messages.json +++ b/apps/desktop/src/locales/km/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/kn/messages.json b/apps/desktop/src/locales/kn/messages.json index 5b53742fb9..63c67251c2 100644 --- a/apps/desktop/src/locales/kn/messages.json +++ b/apps/desktop/src/locales/kn/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "ಖಾತೆ ತೆರೆ" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "ಲಾಗಿನ್" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "ನಿಮ್ಮ ಹೊಸ ಮಾಸ್ಟರ್ ಪಾಸ್‌ವರ್ಡ್ ನೀತಿಯ ಅವಶ್ಯಕತೆಗಳನ್ನು ಪೂರೈಸುವುದಿಲ್ಲ." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ಈ ಪೆಟ್ಟಿಗೆಯನ್ನು ಪರಿಶೀಲಿಸುವ ಮೂಲಕ ನೀವು ಈ ಕೆಳಗಿನವುಗಳನ್ನು ಒಪ್ಪುತ್ತೀರಿ:" }, diff --git a/apps/desktop/src/locales/ko/messages.json b/apps/desktop/src/locales/ko/messages.json index d8686af978..33e31f00c0 100644 --- a/apps/desktop/src/locales/ko/messages.json +++ b/apps/desktop/src/locales/ko/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "계정 만들기" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "로그인" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "새 마스터 비밀번호가 정책 요구 사항을 따르지 않습니다." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "이 박스를 체크하면 다음에 동의하는 것으로 간주됩니다:" }, diff --git a/apps/desktop/src/locales/lt/messages.json b/apps/desktop/src/locales/lt/messages.json index 726439fe48..9ad866d75a 100644 --- a/apps/desktop/src/locales/lt/messages.json +++ b/apps/desktop/src/locales/lt/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Sukurti paskyrą" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Prisijungti" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Jūsų naujasis pagrindinis slaptažodis neatitinka politikos reikalavimų." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Pažymėdami šį laukelį, sutinkate su šiais dalykais:" }, diff --git a/apps/desktop/src/locales/lv/messages.json b/apps/desktop/src/locales/lv/messages.json index fa8d1a50bc..67d2bd1ea3 100644 --- a/apps/desktop/src/locales/lv/messages.json +++ b/apps/desktop/src/locales/lv/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Izveidot kontu" }, + "setAStrongPassword": { + "message": "Jāiestata droša parole" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Jāpabeidz sava konta izveida ar paroles iestatīšanu" + }, "logIn": { "message": "Pieteikties" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Jaunā galvenā parole neatbilst nosacījumu prasībām." }, + "receiveMarketingEmails": { + "message": "Saņemt e-pasta ziņojumus no Bitwarden par paziņojumiem, padomiem un izpētes iespējām." + }, + "unsubscribe": { + "message": "Atteikt abonēšanu" + }, + "atAnyTime": { + "message": "jebkurā laikā." + }, + "byContinuingYouAgreeToThe": { + "message": "Turpinot tiek sniegta piekrišana" + }, + "and": { + "message": "un" + }, "acceptPolicies": { "message": "Ar šīs rūtiņas atzīmēšanu tiek piekrists sekojošajam:" }, diff --git a/apps/desktop/src/locales/me/messages.json b/apps/desktop/src/locales/me/messages.json index 42238a63eb..4931bf14a5 100644 --- a/apps/desktop/src/locales/me/messages.json +++ b/apps/desktop/src/locales/me/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Kreiraj nalog" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Prijavi se" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Označavanjem ovog polja pristajete na sledeće:" }, diff --git a/apps/desktop/src/locales/ml/messages.json b/apps/desktop/src/locales/ml/messages.json index 597c61a9bb..78e7444a68 100644 --- a/apps/desktop/src/locales/ml/messages.json +++ b/apps/desktop/src/locales/ml/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "അക്കൗണ്ട് സൃഷ്ടിക്കുക" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "പ്രവേശിക്കുക" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "നിങ്ങളുടെ പുതിയ മാസ്റ്റർ പാസ്‌വേഡ് നയ ആവശ്യകതകൾ നിറവേറ്റുന്നില്ല." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "ഈ ബോക്സ് ചെക്കുചെയ്യുന്നതിലൂടെ നിങ്ങൾ ഇനിപ്പറയുന്നവ അംഗീകരിക്കുന്നു:" }, diff --git a/apps/desktop/src/locales/mr/messages.json b/apps/desktop/src/locales/mr/messages.json index d9b67aee6f..7124e246f3 100644 --- a/apps/desktop/src/locales/mr/messages.json +++ b/apps/desktop/src/locales/mr/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/my/messages.json b/apps/desktop/src/locales/my/messages.json index b3e3915c43..7df63346c0 100644 --- a/apps/desktop/src/locales/my/messages.json +++ b/apps/desktop/src/locales/my/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/nb/messages.json b/apps/desktop/src/locales/nb/messages.json index d3880df4db..85fc7f950e 100644 --- a/apps/desktop/src/locales/nb/messages.json +++ b/apps/desktop/src/locales/nb/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Opprett en konto" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Logg på" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Det nye hovedpassordet ditt oppfyller ikke vilkårene." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Ved å huke av i denne boksen sier du deg enig i følgende:" }, diff --git a/apps/desktop/src/locales/ne/messages.json b/apps/desktop/src/locales/ne/messages.json index bf64ebd43c..cac0b7d6b3 100644 --- a/apps/desktop/src/locales/ne/messages.json +++ b/apps/desktop/src/locales/ne/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/nl/messages.json b/apps/desktop/src/locales/nl/messages.json index 25734ff4bf..b7e12b8e37 100644 --- a/apps/desktop/src/locales/nl/messages.json +++ b/apps/desktop/src/locales/nl/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Account aanmaken" }, + "setAStrongPassword": { + "message": "Sterk wachtwoord instellen" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Rond het aanmaken van je account af met het instellen van een wachtwoord" + }, "logIn": { "message": "Inloggen" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Je nieuwe hoofdwachtwoord voldoet niet aan de beleidseisen." }, + "receiveMarketingEmails": { + "message": "Ontvang e-mailberichten van Bitwarden voor aankondigingen, advies en onderzoeksmogelijkheden." + }, + "unsubscribe": { + "message": "Afmelden" + }, + "atAnyTime": { + "message": "op ieder moment." + }, + "byContinuingYouAgreeToThe": { + "message": "Door verder te gaan, ga je akkoord met de" + }, + "and": { + "message": "en" + }, "acceptPolicies": { "message": "Door dit vakje aan te vinken, ga je akkoord met het volgende:" }, diff --git a/apps/desktop/src/locales/nn/messages.json b/apps/desktop/src/locales/nn/messages.json index 23e3b5d69f..f16a371820 100644 --- a/apps/desktop/src/locales/nn/messages.json +++ b/apps/desktop/src/locales/nn/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Opprett konto" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Logg inn" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/or/messages.json b/apps/desktop/src/locales/or/messages.json index f3d78c2358..f261c67aa1 100644 --- a/apps/desktop/src/locales/or/messages.json +++ b/apps/desktop/src/locales/or/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/pl/messages.json b/apps/desktop/src/locales/pl/messages.json index 703e50c35f..d949f1c1e7 100644 --- a/apps/desktop/src/locales/pl/messages.json +++ b/apps/desktop/src/locales/pl/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Utwórz konto" }, + "setAStrongPassword": { + "message": "Ustaw silne hasło" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Ukończ tworzenie konta poprzez ustawienie hasła" + }, "logIn": { "message": "Zaloguj się" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Nowe hasło główne nie spełnia wymaganych zasad." }, + "receiveMarketingEmails": { + "message": "Otrzymuj e-maile od Bitwarden z ogłoszeniami, poradami i badaniami." + }, + "unsubscribe": { + "message": "Anuluj subskrypcję" + }, + "atAnyTime": { + "message": "w każdej chwili." + }, + "byContinuingYouAgreeToThe": { + "message": "Kontynuując, zgadzasz się na" + }, + "and": { + "message": "i" + }, "acceptPolicies": { "message": "Zaznaczając tę opcję, akceptujesz:" }, diff --git a/apps/desktop/src/locales/pt_BR/messages.json b/apps/desktop/src/locales/pt_BR/messages.json index 8678917422..c4057ff318 100644 --- a/apps/desktop/src/locales/pt_BR/messages.json +++ b/apps/desktop/src/locales/pt_BR/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Criar Conta" }, + "setAStrongPassword": { + "message": "Defina uma senha forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine de criar a sua conta definindo uma senha" + }, "logIn": { "message": "Iniciar sessão" }, @@ -696,13 +702,13 @@ "message": "Especifique a URL de base da sua instalação local do Bitwarden." }, "selfHostedBaseUrlHint": { - "message": "Specify the base URL of your on-premises hosted Bitwarden installation. Example: https://bitwarden.company.com" + "message": "Especifique a URL de base da sua instalação local do Bitwarden. Exemplo: https://bitwarden.company.com" }, "selfHostedCustomEnvHeader": { - "message": "For advanced configuration, you can specify the base URL of each service independently." + "message": "Para usuários avançados. Você pode especificar a URL de base de cada serviço independentemente." }, "selfHostedEnvFormInvalid": { - "message": "You must add either the base Server URL or at least one custom environment." + "message": "Você deve adicionar um URL do servidor de base ou pelo menos um ambiente personalizado." }, "customEnvironment": { "message": "Ambiente Personalizado" @@ -753,7 +759,7 @@ "message": "Sessão encerrada" }, "loggedOutDesc": { - "message": "You have been logged out of your account." + "message": "Você foi desconectado de sua conta." }, "loginExpired": { "message": "A sua sessão expirou." @@ -1225,10 +1231,10 @@ } }, "errorRefreshingAccessToken": { - "message": "Access Token Refresh Error" + "message": "Erro ao Atualizar Token" }, "errorRefreshingAccessTokenDesc": { - "message": "No refresh token or API keys found. Please try logging out and logging back in." + "message": "Nenhum token de atualização ou chave de API foi encontrado. Tente sair e entrar novamente." }, "help": { "message": "Ajuda" @@ -1318,7 +1324,7 @@ "description": "ex. Date this password was updated" }, "exportFrom": { - "message": "Export from" + "message": "Exportar de" }, "exportVault": { "message": "Exportar cofre" @@ -1327,31 +1333,31 @@ "message": "Formato do arquivo" }, "fileEncryptedExportWarningDesc": { - "message": "This file export will be password protected and require the file password to decrypt." + "message": "Esta arquivo de exportação será protegido por senha e precisará da mesma para ser descriptografado." }, "filePassword": { - "message": "File password" + "message": "Senha do arquivo" }, "exportPasswordDescription": { - "message": "This password will be used to export and import this file" + "message": "Esta senha será usada para exportar e importar este arquivo" }, "accountRestrictedOptionDescription": { - "message": "Use your account encryption key, derived from your account's username and Master Password, to encrypt the export and restrict import to only the current Bitwarden account." + "message": "Use sua chave criptográfica da conta, derivada do nome de usuário e Senha Mestra da sua conta, para criptografar a exportação e restringir importação para apenas a conta atual do Bitwarden." }, "passwordProtected": { - "message": "Password protected" + "message": "Protegido por senha" }, "passwordProtectedOptionDescription": { - "message": "Set a file password to encrypt the export and import it to any Bitwarden account using the password for decryption." + "message": "Defina uma senha de arquivo para criptografar a exportação e importá-la para qualquer conta do Bitwarden usando a senha para descriptografia." }, "exportTypeHeading": { - "message": "Export type" + "message": "Tipo da exportação" }, "accountRestricted": { - "message": "Account restricted" + "message": "Conta restrita" }, "filePasswordAndConfirmFilePasswordDoNotMatch": { - "message": "“File password” and “Confirm file password“ do not match." + "message": "\"Senha do arquivo\" e \"Confirmação de senha\" não correspondem." }, "hCaptchaUrl": { "message": "hCaptcha Url", @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "A sua nova senha mestra não cumpre aos requisitos da política." }, + "receiveMarketingEmails": { + "message": "Obtenha e-mails do Bitwarden para anúncios, conselhos e oportunidades de pesquisa." + }, + "unsubscribe": { + "message": "Cancelar subscrição" + }, + "atAnyTime": { + "message": "a qualquer momento." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, você concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao marcar esta caixa, você concorda com o seguinte:" }, @@ -2120,10 +2141,10 @@ } }, "exportingOrganizationVaultTitle": { - "message": "Exporting organization vault" + "message": "Exportando cofre da organização" }, "exportingOrganizationVaultDesc": { - "message": "Only the organization vault associated with $ORGANIZATION$ will be exported. Items in individual vaults or other organizations will not be included.", + "message": "Apenas o cofre da organização associado com $ORGANIZATION$ será exportado. Itens do cofre pessoal e itens de outras organizações não serão incluídos.", "placeholders": { "organization": { "content": "$1", @@ -2487,10 +2508,10 @@ "message": "Importante:" }, "accessTokenUnableToBeDecrypted": { - "message": "You have been logged out because your access token could not be decrypted. Please log in again to resolve this issue." + "message": "Você foi desconectado porque seu token de acesso não pôde ser descriptografado. Por favor, faça o login novamente para resolver esse problema." }, "refreshTokenSecureStorageRetrievalFailure": { - "message": "You have been logged out because your refresh token could not be retrieved. Please log in again to resolve this issue." + "message": "Você foi desconectado porque seu token de atualização não pôde ser recuperado. Por favor, faça o login novamente para resolver esse problema." }, "masterPasswordHint": { "message": "A sua senha mestra não pode ser recuperada se você esquecê-la!" diff --git a/apps/desktop/src/locales/pt_PT/messages.json b/apps/desktop/src/locales/pt_PT/messages.json index 0360ad5043..f74cbfd05a 100644 --- a/apps/desktop/src/locales/pt_PT/messages.json +++ b/apps/desktop/src/locales/pt_PT/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Criar conta" }, + "setAStrongPassword": { + "message": "Defina uma palavra-passe forte" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Termine a criação da sua conta definindo uma palavra-passe" + }, "logIn": { "message": "Iniciar sessão" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "A sua nova palavra-passe mestra não cumpre os requisitos da política." }, + "receiveMarketingEmails": { + "message": "Receba e-mails do Bitwarden com anúncios, conselhos e oportunidades de investigação." + }, + "unsubscribe": { + "message": "Anular subscrição" + }, + "atAnyTime": { + "message": "a qualquer altura." + }, + "byContinuingYouAgreeToThe": { + "message": "Ao continuar, concorda com os" + }, + "and": { + "message": "e" + }, "acceptPolicies": { "message": "Ao marcar esta caixa concorda com o seguinte:" }, diff --git a/apps/desktop/src/locales/ro/messages.json b/apps/desktop/src/locales/ro/messages.json index 66182bfcba..a42391cc20 100644 --- a/apps/desktop/src/locales/ro/messages.json +++ b/apps/desktop/src/locales/ro/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Creare cont" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Conectare" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Noua dvs. parolă principală nu îndeplinește cerințele politicii." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "Dacă bifați această casetă sunteți de acord cu următoarele:" }, diff --git a/apps/desktop/src/locales/ru/messages.json b/apps/desktop/src/locales/ru/messages.json index 6aa413d9f1..b328e3f2c2 100644 --- a/apps/desktop/src/locales/ru/messages.json +++ b/apps/desktop/src/locales/ru/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Создать аккаунт" }, + "setAStrongPassword": { + "message": "Задайте надежный пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершите создание аккаунта, задав пароль" + }, "logIn": { "message": "Войти" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новый мастер-пароль не соответствует требованиям политики." }, + "receiveMarketingEmails": { + "message": "Получайте электронные письма от Bitwarden с анонсами, советами и возможностями для исследований." + }, + "unsubscribe": { + "message": "Отписаться" + }, + "atAnyTime": { + "message": "в любое время." + }, + "byContinuingYouAgreeToThe": { + "message": "Продолжая, вы соглашаетесь с" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Отметив этот флажок, вы соглашаетесь со следующим:" }, diff --git a/apps/desktop/src/locales/si/messages.json b/apps/desktop/src/locales/si/messages.json index 14415f055f..cfd67b2b89 100644 --- a/apps/desktop/src/locales/si/messages.json +++ b/apps/desktop/src/locales/si/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/sk/messages.json b/apps/desktop/src/locales/sk/messages.json index cbb2073533..b99cabf981 100644 --- a/apps/desktop/src/locales/sk/messages.json +++ b/apps/desktop/src/locales/sk/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Vytvoriť účet" }, + "setAStrongPassword": { + "message": "Nastavte silné heslo" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Zdajte heslo na vytvorenie účtu" + }, "logIn": { "message": "Prihlásiť sa" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Vaše nové hlavné heslo nespĺňa pravidlá." }, + "receiveMarketingEmails": { + "message": "Dostávať e-maily od Bitwardenu s oznámeniami, radami a možnosťami výskumu." + }, + "unsubscribe": { + "message": "Odhlásiť sa z odberu" + }, + "atAnyTime": { + "message": "môžete kedykoľvek." + }, + "byContinuingYouAgreeToThe": { + "message": "Pokračovaním súhlasíte s" + }, + "and": { + "message": "a" + }, "acceptPolicies": { "message": "Označením tohto políčka súhlasíte s nasledovným:" }, diff --git a/apps/desktop/src/locales/sl/messages.json b/apps/desktop/src/locales/sl/messages.json index 361d484242..f1e4ea8ca7 100644 --- a/apps/desktop/src/locales/sl/messages.json +++ b/apps/desktop/src/locales/sl/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Ustvari račun" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Prijava" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/sr/messages.json b/apps/desktop/src/locales/sr/messages.json index 76a8f63a32..36a59dcdc4 100644 --- a/apps/desktop/src/locales/sr/messages.json +++ b/apps/desktop/src/locales/sr/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Креирај налог" }, + "setAStrongPassword": { + "message": "Поставите јаку лозинку" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завршите креирање налога постављањем лозинке" + }, "logIn": { "message": "Пријавите се" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваша нова главна лозинка не испуњава захтеве полисе." }, + "receiveMarketingEmails": { + "message": "Добијајте е-пошту од Bitwarden-а за најаве, савете и могућности истраживања." + }, + "unsubscribe": { + "message": "Одјави се" + }, + "atAnyTime": { + "message": "било када." + }, + "byContinuingYouAgreeToThe": { + "message": "Ако наставите, слажете се са" + }, + "and": { + "message": "и" + }, "acceptPolicies": { "message": "Означавањем овог поља пристајете на следеће:" }, diff --git a/apps/desktop/src/locales/sv/messages.json b/apps/desktop/src/locales/sv/messages.json index a821e5aedb..c0f52c2da2 100644 --- a/apps/desktop/src/locales/sv/messages.json +++ b/apps/desktop/src/locales/sv/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Skapa konto" }, + "setAStrongPassword": { + "message": "Ställ in ett starkt lösenord" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Logga in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ditt nya huvudlösenord uppfyller inte kraven i policyn." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "och" + }, "acceptPolicies": { "message": "Genom att markera denna ruta godkänner du följande:" }, diff --git a/apps/desktop/src/locales/te/messages.json b/apps/desktop/src/locales/te/messages.json index d9b67aee6f..7124e246f3 100644 --- a/apps/desktop/src/locales/te/messages.json +++ b/apps/desktop/src/locales/te/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Create account" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Log in" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/th/messages.json b/apps/desktop/src/locales/th/messages.json index b8541361af..d8b054107b 100644 --- a/apps/desktop/src/locales/th/messages.json +++ b/apps/desktop/src/locales/th/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "สร้างบัญชี" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "เข้าสู่ระบบ" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/tr/messages.json b/apps/desktop/src/locales/tr/messages.json index 8cd3429613..4adb8b7d7e 100644 --- a/apps/desktop/src/locales/tr/messages.json +++ b/apps/desktop/src/locales/tr/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Hesap oluştur" }, + "setAStrongPassword": { + "message": "Güçlü bir parola belirleyin" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Parolanızı belirleyerek hesabınızı oluşturmayı tamamlayın" + }, "logIn": { "message": "Giriş yap" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Yeni ana parolanız ilke gereksinimlerini karşılamıyor." }, + "receiveMarketingEmails": { + "message": "Bitwarden'dan duyurular, öneriler ve araştırmalarla ilgili e-postalar alın." + }, + "unsubscribe": { + "message": "İstediğiniz zaman" + }, + "atAnyTime": { + "message": "aboneliğinizi iptal edebilirsiniz." + }, + "byContinuingYouAgreeToThe": { + "message": "Devam ederek şunları kabul etmiş olursunuz:" + }, + "and": { + "message": "ve" + }, "acceptPolicies": { "message": "Bu kutuyu işaretleyerek aşağıdakileri kabul etmiş olursunuz:" }, diff --git a/apps/desktop/src/locales/uk/messages.json b/apps/desktop/src/locales/uk/messages.json index caffd391d0..05943d0c83 100644 --- a/apps/desktop/src/locales/uk/messages.json +++ b/apps/desktop/src/locales/uk/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Створити обліковий запис" }, + "setAStrongPassword": { + "message": "Встановіть надійний пароль" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Завершіть створення облікового запису, встановивши пароль" + }, "logIn": { "message": "Увійти" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Ваш новий головний пароль не задовольняє вимоги політики." }, + "receiveMarketingEmails": { + "message": "Отримуйте електронні листи від Bitwarden з оголошеннями, порадами та інформацією про нові можливості." + }, + "unsubscribe": { + "message": "Відписатися" + }, + "atAnyTime": { + "message": "можна будь-коли." + }, + "byContinuingYouAgreeToThe": { + "message": "Продовжуючи, ви погоджуєтеся з" + }, + "and": { + "message": "і" + }, "acceptPolicies": { "message": "Позначивши цей прапорець, ви погоджуєтеся з:" }, diff --git a/apps/desktop/src/locales/vi/messages.json b/apps/desktop/src/locales/vi/messages.json index 3b8fba2a40..8bdf9759d4 100644 --- a/apps/desktop/src/locales/vi/messages.json +++ b/apps/desktop/src/locales/vi/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "Tạo Tài Khoản" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "Đăng Nhập" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "Your new master password does not meet the policy requirements." }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "By checking this box you agree to the following:" }, diff --git a/apps/desktop/src/locales/zh_CN/messages.json b/apps/desktop/src/locales/zh_CN/messages.json index 47ce6b9226..9b4f9f684d 100644 --- a/apps/desktop/src/locales/zh_CN/messages.json +++ b/apps/desktop/src/locales/zh_CN/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "创建账户" }, + "setAStrongPassword": { + "message": "设置强密码" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "设置密码后就能完成账户创建" + }, "logIn": { "message": "登录" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "您的新主密码不符合策略要求。" }, + "receiveMarketingEmails": { + "message": "接收来自 Bitwarden 的电子邮件,以获取公告、建议和调研。" + }, + "unsubscribe": { + "message": "取消订阅" + }, + "atAnyTime": { + "message": "随时" + }, + "byContinuingYouAgreeToThe": { + "message": "若继续,代表您同意" + }, + "and": { + "message": "以及" + }, "acceptPolicies": { "message": "选中此框表示您同意:" }, diff --git a/apps/desktop/src/locales/zh_TW/messages.json b/apps/desktop/src/locales/zh_TW/messages.json index 7c478d835f..e1e4b259b2 100644 --- a/apps/desktop/src/locales/zh_TW/messages.json +++ b/apps/desktop/src/locales/zh_TW/messages.json @@ -499,6 +499,12 @@ "createAccount": { "message": "建立帳戶" }, + "setAStrongPassword": { + "message": "Set a strong password" + }, + "finishCreatingYourAccountBySettingAPassword": { + "message": "Finish creating your account by setting a password" + }, "logIn": { "message": "登入" }, @@ -1659,6 +1665,21 @@ "masterPasswordPolicyRequirementsNotMet": { "message": "新的主密碼不符合原則要求。" }, + "receiveMarketingEmails": { + "message": "Get emails from Bitwarden for announcements, advice, and research opportunities." + }, + "unsubscribe": { + "message": "Unsubscribe" + }, + "atAnyTime": { + "message": "at any time." + }, + "byContinuingYouAgreeToThe": { + "message": "By continuing, you agree to the" + }, + "and": { + "message": "and" + }, "acceptPolicies": { "message": "選中此選取框,即表示您同意下列條款:" }, From 4e19c3ef521f41c63000fd83dbd2cc7faef0f1ad Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Mon, 17 Jun 2024 10:41:22 -0400 Subject: [PATCH 04/31] [PM-7387] Hide Master Password tab for users without MP (#9555) --- .../src/app/auth/settings/security/security.component.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/app/auth/settings/security/security.component.html b/apps/web/src/app/auth/settings/security/security.component.html index 843a1d2312..25459faeac 100644 --- a/apps/web/src/app/auth/settings/security/security.component.html +++ b/apps/web/src/app/auth/settings/security/security.component.html @@ -1,6 +1,8 @@ - {{ "masterPassword" | i18n }} + + {{ "masterPassword" | i18n }} + {{ "twoStepLogin" | i18n }} {{ "keys" | i18n }} From 95554af9e2b184dd27a42602bc238e95876a3974 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Mon, 17 Jun 2024 10:55:18 -0400 Subject: [PATCH 05/31] [PM-8858] include only 1 digit in passphrase (#9632) --- libs/common/src/tools/generator/random.ts | 4 ++-- .../generator/core/src/engine/crypto-service-randomizer.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/common/src/tools/generator/random.ts b/libs/common/src/tools/generator/random.ts index 255a5df7a7..6b72e3cd91 100644 --- a/libs/common/src/tools/generator/random.ts +++ b/libs/common/src/tools/generator/random.ts @@ -20,8 +20,8 @@ export class CryptoServiceRandomizer implements Randomizer { } if (options?.number ?? false) { - const num = await this.crypto.randomNumber(1, 9999); - word = word + this.zeroPad(num.toString(), 4); + const num = await this.crypto.randomNumber(1, 9); + word = word + num.toString(); } return word; diff --git a/libs/tools/generator/core/src/engine/crypto-service-randomizer.ts b/libs/tools/generator/core/src/engine/crypto-service-randomizer.ts index 8cc8854cbc..a15440836d 100644 --- a/libs/tools/generator/core/src/engine/crypto-service-randomizer.ts +++ b/libs/tools/generator/core/src/engine/crypto-service-randomizer.ts @@ -20,8 +20,8 @@ export class CryptoServiceRandomizer implements Randomizer { } if (options?.number ?? false) { - const num = await this.crypto.randomNumber(1, 9999); - word = word + this.zeroPad(num.toString(), 4); + const num = await this.crypto.randomNumber(1, 9); + word = word + num.toString(); } return word; From c26669cf6046748c43bd458ec27062fb825cd42c Mon Sep 17 00:00:00 2001 From: Tom <144813356+ttalty@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:00:19 -0400 Subject: [PATCH 06/31] Moving the config command and adding the error for server config when logged in (#9347) --- .../{ => platform}/commands/config.command.ts | 18 ++++++++++++++---- apps/cli/src/program.ts | 7 +++++-- 2 files changed, 19 insertions(+), 6 deletions(-) rename apps/cli/src/{ => platform}/commands/config.command.ts (70%) diff --git a/apps/cli/src/commands/config.command.ts b/apps/cli/src/platform/commands/config.command.ts similarity index 70% rename from apps/cli/src/commands/config.command.ts rename to apps/cli/src/platform/commands/config.command.ts index eb6559443d..cd94e8af9c 100644 --- a/apps/cli/src/commands/config.command.ts +++ b/apps/cli/src/platform/commands/config.command.ts @@ -1,17 +1,21 @@ import { OptionValues } from "commander"; import { firstValueFrom } from "rxjs"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { EnvironmentService, Region, } from "@bitwarden/common/platform/abstractions/environment.service"; -import { Response } from "../models/response"; -import { MessageResponse } from "../models/response/message.response"; -import { StringResponse } from "../models/response/string.response"; +import { Response } from "../../models/response"; +import { MessageResponse } from "../../models/response/message.response"; +import { StringResponse } from "../../models/response/string.response"; export class ConfigCommand { - constructor(private environmentService: EnvironmentService) {} + constructor( + private environmentService: EnvironmentService, + private accountService: AccountService, + ) {} async run(setting: string, value: string, options: OptionValues): Promise { setting = setting.toLowerCase(); @@ -40,6 +44,12 @@ export class ConfigCommand { return Response.success(stringRes); } + // The server config cannot be updated while a user is actively logged in to the current server + const activeAccount = await firstValueFrom(this.accountService.activeAccount$); + if (activeAccount) { + return Response.error("Logout required before server config update."); + } + url = url === "null" || url === "bitwarden.com" || url === "https://bitwarden.com" ? null : url; await this.environmentService.setEnvironment(Region.SelfHosted, { base: url, diff --git a/apps/cli/src/program.ts b/apps/cli/src/program.ts index 37c838b664..51c4b39e98 100644 --- a/apps/cli/src/program.ts +++ b/apps/cli/src/program.ts @@ -10,12 +10,12 @@ import { LogoutCommand } from "./auth/commands/logout.command"; import { UnlockCommand } from "./auth/commands/unlock.command"; import { BaseProgram } from "./base-program"; import { CompletionCommand } from "./commands/completion.command"; -import { ConfigCommand } from "./commands/config.command"; import { EncodeCommand } from "./commands/encode.command"; import { StatusCommand } from "./commands/status.command"; import { UpdateCommand } from "./commands/update.command"; import { Response } from "./models/response"; import { MessageResponse } from "./models/response/message.response"; +import { ConfigCommand } from "./platform/commands/config.command"; import { GenerateCommand } from "./tools/generate.command"; import { CliUtils } from "./utils"; import { SyncCommand } from "./vault/sync.command"; @@ -403,7 +403,10 @@ export class Program extends BaseProgram { writeLn("", true); }) .action(async (setting, value, options) => { - const command = new ConfigCommand(this.serviceContainer.environmentService); + const command = new ConfigCommand( + this.serviceContainer.environmentService, + this.serviceContainer.accountService, + ); const response = await command.run(setting, value, options); this.processResponse(response); }); From ce88038c0d1546023846470bf26ddd89da602004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Mon, 17 Jun 2024 11:10:00 -0400 Subject: [PATCH 07/31] improve developer experience of generator extension symbols (#9690) --- libs/tools/generator/extensions/src/index.ts | 5 +++++ .../{factory.ts => create-generation-service.ts} | 0 .../{factory.ts => create-generation-service.ts} | 0 3 files changed, 5 insertions(+) rename libs/tools/generator/extensions/src/legacy-password/{factory.ts => create-generation-service.ts} (100%) rename libs/tools/generator/extensions/src/legacy-username/{factory.ts => create-generation-service.ts} (100%) diff --git a/libs/tools/generator/extensions/src/index.ts b/libs/tools/generator/extensions/src/index.ts index d266519192..53f7232644 100644 --- a/libs/tools/generator/extensions/src/index.ts +++ b/libs/tools/generator/extensions/src/index.ts @@ -2,3 +2,8 @@ export * as history from "./history"; export * as legacyPassword from "./legacy-password"; export * as legacyUsername from "./legacy-username"; export * as navigation from "./navigation"; + +export { GeneratorHistoryService } from "./history"; +export { GeneratorNavigationService } from "./navigation"; +export { PasswordGenerationServiceAbstraction } from "./legacy-password"; +export { UsernameGenerationServiceAbstraction } from "./legacy-username"; diff --git a/libs/tools/generator/extensions/src/legacy-password/factory.ts b/libs/tools/generator/extensions/src/legacy-password/create-generation-service.ts similarity index 100% rename from libs/tools/generator/extensions/src/legacy-password/factory.ts rename to libs/tools/generator/extensions/src/legacy-password/create-generation-service.ts diff --git a/libs/tools/generator/extensions/src/legacy-username/factory.ts b/libs/tools/generator/extensions/src/legacy-username/create-generation-service.ts similarity index 100% rename from libs/tools/generator/extensions/src/legacy-username/factory.ts rename to libs/tools/generator/extensions/src/legacy-username/create-generation-service.ts From 92f71e4f830ff410b9cc063eb63e16aa7bf617c8 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:28:35 -0400 Subject: [PATCH 08/31] [PM-8865] Reset "should trust device" state to null (#9639) --- .../src/auth/services/device-trust.service.implementation.ts | 2 +- libs/common/src/auth/services/device-trust.service.spec.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/common/src/auth/services/device-trust.service.implementation.ts b/libs/common/src/auth/services/device-trust.service.implementation.ts index 242a748095..51461e653b 100644 --- a/libs/common/src/auth/services/device-trust.service.implementation.ts +++ b/libs/common/src/auth/services/device-trust.service.implementation.ts @@ -102,7 +102,7 @@ export class DeviceTrustService implements DeviceTrustServiceAbstraction { if (shouldTrustDevice) { await this.trustDevice(userId); // reset the trust choice - await this.setShouldTrustDevice(userId, false); + await this.setShouldTrustDevice(userId, null); } } diff --git a/libs/common/src/auth/services/device-trust.service.spec.ts b/libs/common/src/auth/services/device-trust.service.spec.ts index 1527870cb4..7cc4de8b2d 100644 --- a/libs/common/src/auth/services/device-trust.service.spec.ts +++ b/libs/common/src/auth/services/device-trust.service.spec.ts @@ -115,7 +115,7 @@ describe("deviceTrustService", () => { expect(deviceTrustService.getShouldTrustDevice).toHaveBeenCalledTimes(1); expect(deviceTrustService.trustDevice).toHaveBeenCalledTimes(1); - expect(deviceTrustService.setShouldTrustDevice).toHaveBeenCalledWith(mockUserId, false); + expect(deviceTrustService.setShouldTrustDevice).toHaveBeenCalledWith(mockUserId, null); }); it("should not trust device nor reset when getShouldTrustDevice returns false", async () => { From 6f91ecf41bc06287b3ba12d003d99702a7988e4a Mon Sep 17 00:00:00 2001 From: cyprain-okeke <108260115+cyprain-okeke@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:31:24 +0100 Subject: [PATCH 09/31] Fix the reb color issue (#9696) --- .../providers/subscription/subscription-status.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/billing/providers/subscription/subscription-status.component.html b/bitwarden_license/bit-web/src/app/billing/providers/subscription/subscription-status.component.html index 0c80d3ef69..1d9420cb85 100644 --- a/bitwarden_license/bit-web/src/app/billing/providers/subscription/subscription-status.component.html +++ b/bitwarden_license/bit-web/src/app/billing/providers/subscription/subscription-status.component.html @@ -21,10 +21,10 @@ {{ displayedStatus }} -
+
{{ data.date.label | titlecase }}
-
+
{{ data.date.value | date: "mediumDate" }}
From fe1c432e034ee8c495d99e7c9372163589502d56 Mon Sep 17 00:00:00 2001 From: Todd Martin <106564991+trmartin4@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:37:05 -0400 Subject: [PATCH 10/31] Auth/pm 8882/Add TDE Logging (#9673) * Added logging behind feature flag. * Added default for new flag. * Additional logging changes. * Consolidated log messages. * Removed unneccessary log. * Fixed test error. * Fixed linting. * Fixed constructor on test. * Updated to remove flag * Moved service. * Added logging to redirect guard. --- .../angular/src/auth/guards/redirect.guard.ts | 8 +++++ .../guards/tde-decryption-required.guard.ts | 16 ++++++++++ .../login-strategies/sso-login.strategy.ts | 30 +++++++++++++++++-- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/libs/angular/src/auth/guards/redirect.guard.ts b/libs/angular/src/auth/guards/redirect.guard.ts index 0c43673c34..760558dfb5 100644 --- a/libs/angular/src/auth/guards/redirect.guard.ts +++ b/libs/angular/src/auth/guards/redirect.guard.ts @@ -6,6 +6,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; export interface RedirectRoutes { loggedIn: string; @@ -32,6 +33,7 @@ export function redirectGuard(overrides: Partial = {}): CanActiv const authService = inject(AuthService); const cryptoService = inject(CryptoService); const deviceTrustService = inject(DeviceTrustServiceAbstraction); + const logService = inject(LogService); const router = inject(Router); const authStatus = await authService.getAuthStatus(); @@ -49,6 +51,12 @@ export function redirectGuard(overrides: Partial = {}): CanActiv const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$); const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$); if (authStatus === AuthenticationStatus.Locked && tdeEnabled && !everHadUserKey) { + logService.info( + "Sending user to TDE decryption options. AuthStatus is %s. TDE support is %s. Ever had user key is %s.", + AuthenticationStatus[authStatus], + tdeEnabled, + everHadUserKey, + ); return router.createUrlTree([routes.notDecrypted], { queryParams: route.queryParams }); } diff --git a/libs/angular/src/auth/guards/tde-decryption-required.guard.ts b/libs/angular/src/auth/guards/tde-decryption-required.guard.ts index 524ce7dce5..51d1a5a3b5 100644 --- a/libs/angular/src/auth/guards/tde-decryption-required.guard.ts +++ b/libs/angular/src/auth/guards/tde-decryption-required.guard.ts @@ -11,6 +11,7 @@ import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; /** * Only allow access to this route if the vault is locked and has never been decrypted. @@ -23,15 +24,30 @@ export function tdeDecryptionRequiredGuard(): CanActivateFn { const authService = inject(AuthService); const cryptoService = inject(CryptoService); const deviceTrustService = inject(DeviceTrustServiceAbstraction); + const logService = inject(LogService); const router = inject(Router); const authStatus = await authService.getAuthStatus(); const tdeEnabled = await firstValueFrom(deviceTrustService.supportsDeviceTrust$); const everHadUserKey = await firstValueFrom(cryptoService.everHadUserKey$); + + // We need to determine if we should bypass the decryption options and send the user to the vault. + // The ONLY time that we want to send a user to the decryption options is when: + // 1. The user's auth status is Locked, AND + // 2. TDE is enabled, AND + // 3. The user has never had a user key in state since last logout. + // The inverse of this is when we should send the user to the vault. if (authStatus !== AuthenticationStatus.Locked || !tdeEnabled || everHadUserKey) { return router.createUrlTree(["/"]); } + logService.info( + "Sending user to TDE decryption options. AuthStatus is %s. TDE support is %s. Ever had user key is %s.", + AuthenticationStatus[authStatus], + tdeEnabled, + everHadUserKey, + ); + return true; }; } diff --git a/libs/auth/src/common/login-strategies/sso-login.strategy.ts b/libs/auth/src/common/login-strategies/sso-login.strategy.ts index b7ed8906e7..2ba0f682b5 100644 --- a/libs/auth/src/common/login-strategies/sso-login.strategy.ts +++ b/libs/auth/src/common/login-strategies/sso-login.strategy.ts @@ -87,12 +87,16 @@ export class SsoLoginStrategy extends LoginStrategy { data.userEnteredEmail = credentials.email; + const deviceRequest = await this.buildDeviceRequest(); + + this.logService.info("Logging in with appId %s.", deviceRequest.identifier); + data.tokenRequest = new SsoTokenRequest( credentials.code, credentials.codeVerifier, credentials.redirectUrl, await this.buildTwoFactor(credentials.twoFactor, credentials.email), - await this.buildDeviceRequest(), + deviceRequest, ); this.cache.next(data); @@ -195,12 +199,18 @@ export class SsoLoginStrategy extends LoginStrategy { // Note: TDE and key connector are mutually exclusive if (userDecryptionOptions?.trustedDeviceOption) { + this.logService.info("Attempting to set user key with approved admin auth request."); + + // Try to use the user key from an approved admin request if it exists. + // Using it will clear it from state and future requests will use the device key. await this.trySetUserKeyWithApprovedAdminRequestIfExists(userId); const hasUserKey = await this.cryptoService.hasUserKey(userId); - // Only try to set user key with device key if admin approval request was not successful + // Only try to set user key with device key if admin approval request was not successful. if (!hasUserKey) { + this.logService.info("Attempting to set user key with device key."); + await this.trySetUserKeyWithDeviceKey(tokenResponse, userId); } } else if ( @@ -275,11 +285,27 @@ export class SsoLoginStrategy extends LoginStrategy { ): Promise { const trustedDeviceOption = tokenResponse.userDecryptionOptions?.trustedDeviceOption; + if (!trustedDeviceOption) { + this.logService.error("Unable to set user key due to missing trustedDeviceOption."); + return; + } + const deviceKey = await this.deviceTrustService.getDeviceKey(userId); const encDevicePrivateKey = trustedDeviceOption?.encryptedPrivateKey; const encUserKey = trustedDeviceOption?.encryptedUserKey; if (!deviceKey || !encDevicePrivateKey || !encUserKey) { + if (!deviceKey) { + await this.logService.warning("Unable to set user key due to missing device key."); + } + if (!encDevicePrivateKey) { + await this.logService.warning( + "Unable to set user key due to missing encrypted device private key.", + ); + } + if (!encUserKey) { + await this.logService.warning("Unable to set user key due to missing encrypted user key."); + } return; } From 29d433a8a3d0310a8238ffeea9fbaad199a44005 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=9C=A8=20Audrey=20=E2=9C=A8?= Date: Mon, 17 Jun 2024 12:56:21 -0400 Subject: [PATCH 11/31] [PM-8959] fix barrel file imports (#9698) --- libs/tools/generator/extensions/src/legacy-password/index.ts | 2 +- libs/tools/generator/extensions/src/legacy-username/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/tools/generator/extensions/src/legacy-password/index.ts b/libs/tools/generator/extensions/src/legacy-password/index.ts index 61fbc73456..55f5989e48 100644 --- a/libs/tools/generator/extensions/src/legacy-password/index.ts +++ b/libs/tools/generator/extensions/src/legacy-password/index.ts @@ -1,3 +1,3 @@ export * from "./password-generation.service.abstraction"; -export * from "./factory"; +export * from "./create-generation-service"; export * from "./password-generator-options"; diff --git a/libs/tools/generator/extensions/src/legacy-username/index.ts b/libs/tools/generator/extensions/src/legacy-username/index.ts index 462b49d7cd..eac796d643 100644 --- a/libs/tools/generator/extensions/src/legacy-username/index.ts +++ b/libs/tools/generator/extensions/src/legacy-username/index.ts @@ -1,3 +1,3 @@ export * from "./username-generation.service.abstraction"; -export * from "./factory"; +export * from "./create-generation-service"; export * from "./username-generation-options"; From 3bfdc50d5d2e9b48feefa5d84ea73f530c14eee5 Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:01:01 -0400 Subject: [PATCH 12/31] Bumped client version(s) (#9700) --- apps/web/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index b56a3e03d0..82c447c9b4 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2024.6.1", + "version": "2024.6.2", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index fe43d36aaf..28ceeeb83e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2024.6.1" + "version": "2024.6.2" }, "libs/admin-console": { "name": "@bitwarden/admin-console", From 06410a06332d07e75be9d97c0258dea0c7b2c0da Mon Sep 17 00:00:00 2001 From: Will Martin Date: Mon, 17 Jun 2024 14:10:50 -0400 Subject: [PATCH 13/31] [CL-118][CL-164][PM-8019] collapsible side navigation (#6383) --- apps/browser/src/_locales/en/messages.json | 3 + apps/desktop/src/locales/en/messages.json | 3 + .../organization-layout.component.html | 21 +-- .../navigation-switcher.component.html | 2 +- .../navigation-switcher.component.spec.ts | 14 ++ .../app/layouts/user-layout.component.html | 14 +- apps/web/src/locales/en/messages.json | 3 + .../providers/providers-layout.component.html | 14 +- .../layout/layout.component.html | 2 +- .../layout/navigation.component.html | 24 ++- .../src/layout/layout.component.html | 32 ++-- .../components/src/layout/layout.component.ts | 10 +- libs/components/src/layout/layout.stories.ts | 174 ++++++++++++++--- libs/components/src/navigation/index.ts | 1 + .../src/navigation/nav-divider.component.html | 2 +- .../src/navigation/nav-divider.component.ts | 6 +- .../src/navigation/nav-group.component.html | 21 ++- .../src/navigation/nav-group.component.ts | 22 ++- .../src/navigation/nav-group.stories.ts | 16 +- .../src/navigation/nav-item.component.html | 175 +++++++++++------- .../src/navigation/nav-item.component.ts | 6 +- .../src/navigation/nav-item.stories.ts | 32 +++- .../src/navigation/nav-logo.component.html | 20 ++ .../src/navigation/nav-logo.component.ts | 27 +++ .../src/navigation/navigation.module.ts | 32 +++- .../src/navigation/side-nav.component.html | 42 +++++ .../src/navigation/side-nav.component.ts | 26 +++ .../src/navigation/side-nav.service.ts | 43 +++++ .../kitchen-sink/kitchen-sink.stories.ts | 4 +- .../utils/position-fixed-wrapper-decorator.ts | 17 ++ 30 files changed, 624 insertions(+), 184 deletions(-) create mode 100644 libs/components/src/navigation/nav-logo.component.html create mode 100644 libs/components/src/navigation/nav-logo.component.ts create mode 100644 libs/components/src/navigation/side-nav.component.html create mode 100644 libs/components/src/navigation/side-nav.component.ts create mode 100644 libs/components/src/navigation/side-nav.service.ts create mode 100644 libs/components/src/utils/position-fixed-wrapper-decorator.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index eb2815696e..79ea4d4856 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2876,6 +2876,9 @@ "message": "Turn off master password re-prompt to edit this field", "description": "Message appearing below the autofill on load message when master password reprompt is set for a vault item." }, + "toggleSideNavigation": { + "message": "Toggle side navigation" + }, "skipToContent": { "message": "Skip to content" }, diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 0c5f7244f0..73e1bc56e6 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2692,6 +2692,9 @@ "submenu": { "message": "Submenu" }, + "toggleSideNavigation": { + "message": "Toggle side navigation" + }, "skipToContent": { "message": "Skip to content" }, diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index 445a0855c1..563905548d 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -1,12 +1,6 @@ - - + + + + +
{{ "moreFromBitwarden" | i18n }} ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + describe("NavigationProductSwitcherComponent", () => { let fixture: ComponentFixture; let productSwitcherService: MockProxy; diff --git a/apps/web/src/app/layouts/user-layout.component.html b/apps/web/src/app/layouts/user-layout.component.html index a1c1273674..0d2be927ec 100644 --- a/apps/web/src/app/layouts/user-layout.component.html +++ b/apps/web/src/app/layouts/user-layout.component.html @@ -1,8 +1,6 @@ - diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 1d0e882b17..c248b04dc0 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -7655,6 +7655,9 @@ "alreadyHaveAccount": { "message": "Already have an account?" }, + "toggleSideNavigation": { + "message": "Toggle side navigation" + }, "skipToContent": { "message": "Skip to content" }, diff --git a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html index 7ee6a067d4..7d1d195bf9 100644 --- a/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html +++ b/bitwarden_license/bit-web/src/app/admin-console/providers/providers-layout.component.html @@ -1,8 +1,6 @@ - diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/layout.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/layout/layout.component.html index 462c15311a..ad63d94839 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/layout.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/layout.component.html @@ -1,4 +1,4 @@ - + diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html index ad608ff458..2c7661d13b 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html +++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html @@ -1,8 +1,5 @@ - + + + + + diff --git a/libs/components/src/layout/layout.component.html b/libs/components/src/layout/layout.component.html index b5af1a1984..2daefce556 100644 --- a/libs/components/src/layout/layout.component.html +++ b/libs/components/src/layout/layout.component.html @@ -13,24 +13,28 @@ > -
- +
+
+ + +
+
+
diff --git a/libs/components/src/layout/layout.component.ts b/libs/components/src/layout/layout.component.ts index 9fe3b46ef3..d55ad8493e 100644 --- a/libs/components/src/layout/layout.component.ts +++ b/libs/components/src/layout/layout.component.ts @@ -1,21 +1,21 @@ -import { Component, Input } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; import { RouterModule } from "@angular/router"; import { LinkModule } from "../link"; +import { SideNavService } from "../navigation/side-nav.service"; import { SharedModule } from "../shared"; -export type LayoutVariant = "primary" | "secondary"; - @Component({ selector: "bit-layout", templateUrl: "layout.component.html", standalone: true, - imports: [SharedModule, LinkModule, RouterModule], + imports: [CommonModule, SharedModule, LinkModule, RouterModule], }) export class LayoutComponent { protected mainContentId = "main-content"; - @Input() variant: LayoutVariant = "primary"; + constructor(protected sideNavService: SideNavService) {} focusMainContent() { document.getElementById(this.mainContentId)?.focus(); diff --git a/libs/components/src/layout/layout.stories.ts b/libs/components/src/layout/layout.stories.ts index e85d04af4d..0016cc4183 100644 --- a/libs/components/src/layout/layout.stories.ts +++ b/libs/components/src/layout/layout.stories.ts @@ -1,5 +1,5 @@ import { RouterTestingModule } from "@angular/router/testing"; -import { Meta, StoryObj, componentWrapperDecorator, moduleMetadata } from "@storybook/angular"; +import { Meta, StoryObj, moduleMetadata } from "@storybook/angular"; import { userEvent } from "@storybook/testing-library"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic import { CalloutModule } from "../callout"; import { NavigationModule } from "../navigation"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { positionFixedWrapperDecorator } from "../utils/position-fixed-wrapper-decorator"; import { LayoutComponent } from "./layout.component"; @@ -14,16 +15,7 @@ export default { title: "Component Library/Layout", component: LayoutComponent, decorators: [ - componentWrapperDecorator( - /** - * Applying a CSS transform makes a `position: fixed` element act like it is `position: relative` - * https://github.com/storybookjs/storybook/issues/8011#issue-490251969 - */ - (story) => - /* HTML */ `
- ${story} -
`, - ), + positionFixedWrapperDecorator(), moduleMetadata({ imports: [NavigationModule, RouterTestingModule, CalloutModule], providers: [ @@ -31,6 +23,7 @@ export default { provide: I18nService, useFactory: () => { return new I18nMockService({ + toggleSideNavigation: "Toggle side navigation", skipToContent: "Skip to content", submenu: "submenu", toggleCollapse: "toggle collapse", @@ -40,6 +33,9 @@ export default { ], }), ], + parameters: { + chromatic: { viewports: [640, 1280] }, + }, } as Meta; type Story = StoryObj; @@ -47,7 +43,9 @@ type Story = StoryObj; export const Empty: Story = { render: (args) => ({ props: args, - template: /* HTML */ ``, + template: /* HTML */ ` + + `, }), }; @@ -56,13 +54,9 @@ export const WithContent: Story = { props: args, template: /* HTML */ ` - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hello world! `, @@ -147,8 +275,8 @@ export const Secondary: Story = { render: (args) => ({ props: args, template: /* HTML */ ` - - + Hello world! `, diff --git a/libs/components/src/navigation/index.ts b/libs/components/src/navigation/index.ts index 240b832ec7..8f182b1104 100644 --- a/libs/components/src/navigation/index.ts +++ b/libs/components/src/navigation/index.ts @@ -1 +1,2 @@ export * from "./navigation.module"; +export * from "./side-nav.service"; diff --git a/libs/components/src/navigation/nav-divider.component.html b/libs/components/src/navigation/nav-divider.component.html index 4f77a18a37..224f6ae065 100644 --- a/libs/components/src/navigation/nav-divider.component.html +++ b/libs/components/src/navigation/nav-divider.component.html @@ -1 +1 @@ -
+
diff --git a/libs/components/src/navigation/nav-divider.component.ts b/libs/components/src/navigation/nav-divider.component.ts index e0c5cf98b7..008d3f46c3 100644 --- a/libs/components/src/navigation/nav-divider.component.ts +++ b/libs/components/src/navigation/nav-divider.component.ts @@ -1,7 +1,11 @@ import { Component } from "@angular/core"; +import { SideNavService } from "./side-nav.service"; + @Component({ selector: "bit-nav-divider", templateUrl: "./nav-divider.component.html", }) -export class NavDividerComponent {} +export class NavDividerComponent { + constructor(protected sideNavService: SideNavService) {} +} diff --git a/libs/components/src/navigation/nav-group.component.html b/libs/components/src/navigation/nav-group.component.html index c3863a398e..c22a067ffe 100644 --- a/libs/components/src/navigation/nav-group.component.html +++ b/libs/components/src/navigation/nav-group.component.html @@ -6,9 +6,8 @@ [relativeTo]="relativeTo" [routerLinkActiveOptions]="routerLinkActiveOptions" [variant]="variant" - (mainContentClicked)="toggle()" [treeDepth]="treeDepth" - (mainContentClicked)="mainContentClicked.emit()" + (mainContentClicked)="handleMainContentClicked()" [ariaLabel]="ariaLabel" [hideActiveStyles]="parentHideActiveStyles" > @@ -43,11 +42,13 @@ -
- -
+ +
+ +
+
diff --git a/libs/components/src/navigation/nav-group.component.ts b/libs/components/src/navigation/nav-group.component.ts index 757e0e98db..1ebe733864 100644 --- a/libs/components/src/navigation/nav-group.component.ts +++ b/libs/components/src/navigation/nav-group.component.ts @@ -11,6 +11,7 @@ import { } from "@angular/core"; import { NavBaseComponent } from "./nav-base.component"; +import { SideNavService } from "./side-nav.service"; @Component({ selector: "bit-nav-group", @@ -23,9 +24,9 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI }) nestedNavComponents!: QueryList; - /** The parent nav item should not show active styles when open. */ + /** When the side nav is open, the parent nav item should not show active styles when open. */ protected get parentHideActiveStyles(): boolean { - return this.hideActiveStyles || this.open; + return this.hideActiveStyles || (this.open && this.sideNavService.open); } /** @@ -42,7 +43,10 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI @Output() openChange = new EventEmitter(); - constructor(@Optional() @SkipSelf() private parentNavGroup: NavGroupComponent) { + constructor( + protected sideNavService: SideNavService, + @Optional() @SkipSelf() private parentNavGroup: NavGroupComponent, + ) { super(); } @@ -69,6 +73,18 @@ export class NavGroupComponent extends NavBaseComponent implements AfterContentI }); } + protected handleMainContentClicked() { + if (!this.sideNavService.open) { + if (!this.route) { + this.sideNavService.setOpen(); + } + this.open = true; + } else { + this.toggle(); + } + this.mainContentClicked.emit(); + } + ngAfterContentInit(): void { this.initNestedStyles(); } diff --git a/libs/components/src/navigation/nav-group.stories.ts b/libs/components/src/navigation/nav-group.stories.ts index 15bee43d55..47a600727f 100644 --- a/libs/components/src/navigation/nav-group.stories.ts +++ b/libs/components/src/navigation/nav-group.stories.ts @@ -4,8 +4,10 @@ import { StoryObj, Meta, moduleMetadata, applicationConfig } from "@storybook/an import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { LayoutComponent } from "../layout"; import { SharedModule } from "../shared/shared.module"; import { I18nMockService } from "../utils/i18n-mock.service"; +import { positionFixedWrapperDecorator } from "../utils/position-fixed-wrapper-decorator"; import { NavGroupComponent } from "./nav-group.component"; import { NavigationModule } from "./navigation.module"; @@ -20,8 +22,17 @@ export default { title: "Component Library/Nav/Nav Group", component: NavGroupComponent, decorators: [ + positionFixedWrapperDecorator( + (story) => `${story}`, + ), moduleMetadata({ - imports: [SharedModule, RouterModule, NavigationModule, DummyContentComponent], + imports: [ + SharedModule, + RouterModule, + NavigationModule, + DummyContentComponent, + LayoutComponent, + ], providers: [ { provide: I18nService, @@ -29,6 +40,8 @@ export default { return new I18nMockService({ submenu: "submenu", toggleCollapse: "toggle collapse", + toggleSideNavigation: "Toggle side navigation", + skipToContent: "Skip to content", }); }, }, @@ -53,6 +66,7 @@ export default { type: "figma", url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=4687%3A86642", }, + chromatic: { viewports: [640, 1280] }, }, } as Meta; diff --git a/libs/components/src/navigation/nav-item.component.html b/libs/components/src/navigation/nav-item.component.html index 7655043165..6b594b3d49 100644 --- a/libs/components/src/navigation/nav-item.component.html +++ b/libs/components/src/navigation/nav-item.component.html @@ -1,84 +1,115 @@ -
- -
- -
- -
+
+
+ +
+ +
+ +
+
- + - - - {{ - text - }} - + + +
+ {{ text }} +
+
- - - - - + + + + + + + + + + + + + + +
- - - - - - - - - - -
- + +
-
+ diff --git a/libs/components/src/navigation/nav-item.component.ts b/libs/components/src/navigation/nav-item.component.ts index 4132e0b327..8348638568 100644 --- a/libs/components/src/navigation/nav-item.component.ts +++ b/libs/components/src/navigation/nav-item.component.ts @@ -3,6 +3,7 @@ import { BehaviorSubject, map } from "rxjs"; import { NavBaseComponent } from "./nav-base.component"; import { NavGroupComponent } from "./nav-group.component"; +import { SideNavService } from "./side-nav.service"; @Component({ selector: "bit-nav-item", @@ -49,7 +50,10 @@ export class NavItemComponent extends NavBaseComponent { this.focusVisibleWithin$.next(false); } - constructor(@Optional() private parentNavGroup: NavGroupComponent) { + constructor( + protected sideNavService: SideNavService, + @Optional() private parentNavGroup: NavGroupComponent, + ) { super(); } } diff --git a/libs/components/src/navigation/nav-item.stories.ts b/libs/components/src/navigation/nav-item.stories.ts index 98ff68ee35..918fe0c3d3 100644 --- a/libs/components/src/navigation/nav-item.stories.ts +++ b/libs/components/src/navigation/nav-item.stories.ts @@ -1,7 +1,12 @@ import { RouterTestingModule } from "@angular/router/testing"; import { StoryObj, Meta, moduleMetadata } from "@storybook/angular"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; + import { IconButtonModule } from "../icon-button"; +import { LayoutComponent } from "../layout"; +import { I18nMockService } from "../utils/i18n-mock.service"; +import { positionFixedWrapperDecorator } from "../utils/position-fixed-wrapper-decorator"; import { NavItemComponent } from "./nav-item.component"; import { NavigationModule } from "./navigation.module"; @@ -10,9 +15,25 @@ export default { title: "Component Library/Nav/Nav Item", component: NavItemComponent, decorators: [ + positionFixedWrapperDecorator( + (story) => `${story}`, + ), moduleMetadata({ declarations: [], - imports: [RouterTestingModule, IconButtonModule, NavigationModule], + imports: [RouterTestingModule, IconButtonModule, NavigationModule, LayoutComponent], + providers: [ + { + provide: I18nService, + useFactory: () => { + return new I18nMockService({ + submenu: "submenu", + toggleCollapse: "toggle collapse", + toggleSideNavigation: "Toggle side navigation", + skipToContent: "Skip to content", + }); + }, + }, + ], }), ], parameters: { @@ -20,6 +41,7 @@ export default { type: "figma", url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=4687%3A86642", }, + chromatic: { viewports: [640, 1280] }, }, } as Meta; @@ -60,14 +82,6 @@ export const WithChildButtons: Story = { props: args, template: ` -
+ diff --git a/libs/components/src/navigation/nav-logo.component.ts b/libs/components/src/navigation/nav-logo.component.ts new file mode 100644 index 0000000000..71fdcfa440 --- /dev/null +++ b/libs/components/src/navigation/nav-logo.component.ts @@ -0,0 +1,27 @@ +import { Component, Input } from "@angular/core"; + +import { Icon } from "../icon"; + +import { SideNavService } from "./side-nav.service"; + +@Component({ + selector: "bit-nav-logo", + templateUrl: "./nav-logo.component.html", +}) +export class NavLogoComponent { + /** Icon that is displayed when the side nav is closed */ + @Input() closedIcon = "bwi-shield"; + + /** Icon that is displayed when the side nav is open */ + @Input({ required: true }) openIcon: Icon; + + /** + * Route to be passed to internal `routerLink` + */ + @Input({ required: true }) route: string | any[]; + + /** Passed to `attr.aria-label` and `attr.title` */ + @Input({ required: true }) label: string; + + constructor(protected sideNavService: SideNavService) {} +} diff --git a/libs/components/src/navigation/navigation.module.ts b/libs/components/src/navigation/navigation.module.ts index 3685c1b935..852bd1c0a2 100644 --- a/libs/components/src/navigation/navigation.module.ts +++ b/libs/components/src/navigation/navigation.module.ts @@ -1,18 +1,44 @@ +import { A11yModule } from "@angular/cdk/a11y"; import { OverlayModule } from "@angular/cdk/overlay"; import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { RouterModule } from "@angular/router"; +import { IconModule } from "../icon"; import { IconButtonModule } from "../icon-button/icon-button.module"; +import { LinkModule } from "../link"; import { SharedModule } from "../shared/shared.module"; import { NavDividerComponent } from "./nav-divider.component"; import { NavGroupComponent } from "./nav-group.component"; import { NavItemComponent } from "./nav-item.component"; +import { NavLogoComponent } from "./nav-logo.component"; +import { SideNavComponent } from "./side-nav.component"; @NgModule({ - imports: [CommonModule, SharedModule, IconButtonModule, OverlayModule, RouterModule], - declarations: [NavDividerComponent, NavGroupComponent, NavItemComponent], - exports: [NavDividerComponent, NavGroupComponent, NavItemComponent], + imports: [ + CommonModule, + SharedModule, + IconButtonModule, + OverlayModule, + RouterModule, + IconModule, + A11yModule, + LinkModule, + ], + declarations: [ + NavDividerComponent, + NavGroupComponent, + NavItemComponent, + NavLogoComponent, + SideNavComponent, + ], + exports: [ + NavDividerComponent, + NavGroupComponent, + NavItemComponent, + NavLogoComponent, + SideNavComponent, + ], }) export class NavigationModule {} diff --git a/libs/components/src/navigation/side-nav.component.html b/libs/components/src/navigation/side-nav.component.html new file mode 100644 index 0000000000..326bd9e6da --- /dev/null +++ b/libs/components/src/navigation/side-nav.component.html @@ -0,0 +1,42 @@ + diff --git a/libs/components/src/navigation/side-nav.component.ts b/libs/components/src/navigation/side-nav.component.ts new file mode 100644 index 0000000000..0561e2e603 --- /dev/null +++ b/libs/components/src/navigation/side-nav.component.ts @@ -0,0 +1,26 @@ +import { Component, ElementRef, Input, ViewChild } from "@angular/core"; + +import { SideNavService } from "./side-nav.service"; + +@Component({ + selector: "bit-side-nav", + templateUrl: "side-nav.component.html", +}) +export class SideNavComponent { + @Input() variant: "primary" | "secondary" = "primary"; + + @ViewChild("toggleButton", { read: ElementRef, static: true }) + private toggleButton: ElementRef; + + constructor(protected sideNavService: SideNavService) {} + + protected handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + this.sideNavService.setClose(); + this.toggleButton?.nativeElement.focus(); + return false; + } + + return true; + }; +} diff --git a/libs/components/src/navigation/side-nav.service.ts b/libs/components/src/navigation/side-nav.service.ts new file mode 100644 index 0000000000..87691244ca --- /dev/null +++ b/libs/components/src/navigation/side-nav.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from "@angular/core"; +import { BehaviorSubject, Observable, combineLatest, fromEvent, map, startWith } from "rxjs"; + +@Injectable({ + providedIn: "root", +}) +export class SideNavService { + private _open$ = new BehaviorSubject(!window.matchMedia("(max-width: 768px)").matches); + open$ = this._open$.asObservable(); + + isOverlay$ = combineLatest([this.open$, media("(max-width: 768px)")]).pipe( + map(([open, isSmallScreen]) => open && isSmallScreen), + ); + + get open() { + return this._open$.getValue(); + } + + setOpen() { + this._open$.next(true); + } + + setClose() { + this._open$.next(false); + } + + toggle() { + const curr = this._open$.getValue(); + if (curr) { + this.setClose(); + } else { + this.setOpen(); + } + } +} + +export const media = (query: string): Observable => { + const mediaQuery = window.matchMedia(query); + return fromEvent(mediaQuery, "change").pipe( + startWith(mediaQuery), + map((list: MediaQueryList) => list.matches), + ); +}; diff --git a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts index 70adb21191..f9d1e4166f 100644 --- a/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts +++ b/libs/components/src/stories/kitchen-sink/kitchen-sink.stories.ts @@ -99,14 +99,14 @@ export const Default: Story = { return { props: args, template: /* HTML */ ` - + `, }; diff --git a/libs/components/src/utils/position-fixed-wrapper-decorator.ts b/libs/components/src/utils/position-fixed-wrapper-decorator.ts new file mode 100644 index 0000000000..a3298e6ad0 --- /dev/null +++ b/libs/components/src/utils/position-fixed-wrapper-decorator.ts @@ -0,0 +1,17 @@ +import { componentWrapperDecorator } from "@storybook/angular"; + +/** + * Render a story that uses `position: fixed` + * Used in layout and navigation components + **/ +export const positionFixedWrapperDecorator = (wrapper?: (story: string) => string) => + componentWrapperDecorator( + /** + * Applying a CSS transform makes a `position: fixed` element act like it is `position: relative` + * https://github.com/storybookjs/storybook/issues/8011#issue-490251969 + */ + (story) => + /* HTML */ `
+ ${wrapper ? wrapper(story) : story} +
`, + ); From 1970abf723a147dc93d85fb300029f614830c1ff Mon Sep 17 00:00:00 2001 From: Bernd Schoolmann Date: Mon, 17 Jun 2024 20:47:06 +0200 Subject: [PATCH 14/31] [PM-4370] Implement PRF key rotation (#9517) * Add prf key rotation * Fix tests * Re-add comment * Remove encrypted private key from webauthnlogincredentialresponse * Refactor to use rotateablekeyset * Move key rotation logic to webauthn-login-admin service * Fix type error * Add parameter validation * Add documentation * Add input validation * Add tests --- .../services/rotateable-key-set.service.ts | 38 +++++++++++ .../webauthn-login-credential.response.ts | 24 +++++++ .../webauthn-login-admin-api.service.ts | 8 ++- .../webauthn-login-admin.service.spec.ts | 64 ++++++++++++++++++- .../webauthn-login-admin.service.ts | 42 ++++++++++++ .../request/update-key.request.ts | 2 + .../user-key-rotation.service.spec.ts | 11 +++- .../key-rotation/user-key-rotation.service.ts | 7 ++ .../models/domain/rotateable-key-set.ts | 2 +- .../webauthn-rotate-credential.request.ts | 26 ++++++++ 10 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 libs/common/src/auth/models/request/webauthn-rotate-credential.request.ts diff --git a/apps/web/src/app/auth/core/services/rotateable-key-set.service.ts b/apps/web/src/app/auth/core/services/rotateable-key-set.service.ts index 04b24e0eb0..72f9744056 100644 --- a/apps/web/src/app/auth/core/services/rotateable-key-set.service.ts +++ b/apps/web/src/app/auth/core/services/rotateable-key-set.service.ts @@ -29,4 +29,42 @@ export class RotateableKeySetService { const encryptedPublicKey = await this.encryptService.encrypt(rawPublicKey, userKey); return new RotateableKeySet(encryptedUserKey, encryptedPublicKey, encryptedPrivateKey); } + + /** + * Rotates the current user's `UserKey` and updates the provided `RotateableKeySet` with the new keys. + * + * @param keySet The current `RotateableKeySet` for the user + * @returns The updated `RotateableKeySet` with the new `UserKey` + */ + async rotateKeySet( + keySet: RotateableKeySet, + oldUserKey: SymmetricCryptoKey, + newUserKey: SymmetricCryptoKey, + ): Promise> { + // validate parameters + if (!keySet) { + throw new Error("failed to rotate key set: keySet is required"); + } + if (!oldUserKey) { + throw new Error("failed to rotate key set: oldUserKey is required"); + } + if (!newUserKey) { + throw new Error("failed to rotate key set: newUserKey is required"); + } + + const publicKey = await this.encryptService.decryptToBytes( + keySet.encryptedPublicKey, + oldUserKey, + ); + const newEncryptedPublicKey = await this.encryptService.encrypt(publicKey, newUserKey); + const newEncryptedUserKey = await this.encryptService.rsaEncrypt(newUserKey.key, publicKey); + + const newRotateableKeySet = new RotateableKeySet( + newEncryptedUserKey, + newEncryptedPublicKey, + keySet.encryptedPrivateKey, + ); + + return newRotateableKeySet; + } } 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 index 2d8876915a..f96ed38bdc 100644 --- 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 @@ -1,4 +1,6 @@ +import { RotateableKeySet } from "@bitwarden/auth/common"; import { BaseResponse } from "@bitwarden/common/models/response/base.response"; +import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { WebauthnLoginCredentialPrfStatus } from "../../../enums/webauthn-login-credential-prf-status.enum"; @@ -9,11 +11,33 @@ export class WebauthnLoginCredentialResponse extends BaseResponse { id: string; name: string; prfStatus: WebauthnLoginCredentialPrfStatus; + encryptedPublicKey?: string; + encryptedUserKey?: string; constructor(response: unknown) { super(response); this.id = this.getResponseProperty("Id"); this.name = this.getResponseProperty("Name"); this.prfStatus = this.getResponseProperty("PrfStatus"); + this.encryptedPublicKey = this.getResponseProperty("EncryptedPublicKey"); + this.encryptedUserKey = this.getResponseProperty("EncryptedUserKey"); + } + + getRotateableKeyset(): RotateableKeySet { + if (!EncString.isSerializedEncString(this.encryptedUserKey)) { + throw new Error("Invalid encrypted user key"); + } + if (!EncString.isSerializedEncString(this.encryptedPublicKey)) { + throw new Error("Invalid encrypted public key"); + } + + return new RotateableKeySet( + new EncString(this.encryptedUserKey), + new EncString(this.encryptedPublicKey), + ); + } + + hasPrfKeyset(): boolean { + return this.encryptedUserKey != null && this.encryptedPublicKey != null; } } diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin-api.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin-api.service.ts index efa32d0c6f..333140a171 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin-api.service.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin-api.service.ts @@ -45,8 +45,12 @@ export class WebAuthnLoginAdminApiService { return true; } - getCredentials(): Promise> { - return this.apiService.send("GET", "/webauthn", null, true, true); + async getCredentials(): Promise> { + const response = await this.apiService.send("GET", "/webauthn", null, true, true); + return new ListResponse( + response, + WebauthnLoginCredentialResponse, + ); } async deleteCredential(credentialId: string, request: SecretVerificationRequest): Promise { diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.spec.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.spec.ts index 531dd3a813..4ad712b935 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.spec.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.spec.ts @@ -9,7 +9,8 @@ import { WebAuthnLoginCredentialAssertionView } from "@bitwarden/common/auth/mod import { WebAuthnLoginAssertionResponseRequest } from "@bitwarden/common/auth/services/webauthn-login/request/webauthn-login-assertion-response.request"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { PrfKey } from "@bitwarden/common/types/key"; +import { makeSymmetricCryptoKey } from "@bitwarden/common/spec"; +import { PrfKey, UserKey } from "@bitwarden/common/types/key"; import { CredentialCreateOptionsView } from "../../views/credential-create-options.view"; import { PendingWebauthnLoginCredentialView } from "../../views/pending-webauthn-login-credential.view"; @@ -184,6 +185,67 @@ describe("WebauthnAdminService", () => { } }); }); + + describe("rotateCredentials", () => { + it("should throw when old userkey is null", async () => { + const newUserKey = makeSymmetricCryptoKey(64) as UserKey; + try { + await service.rotateWebAuthnKeys(null, newUserKey); + } catch (error) { + expect(error).toEqual(new Error("oldUserKey is required")); + } + }); + it("should throw when new userkey is null", async () => { + const oldUserKey = makeSymmetricCryptoKey(64) as UserKey; + try { + await service.rotateWebAuthnKeys(oldUserKey, null); + } catch (error) { + expect(error).toEqual(new Error("newUserKey is required")); + } + }); + it("should call rotateKeySet with the correct parameters", async () => { + const oldUserKey = makeSymmetricCryptoKey(64) as UserKey; + const newUserKey = makeSymmetricCryptoKey(64) as UserKey; + const mockEncryptedPublicKey = new EncString("test_encryptedPublicKey"); + const mockEncryptedUserKey = new EncString("test_encryptedUserKey"); + jest.spyOn(apiService, "getCredentials").mockResolvedValue({ + data: [ + { + getRotateableKeyset: () => + new RotateableKeySet(mockEncryptedUserKey, mockEncryptedPublicKey), + hasPrfKeyset: () => true, + }, + ], + } as any); + const rotateKeySetMock = jest + .spyOn(rotateableKeySetService, "rotateKeySet") + .mockResolvedValue( + new RotateableKeySet(mockEncryptedUserKey, mockEncryptedPublicKey), + ); + await service.rotateWebAuthnKeys(oldUserKey, newUserKey); + expect(rotateKeySetMock).toHaveBeenCalledWith( + expect.any(RotateableKeySet), + oldUserKey, + newUserKey, + ); + }); + it("should skip rotation when no prf keyset is available", async () => { + const oldUserKey = makeSymmetricCryptoKey(64) as UserKey; + const newUserKey = makeSymmetricCryptoKey(64) as UserKey; + jest.spyOn(apiService, "getCredentials").mockResolvedValue({ + data: [ + { + getRotateableKeyset: () => + new RotateableKeySet(new EncString("test_encryptedUserKey"), null), + hasPrfKeyset: () => false, + }, + ], + } as any); + const rotateKeySetMock = jest.spyOn(rotateableKeySetService, "rotateKeySet"); + await service.rotateWebAuthnKeys(oldUserKey, newUserKey); + expect(rotateKeySetMock).not.toHaveBeenCalled(); + }); + }); }); function createCredentialCreateOptions(): CredentialCreateOptionsView { diff --git a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.ts b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.ts index 42b6981c21..fadf5cbd29 100644 --- a/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.ts +++ b/apps/web/src/app/auth/core/services/webauthn-login/webauthn-login-admin.service.ts @@ -4,10 +4,12 @@ import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, import { PrfKeySet } from "@bitwarden/auth/common"; import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction"; import { WebAuthnLoginPrfCryptoServiceAbstraction } from "@bitwarden/common/auth/abstractions/webauthn/webauthn-login-prf-crypto.service.abstraction"; +import { WebauthnRotateCredentialRequest } from "@bitwarden/common/auth/models/request/webauthn-rotate-credential.request"; import { WebAuthnLoginCredentialAssertionOptionsView } from "@bitwarden/common/auth/models/view/webauthn-login/webauthn-login-credential-assertion-options.view"; import { WebAuthnLoginCredentialAssertionView } from "@bitwarden/common/auth/models/view/webauthn-login/webauthn-login-credential-assertion.view"; import { Verification } from "@bitwarden/common/auth/types/verification"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserKey } from "@bitwarden/common/types/key"; import { CredentialCreateOptionsView } from "../../views/credential-create-options.view"; import { PendingWebauthnLoginCredentialView } from "../../views/pending-webauthn-login-credential.view"; @@ -273,4 +275,44 @@ export class WebauthnLoginAdminService { private refresh() { this._refresh$.next(); } + + /** + * Creates rotate credential requests for the purpose of user key rotation. + * This works by fetching the current webauthn credentials, filtering out the ones that have a PRF keyset, + * and rotating these using the rotateable key set service. + * + * @param oldUserKey The old user key + * @param newUserKey The new user key + * @returns A promise that returns an array of rotate credential requests when resolved. + */ + async rotateWebAuthnKeys( + oldUserKey: UserKey, + newUserKey: UserKey, + ): Promise { + if (!oldUserKey) { + throw new Error("oldUserKey is required"); + } + if (!newUserKey) { + throw new Error("newUserKey is required"); + } + + return Promise.all( + (await this.apiService.getCredentials()).data + .filter((credential) => credential.hasPrfKeyset()) + .map(async (response) => { + const keyset = response.getRotateableKeyset(); + const rotatedKeyset = await this.rotateableKeySetService.rotateKeySet( + keyset, + oldUserKey, + newUserKey, + ); + const request = new WebauthnRotateCredentialRequest( + response.id, + rotatedKeyset.encryptedPublicKey, + rotatedKeyset.encryptedUserKey, + ); + return request; + }), + ); + } } diff --git a/apps/web/src/app/auth/key-rotation/request/update-key.request.ts b/apps/web/src/app/auth/key-rotation/request/update-key.request.ts index f8637110e7..9ea40c88e6 100644 --- a/apps/web/src/app/auth/key-rotation/request/update-key.request.ts +++ b/apps/web/src/app/auth/key-rotation/request/update-key.request.ts @@ -1,4 +1,5 @@ import { OrganizationUserResetPasswordWithIdRequest } from "@bitwarden/common/admin-console/abstractions/organization-user/requests"; +import { WebauthnRotateCredentialRequest } from "@bitwarden/common/auth/models/request/webauthn-rotate-credential.request"; import { SendWithIdRequest } from "@bitwarden/common/src/tools/send/models/request/send-with-id.request"; import { CipherWithIdRequest } from "@bitwarden/common/src/vault/models/request/cipher-with-id.request"; import { FolderWithIdRequest } from "@bitwarden/common/src/vault/models/request/folder-with-id.request"; @@ -14,4 +15,5 @@ export class UpdateKeyRequest { sends: SendWithIdRequest[] = []; emergencyAccessKeys: EmergencyAccessWithIdRequest[] = []; resetPasswordKeys: OrganizationUserResetPasswordWithIdRequest[] = []; + webauthnKeys: WebauthnRotateCredentialRequest[] = []; } diff --git a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts index c3d568e118..5addcceabf 100644 --- a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts +++ b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.spec.ts @@ -1,5 +1,5 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction"; import { KdfConfigService } from "@bitwarden/common/auth/abstractions/kdf-config.service"; @@ -30,6 +30,7 @@ import { } from "../../../../../../libs/common/spec/fake-account-service"; import { OrganizationUserResetPasswordService } from "../../admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service"; import { StateService } from "../../core"; +import { WebauthnLoginAdminService } from "../core"; import { EmergencyAccessService } from "../emergency-access"; import { UserKeyRotationApiService } from "./user-key-rotation-api.service"; @@ -51,6 +52,7 @@ describe("KeyRotationService", () => { let mockConfigService: MockProxy; let mockKdfConfigService: MockProxy; let mockSyncService: MockProxy; + let mockWebauthnLoginAdminService: MockProxy; const mockUserId = Utils.newGuid() as UserId; const mockAccountService: FakeAccountService = mockAccountServiceWith(mockUserId); @@ -71,6 +73,7 @@ describe("KeyRotationService", () => { mockConfigService = mock(); mockKdfConfigService = mock(); mockSyncService = mock(); + mockWebauthnLoginAdminService = mock(); keyRotationService = new UserKeyRotationService( mockMasterPasswordService, @@ -87,6 +90,7 @@ describe("KeyRotationService", () => { mockAccountService, mockKdfConfigService, mockSyncService, + mockWebauthnLoginAdminService, ); }); @@ -115,6 +119,9 @@ describe("KeyRotationService", () => { // Mock private key mockCryptoService.getPrivateKey.mockResolvedValue("MockPrivateKey" as any); + mockCryptoService.userKey$.mockReturnValue( + of(new SymmetricCryptoKey(new Uint8Array(64)) as UserKey), + ); // Mock ciphers const mockCiphers = [createMockCipher("1", "Cipher 1"), createMockCipher("2", "Cipher 2")]; @@ -130,6 +137,8 @@ describe("KeyRotationService", () => { sends = new BehaviorSubject(mockSends); mockSendService.sends$ = sends; + mockWebauthnLoginAdminService.rotateWebAuthnKeys.mockResolvedValue([]); + // Mock encryption methods mockEncryptService.encrypt.mockResolvedValue({ encryptedString: "mockEncryptedData", diff --git a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts index cac2dafd51..883d0fef88 100644 --- a/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts +++ b/apps/web/src/app/auth/key-rotation/user-key-rotation.service.ts @@ -18,6 +18,7 @@ import { CipherWithIdRequest } from "@bitwarden/common/vault/models/request/ciph import { FolderWithIdRequest } from "@bitwarden/common/vault/models/request/folder-with-id.request"; import { OrganizationUserResetPasswordService } from "../../admin-console/organizations/members/services/organization-user-reset-password/organization-user-reset-password.service"; +import { WebauthnLoginAdminService } from "../core"; import { EmergencyAccessService } from "../emergency-access"; import { UpdateKeyRequest } from "./request/update-key.request"; @@ -40,6 +41,7 @@ export class UserKeyRotationService { private accountService: AccountService, private kdfConfigService: KdfConfigService, private syncService: SyncService, + private webauthnLoginAdminService: WebauthnLoginAdminService, ) {} /** @@ -70,6 +72,7 @@ export class UserKeyRotationService { // Set master key again in case it was lost (could be lost on refresh) const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id; + const oldUserKey = await firstValueFrom(this.cryptoService.userKey$(userId)); await this.masterPasswordService.setMasterKey(masterKey, userId); const [newUserKey, newEncUserKey] = await this.cryptoService.makeUserKey(masterKey); @@ -94,6 +97,10 @@ export class UserKeyRotationService { request.sends = await this.sendService.getRotatedKeys(newUserKey); request.emergencyAccessKeys = await this.emergencyAccessService.getRotatedKeys(newUserKey); request.resetPasswordKeys = await this.resetPasswordService.getRotatedKeys(newUserKey); + request.webauthnKeys = await this.webauthnLoginAdminService.rotateWebAuthnKeys( + oldUserKey, + newUserKey, + ); await this.apiService.postUserKeyUpdate(request); diff --git a/libs/auth/src/common/models/domain/rotateable-key-set.ts b/libs/auth/src/common/models/domain/rotateable-key-set.ts index 9930010c15..5e0faea339 100644 --- a/libs/auth/src/common/models/domain/rotateable-key-set.ts +++ b/libs/auth/src/common/models/domain/rotateable-key-set.ts @@ -27,7 +27,7 @@ export class RotateableKeySet Date: Mon, 17 Jun 2024 13:49:29 -0500 Subject: [PATCH 15/31] [PM-8027] Inline menu appears within input fields that do not relate to user login (#9110) * [PM-8027] Inlin menu appears within input fields that do not relate to user login * [PM-8027] Inlin menu appears within input fields that do not relate to user login * [PM-8027] Inlin menu appears within input fields that do not relate to user login * [PM-8027] Working through logic heuristics that will help us determine login form fields * [PM-8027] Fixing jest test * [PM-8027] Reworking inline menu to qualify and setup the listeners for each form field after page deatils have been collected * [PM-8027] Cleaning up implementation details * [PM-8027] Cleaning up implementation details * [PM-8027] Cleaning up implementation details * [PM-8027] Updating update of page details after mutation to act on an idle moment in the browser * [PM-8027] Updating how we guard against excessive getPageDetails calls * [PM-8027] Refining how we identify a username login form field * [PM-8027] Refining how we identify a password login form field * [PM-8027] Refining how we identify a username login form field * [PM-8027] Fixing jest tests for the overlay * [PM-8027] Fixing jest tests for the collectPageDetails method * [PM-8027] Removing unnecessary code * [PM-8027] Removing unnecessary code * [PM-8027] Adding jest test to validate new behavior * [PM-8027] Working through jest tests for the InlineMenuFieldQualificationService * [PM-8027] Working through jest tests for the InlineMenuFieldQualificationService * [PM-8027] Working through jest tests for the InlineMenuFieldQualificationService * [PM-8027] Working through jest tests for the InlineMenuFieldQualificationService * [PM-8027] Working through jest tests for the InlineMenuFieldQualificationService * [PM-8027] Finalization of Jest test for the implementation * [PM-8027] Fixing a typo * [PM-8027] Incorporating a feature flag to allow us to fallback to the basic inline menu fielld qualification method if needed * [PM-8027] Incorporating a feature flag to allow us to fallback to the basic inline menu fielld qualification method if needed * [PM-8027] Fixing issue with username fields not qualifyng as a valid login field if a viewable password field is not present * [PM-8027] Fixing an issue where a field that has no form and no visible password fields should be qualified if a single password field exists in the page * [PM-8027] Fixing an issue where a field that has no form and no visible password fields should be qualified if a single password field exists in the page * [PM-8869] Autofill features broken on Safari * [PM-8869] Autofill features broken on Safari * [PM-5189] Fixing an issue found within Safari * [PM-8027] Reverting flag from a fallback flag to an enhancement feature flag * [PM-8027] Fixing jest tests --- .../autofill-overlay-content.service.ts | 2 + ...nline-menu-field-qualifications.service.ts | 6 + .../autofill-overlay-content.service.spec.ts | 69 +- .../autofill-overlay-content.service.ts | 77 +- .../collect-autofill-content.service.spec.ts | 9 +- .../collect-autofill-content.service.ts | 105 ++- ...e-menu-field-qualification.service.spec.ts | 662 ++++++++++++++++++ ...inline-menu-field-qualification.service.ts | 438 ++++++++++++ apps/browser/src/autofill/utils/index.ts | 18 +- .../src/background/runtime.background.ts | 4 + libs/common/src/enums/feature-flag.enum.ts | 2 + 11 files changed, 1300 insertions(+), 92 deletions(-) create mode 100644 apps/browser/src/autofill/services/abstractions/inline-menu-field-qualifications.service.ts create mode 100644 apps/browser/src/autofill/services/inline-menu-field-qualification.service.spec.ts create mode 100644 apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts diff --git a/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts index ec594ac829..4a6d87e0a4 100644 --- a/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/abstractions/autofill-overlay-content.service.ts @@ -1,6 +1,7 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status"; import AutofillField from "../../models/autofill-field"; +import AutofillPageDetails from "../../models/autofill-page-details"; import { ElementWithOpId, FormFieldElement } from "../../types"; type OpenAutofillOverlayOptions = { @@ -19,6 +20,7 @@ interface AutofillOverlayContentService { setupAutofillOverlayListenerOnField( autofillFieldElement: ElementWithOpId, autofillFieldData: AutofillField, + pageDetails: AutofillPageDetails, ): Promise; openAutofillOverlay(options: OpenAutofillOverlayOptions): void; removeAutofillOverlay(): void; diff --git a/apps/browser/src/autofill/services/abstractions/inline-menu-field-qualifications.service.ts b/apps/browser/src/autofill/services/abstractions/inline-menu-field-qualifications.service.ts new file mode 100644 index 0000000000..c8303c0f81 --- /dev/null +++ b/apps/browser/src/autofill/services/abstractions/inline-menu-field-qualifications.service.ts @@ -0,0 +1,6 @@ +import AutofillField from "../../models/autofill-field"; +import AutofillPageDetails from "../../models/autofill-page-details"; + +export interface InlineMenuFieldQualificationsService { + isFieldForLoginForm(field: AutofillField, pageDetails: AutofillPageDetails): boolean; +} diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts index 96a1b4c851..6b8cb91a16 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.spec.ts @@ -4,6 +4,8 @@ import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authenticatio import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/constants"; import AutofillField from "../models/autofill-field"; +import AutofillForm from "../models/autofill-form"; +import AutofillPageDetails from "../models/autofill-page-details"; import { createAutofillFieldMock } from "../spec/autofill-mocks"; import { flushPromises } from "../spec/testing-utils"; import { ElementWithOpId, FormFieldElement } from "../types"; @@ -146,6 +148,7 @@ describe("AutofillOverlayContentService", () => { describe("setupAutofillOverlayListenerOnField", () => { let autofillFieldElement: ElementWithOpId; let autofillFieldData: AutofillField; + let pageDetailsMock: AutofillPageDetails; beforeEach(() => { document.body.innerHTML = ` @@ -166,11 +169,27 @@ describe("AutofillOverlayContentService", () => { placeholder: "username", elementNumber: 1, }); + const passwordFieldData = createAutofillFieldMock({ + opid: "password-field", + form: "validFormId", + elementNumber: 2, + autocompleteType: "current-password", + type: "password", + }); + pageDetailsMock = mock({ + forms: { validFormId: mock() }, + fields: [autofillFieldData, passwordFieldData], + }); }); describe("skips setup for ignored form fields", () => { beforeEach(() => { - autofillFieldData = mock(); + autofillFieldData = mock({ + type: "text", + htmlName: "username", + htmlID: "username", + placeholder: "username", + }); }); it("ignores fields that are readonly", async () => { @@ -179,6 +198,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -190,6 +210,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -201,6 +222,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -213,6 +235,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -225,6 +248,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -236,6 +260,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -247,6 +272,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -259,6 +285,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.addEventListener).not.toHaveBeenCalled(); @@ -272,6 +299,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(sendExtensionMessageSpy).toHaveBeenCalledWith("getAutofillOverlayVisibility"); @@ -287,6 +315,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillOverlayContentService["autofillOverlayVisibility"]).toEqual( @@ -310,6 +339,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillFieldElement.removeEventListener).toHaveBeenNthCalledWith( @@ -334,6 +364,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); }); @@ -357,6 +388,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); jest.spyOn(globalThis.customElements, "define").mockImplementation(); }); @@ -440,6 +472,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( spanAutofillFieldElement, autofillFieldData, + pageDetailsMock, ); spanAutofillFieldElement.dispatchEvent(new Event("input")); @@ -451,6 +484,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -467,6 +501,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( passwordFieldElement, autofillFieldData, + pageDetailsMock, ); passwordFieldElement.dispatchEvent(new Event("input")); @@ -486,6 +521,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -504,6 +540,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -517,6 +554,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -531,6 +569,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -546,6 +585,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("input")); @@ -563,6 +603,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); }); @@ -613,6 +654,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -624,6 +666,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -641,6 +684,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -660,6 +704,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -678,6 +723,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -695,6 +741,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -711,6 +758,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillFieldElement.dispatchEvent(new Event("focus")); @@ -733,6 +781,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(sendExtensionMessageSpy).toHaveBeenCalledWith("openAutofillOverlay"); @@ -747,6 +796,7 @@ describe("AutofillOverlayContentService", () => { await autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); expect(autofillOverlayContentService["mostRecentlyFocusedField"]).toEqual( @@ -1589,6 +1639,7 @@ describe("AutofillOverlayContentService", () => { describe("destroy", () => { let autofillFieldElement: ElementWithOpId; let autofillFieldData: AutofillField; + let pageDetailsMock: AutofillPageDetails; beforeEach(() => { document.body.innerHTML = ` @@ -1608,11 +1659,21 @@ describe("AutofillOverlayContentService", () => { placeholder: "username", elementNumber: 1, }); - // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. - // eslint-disable-next-line @typescript-eslint/no-floating-promises - autofillOverlayContentService.setupAutofillOverlayListenerOnField( + const passwordFieldData = createAutofillFieldMock({ + opid: "password-field", + form: "validFormId", + elementNumber: 2, + autocompleteType: "current-password", + type: "password", + }); + pageDetailsMock = mock({ + forms: { validFormId: mock() }, + fields: [autofillFieldData, passwordFieldData], + }); + void autofillOverlayContentService.setupAutofillOverlayListenerOnField( autofillFieldElement, autofillFieldData, + pageDetailsMock, ); autofillOverlayContentService["mostRecentlyFocusedField"] = autofillFieldElement; }); diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts index 43c0817eaf..d56a8a80cc 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -7,6 +7,7 @@ import { EVENTS, AutofillOverlayVisibility } from "@bitwarden/common/autofill/co import { FocusedFieldData } from "../background/abstractions/overlay.background"; import AutofillField from "../models/autofill-field"; +import AutofillPageDetails from "../models/autofill-page-details"; import AutofillOverlayButtonIframe from "../overlay/iframe-content/autofill-overlay-button-iframe"; import AutofillOverlayListIframe from "../overlay/iframe-content/autofill-overlay-list-iframe"; import { ElementWithOpId, FillableFormFieldElement, FormFieldElement } from "../types"; @@ -23,8 +24,10 @@ import { OpenAutofillOverlayOptions, } from "./abstractions/autofill-overlay-content.service"; import { AutoFillConstants } from "./autofill-constants"; +import { InlineMenuFieldQualificationService } from "./inline-menu-field-qualification.service"; class AutofillOverlayContentService implements AutofillOverlayContentServiceInterface { + private readonly inlineMenuFieldQualificationService: InlineMenuFieldQualificationService; isFieldCurrentlyFocused = false; isCurrentlyFilling = false; isOverlayCiphersPopulated = false; @@ -62,6 +65,10 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte zIndex: "2147483647", }; + constructor() { + this.inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService(); + } + /** * Initializes the autofill overlay content service by setting up the mutation observers. * The observers will be instantiated on DOMContentLoaded if the page is current loading. @@ -81,12 +88,17 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte * * @param formFieldElement - Form field elements identified during the page details collection process. * @param autofillFieldData - Autofill field data captured from the form field element. + * @param pageDetails - The collected page details from the tab. */ async setupAutofillOverlayListenerOnField( formFieldElement: ElementWithOpId, autofillFieldData: AutofillField, + pageDetails: AutofillPageDetails, ) { - if (this.isIgnoredField(autofillFieldData) || this.formFieldElements.has(formFieldElement)) { + if ( + this.formFieldElements.has(formFieldElement) || + this.isIgnoredField(autofillFieldData, pageDetails) + ) { return; } @@ -524,51 +536,6 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte return this.authStatus === AuthenticationStatus.Unlocked; } - /** - * Identifies if the autofill field's data contains any of - * the keyboards matching the passed list of keywords. - * - * @param autofillFieldData - Autofill field data captured from the form field element. - * @param keywords - Keywords to search for in the autofill field data. - */ - private keywordsFoundInFieldData(autofillFieldData: AutofillField, keywords: string[]) { - const searchedString = this.getAutofillFieldDataKeywords(autofillFieldData); - return keywords.some((keyword) => searchedString.includes(keyword)); - } - - /** - * Aggregates the autofill field's data into a single string - * that can be used to search for keywords. - * - * @param autofillFieldData - Autofill field data captured from the form field element. - */ - private getAutofillFieldDataKeywords(autofillFieldData: AutofillField) { - if (this.autofillFieldKeywordsMap.has(autofillFieldData)) { - return this.autofillFieldKeywordsMap.get(autofillFieldData); - } - - const keywordValues = [ - autofillFieldData.htmlID, - autofillFieldData.htmlName, - autofillFieldData.htmlClass, - autofillFieldData.type, - autofillFieldData.title, - autofillFieldData.placeholder, - autofillFieldData.autoCompleteType, - autofillFieldData["label-data"], - autofillFieldData["label-aria"], - autofillFieldData["label-left"], - autofillFieldData["label-right"], - autofillFieldData["label-tag"], - autofillFieldData["label-top"], - ] - .join(",") - .toLowerCase(); - this.autofillFieldKeywordsMap.set(autofillFieldData, keywordValues); - - return keywordValues; - } - /** * Validates that the most recently focused field is currently * focused within the root node relative to the field. @@ -739,23 +706,25 @@ class AutofillOverlayContentService implements AutofillOverlayContentServiceInte * updated in the future to support other types of forms. * * @param autofillFieldData - Autofill field data captured from the form field element. + * @param pageDetails - The collected page details from the tab. */ - private isIgnoredField(autofillFieldData: AutofillField): boolean { + private isIgnoredField( + autofillFieldData: AutofillField, + pageDetails: AutofillPageDetails, + ): boolean { if ( autofillFieldData.readonly || autofillFieldData.disabled || !autofillFieldData.viewable || - this.ignoredFieldTypes.has(autofillFieldData.type) || - this.keywordsFoundInFieldData(autofillFieldData, ["search", "captcha"]) + this.ignoredFieldTypes.has(autofillFieldData.type) ) { return true; } - const isLoginCipherField = - autofillFieldData.type === "password" || - this.keywordsFoundInFieldData(autofillFieldData, AutoFillConstants.UsernameFieldNames); - - return !isLoginCipherField; + return !this.inlineMenuFieldQualificationService.isFieldForLoginForm( + autofillFieldData, + pageDetails, + ); } /** diff --git a/apps/browser/src/autofill/services/collect-autofill-content.service.spec.ts b/apps/browser/src/autofill/services/collect-autofill-content.service.spec.ts index a44fcd0b79..9bb0e717a2 100644 --- a/apps/browser/src/autofill/services/collect-autofill-content.service.spec.ts +++ b/apps/browser/src/autofill/services/collect-autofill-content.service.spec.ts @@ -35,6 +35,7 @@ describe("CollectAutofillContentService", () => { beforeEach(() => { globalThis.requestIdleCallback = jest.fn((cb, options) => setTimeout(cb, 100)); + globalThis.cancelIdleCallback = jest.fn((id) => clearTimeout(id)); document.body.innerHTML = mockLoginForm; collectAutofillContentService = new CollectAutofillContentService( domElementVisibilityService, @@ -247,11 +248,16 @@ describe("CollectAutofillContentService", () => { const isFormFieldViewableSpy = jest .spyOn(collectAutofillContentService["domElementVisibilityService"], "isFormFieldViewable") .mockResolvedValue(true); + const setupAutofillOverlayListenerOnFieldSpy = jest.spyOn( + collectAutofillContentService["autofillOverlayContentService"], + "setupAutofillOverlayListenerOnField", + ); await collectAutofillContentService.getPageDetails(); expect(autofillField.viewable).toBe(true); expect(isFormFieldViewableSpy).toHaveBeenCalledWith(fieldElement); + expect(setupAutofillOverlayListenerOnFieldSpy).toHaveBeenCalled(); }); it("returns an object containing information about the current page as well as autofill data for the forms and fields of the page", async () => { @@ -1191,7 +1197,7 @@ describe("CollectAutofillContentService", () => { "aria-disabled": false, "aria-haspopup": false, "aria-hidden": false, - autoCompleteType: null, + autoCompleteType: "off", checked: false, "data-stripe": hiddenField.dataStripe, disabled: false, @@ -2606,6 +2612,7 @@ describe("CollectAutofillContentService", () => { expect(setupAutofillOverlayListenerOnFieldSpy).toHaveBeenCalledWith( formFieldElement, autofillField, + expect.anything(), ); }); }); diff --git a/apps/browser/src/autofill/services/collect-autofill-content.service.ts b/apps/browser/src/autofill/services/collect-autofill-content.service.ts index 4205590973..75c564e868 100644 --- a/apps/browser/src/autofill/services/collect-autofill-content.service.ts +++ b/apps/browser/src/autofill/services/collect-autofill-content.service.ts @@ -4,32 +4,33 @@ import AutofillPageDetails from "../models/autofill-page-details"; import { ElementWithOpId, FillableFormFieldElement, - FormFieldElement, FormElementWithAttribute, + FormFieldElement, } from "../types"; import { elementIsDescriptionDetailsElement, elementIsDescriptionTermElement, elementIsFillableFormField, elementIsFormElement, + elementIsInputElement, elementIsLabelElement, elementIsSelectElement, elementIsSpanElement, nodeIsElement, - elementIsInputElement, elementIsTextAreaElement, nodeIsFormElement, nodeIsInputElement, // sendExtensionMessage, requestIdleCallbackPolyfill, + cancelIdleCallbackPolyfill, } from "../utils"; import { AutofillOverlayContentService } from "./abstractions/autofill-overlay-content.service"; import { - UpdateAutofillDataAttributeParams, AutofillFieldElements, AutofillFormElements, CollectAutofillContentService as CollectAutofillContentServiceInterface, + UpdateAutofillDataAttributeParams, } from "./abstractions/collect-autofill-content.service"; import { DomElementVisibilityService } from "./abstractions/dom-element-visibility.service"; @@ -44,9 +45,9 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte private intersectionObserver: IntersectionObserver; private elementInitializingIntersectionObserver: Set = new Set(); private mutationObserver: MutationObserver; - private updateAutofillElementsAfterMutationTimeout: number | NodeJS.Timeout; private mutationsQueue: MutationRecord[][] = []; - private readonly updateAfterMutationTimeoutDelay = 1000; + private updateAfterMutationIdleCallback: NodeJS.Timeout | number; + private readonly updateAfterMutationTimeout = 1000; private readonly formFieldQueryString; private readonly nonInputFormFieldTags = new Set(["textarea", "select"]); private readonly ignoredInputTypes = new Set([ @@ -120,7 +121,10 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte } this.domRecentlyMutated = false; - return this.getFormattedPageDetails(autofillFormsData, autofillFieldsData); + const pageDetails = this.getFormattedPageDetails(autofillFormsData, autofillFieldsData); + this.setupInlineMenuListeners(pageDetails); + + return pageDetails; } /** @@ -277,11 +281,14 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte * @private */ private updateCachedAutofillFieldVisibility() { - this.autofillFieldElements.forEach( - async (autofillField, element) => - (autofillField.viewable = - await this.domElementVisibilityService.isFormFieldViewable(element)), - ); + this.autofillFieldElements.forEach(async (autofillField, element) => { + const previouslyViewable = autofillField.viewable; + autofillField.viewable = await this.domElementVisibilityService.isFormFieldViewable(element); + + if (!previouslyViewable && autofillField.viewable) { + this.setupInlineMenuListenerOnField(element, autofillField); + } + }); } /** @@ -453,10 +460,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte if (elementIsSpanElement(element)) { this.cacheAutofillFieldElement(index, element, autofillFieldBase); - void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField( - element, - autofillFieldBase, - ); return autofillFieldBase; } @@ -496,10 +499,6 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte }; this.cacheAutofillFieldElement(index, element, autofillField); - void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField( - element, - autofillField, - ); return autofillField; }; @@ -531,11 +530,11 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte * @private */ private getAutoCompleteAttribute(element: ElementWithOpId): string { - const autoCompleteType = + return ( this.getPropertyOrAttribute(element, "x-autocompletetype") || this.getPropertyOrAttribute(element, "autocompletetype") || - this.getPropertyOrAttribute(element, "autocomplete"); - return autoCompleteType !== "off" ? autoCompleteType : null; + this.getPropertyOrAttribute(element, "autocomplete") + ); } /** @@ -1229,13 +1228,13 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte * @private */ private updateAutofillElementsAfterMutation() { - if (this.updateAutofillElementsAfterMutationTimeout) { - clearTimeout(this.updateAutofillElementsAfterMutationTimeout); + if (this.updateAfterMutationIdleCallback) { + cancelIdleCallbackPolyfill(this.updateAfterMutationIdleCallback); } - this.updateAutofillElementsAfterMutationTimeout = setTimeout( + this.updateAfterMutationIdleCallback = requestIdleCallbackPolyfill( this.getPageDetails.bind(this), - this.updateAfterMutationTimeoutDelay, + { timeout: this.updateAfterMutationTimeout }, ); } @@ -1425,22 +1424,64 @@ class CollectAutofillContentService implements CollectAutofillContentServiceInte cachedAutofillFieldElement.viewable = true; - void this.autofillOverlayContentService?.setupAutofillOverlayListenerOnField( - formFieldElement, - cachedAutofillFieldElement, - ); + this.setupInlineMenuListenerOnField(formFieldElement, cachedAutofillFieldElement); this.intersectionObserver?.unobserve(entry.target); } }; + /** + * Iterates over all cached field elements and sets up the inline menu listeners on each field. + * + * @param pageDetails - The page details to use for the inline menu listeners + */ + private setupInlineMenuListeners(pageDetails: AutofillPageDetails) { + if (!this.autofillOverlayContentService) { + return; + } + + this.autofillFieldElements.forEach((autofillField, formFieldElement) => { + this.setupInlineMenuListenerOnField(formFieldElement, autofillField, pageDetails); + }); + } + + /** + * Sets up the inline menu listener on the passed field element. + * + * @param formFieldElement - The form field element to set up the inline menu listener on + * @param autofillField - The metadata for the form field + * @param pageDetails - The page details to use for the inline menu listeners + */ + private setupInlineMenuListenerOnField( + formFieldElement: ElementWithOpId, + autofillField: AutofillField, + pageDetails?: AutofillPageDetails, + ) { + if (!this.autofillOverlayContentService) { + return; + } + + const autofillPageDetails = + pageDetails || + this.getFormattedPageDetails( + this.getFormattedAutofillFormsData(), + this.getFormattedAutofillFieldsData(), + ); + + void this.autofillOverlayContentService.setupAutofillOverlayListenerOnField( + formFieldElement, + autofillField, + autofillPageDetails, + ); + } + /** * Destroys the CollectAutofillContentService. Clears all * timeouts and disconnects the mutation observer. */ destroy() { - if (this.updateAutofillElementsAfterMutationTimeout) { - clearTimeout(this.updateAutofillElementsAfterMutationTimeout); + if (this.updateAfterMutationIdleCallback) { + cancelIdleCallbackPolyfill(this.updateAfterMutationIdleCallback); } this.mutationObserver?.disconnect(); this.intersectionObserver?.disconnect(); diff --git a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.spec.ts b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.spec.ts new file mode 100644 index 0000000000..2942ba545e --- /dev/null +++ b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.spec.ts @@ -0,0 +1,662 @@ +import { mock, MockProxy } from "jest-mock-extended"; + +import AutofillField from "../models/autofill-field"; +import AutofillForm from "../models/autofill-form"; +import AutofillPageDetails from "../models/autofill-page-details"; + +import { AutoFillConstants } from "./autofill-constants"; +import { InlineMenuFieldQualificationService } from "./inline-menu-field-qualification.service"; + +describe("InlineMenuFieldQualificationService", () => { + let pageDetails: MockProxy; + let inlineMenuFieldQualificationService: InlineMenuFieldQualificationService; + + beforeEach(() => { + pageDetails = mock({ + forms: {}, + fields: [], + }); + inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService(); + inlineMenuFieldQualificationService["inlineMenuFieldQualificationFlagSet"] = true; + }); + + describe("isFieldForLoginForm", () => { + describe("qualifying a password field for a login form", () => { + describe("an invalid password field", () => { + it("has a `new-password` autoCompleteType", () => { + const field = mock({ + type: "password", + autoCompleteType: "new-password", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + false, + ); + }); + + it("has a type that is an excluded type", () => { + AutoFillConstants.ExcludedAutofillLoginTypes.forEach((excludedType) => { + const field = mock({ + type: excludedType, + }); + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + it("has an attribute present on the FieldIgnoreList, indicating that the field is a captcha", () => { + AutoFillConstants.FieldIgnoreList.forEach((attribute, index) => { + const field = mock({ + type: "password", + htmlID: index === 0 ? attribute : "", + htmlName: index === 1 ? attribute : "", + placeholder: index > 1 ? attribute : "", + }); + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + it("has a type other than `password` or `text`", () => { + const field = mock({ + type: "number", + htmlID: "not-password", + htmlName: "not-password", + placeholder: "not-password", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + false, + ); + }); + + it("has a type of `text` without an attribute that indicates the field is a password field", () => { + const field = mock({ + type: "text", + htmlID: "something-else", + htmlName: "something-else", + placeholder: "something-else", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + false, + ); + }); + + it("has a type of `text` and contains attributes that indicates the field is a search field", () => { + const field = mock({ + type: "text", + htmlID: "search", + htmlName: "something-else", + placeholder: "something-else", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + false, + ); + }); + + describe("does not have a parent form element", () => { + beforeEach(() => { + pageDetails.forms = {}; + }); + + it("on a page that has more than one password field", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "", + }); + const secondField = mock({ + type: "password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + }); + pageDetails.fields = [field, secondField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + + it("on a page that has more than one visible username field", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "", + }); + const usernameField = mock({ + type: "text", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const secondUsernameField = mock({ + type: "text", + htmlID: "some-other-user-username", + htmlName: "some-other-user-username", + placeholder: "some-other-user-username", + }); + pageDetails.fields = [field, usernameField, secondUsernameField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + + it("has a disabled `autocompleteType` value", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "", + autoCompleteType: "off", + }); + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + describe("has a parent form element", () => { + let form: MockProxy; + + beforeEach(() => { + form = mock({ opid: "validFormId" }); + pageDetails.forms = { + validFormId: form, + }; + }); + + it("is structured with other password fields in the same form", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + }); + const secondField = mock({ + type: "password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + form: "validFormId", + }); + pageDetails.fields = [field, secondField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + }); + + describe("a valid password field", () => { + it("has an autoCompleteType of `current-password`", () => { + const field = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + true, + ); + }); + + it("has a type of `text` with an attribute that indicates the field is a password field", () => { + const field = mock({ + type: "text", + htmlID: null, + htmlName: "user-password", + placeholder: "user-password", + }); + + expect(inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails)).toBe( + true, + ); + }); + + describe("does not have a parent form element", () => { + it("is the only password field on the page, has one username field on the page, and has a non-disabled `autocompleteType` value", () => { + pageDetails.forms = {}; + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "", + autoCompleteType: "current-password", + }); + const usernameField = mock({ + type: "text", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + pageDetails.fields = [field, usernameField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + }); + + describe("has a parent form element", () => { + let form: MockProxy; + + beforeEach(() => { + form = mock({ opid: "validFormId" }); + pageDetails.forms = { + validFormId: form, + }; + }); + + it("is the only password field within the form and has a visible username field", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + }); + const secondPasswordField = mock({ + type: "password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + form: "anotherFormId", + }); + const usernameField = mock({ + type: "text", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + pageDetails.fields = [field, secondPasswordField, usernameField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + + it("is the only password field within the form and has a non-disabled `autocompleteType` value", () => { + const field = mock({ + type: "password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + autoCompleteType: "", + }); + const secondPasswordField = mock({ + type: "password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + form: "anotherFormId", + }); + pageDetails.fields = [field, secondPasswordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + }); + }); + }); + + describe("qualifying a username field for a login form", () => { + describe("an invalid username field", () => { + ["username", "email"].forEach((autoCompleteType) => { + it(`has a ${autoCompleteType} 'autoCompleteType' value when structured on a page with new password fields`, () => { + const field = mock({ + type: "text", + autoCompleteType, + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "new-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + ["new", "change", "neue", "ändern"].forEach((keyword) => { + it(`has a keyword of ${keyword} that indicates a 'new or changed' username is being filled`, () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: `${keyword} username`, + }); + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + describe("does not have a parent form element", () => { + beforeEach(() => { + pageDetails.forms = {}; + }); + + it("is structured on a page with multiple password fields", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + }); + const secondPasswordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + }); + pageDetails.fields = [field, passwordField, secondPasswordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + + describe("has a parent form element", () => { + let form: MockProxy; + + beforeEach(() => { + form = mock({ opid: "validFormId" }); + pageDetails.forms = { + validFormId: form, + }; + }); + + it("is structured on a page with no password fields and has a disabled `autoCompleteType` value", () => { + const field = mock({ + type: "text", + autoCompleteType: "off", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + pageDetails.fields = [field]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + + it("is structured on a page with no password fields but has other types of fields in the form", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + const otherField = mock({ + type: "number", + autoCompleteType: "", + htmlID: "some-other-field", + htmlName: "some-other-field", + placeholder: "some-other-field", + form: "validFormId", + }); + pageDetails.fields = [field, otherField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + + it("is structured on a page with multiple viewable password field", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + }); + const secondPasswordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "some-other-password", + htmlName: "some-other-password", + placeholder: "some-other-password", + form: "validFormId", + }); + pageDetails.fields = [field, passwordField, secondPasswordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + + it("is structured on a page with a with no visible password fields and but contains a disabled autocomplete type", () => { + const field = mock({ + type: "text", + autoCompleteType: "off", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + viewable: false, + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(false); + }); + }); + }); + + describe("a valid username field", () => { + ["username", "email"].forEach((autoCompleteType) => { + it(`has a ${autoCompleteType} 'autoCompleteType' value`, () => { + const field = mock({ + type: "text", + autoCompleteType, + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + }); + + describe("does not have a parent form element", () => { + beforeEach(() => { + pageDetails.forms = {}; + }); + + it("is structured on a page with a single visible password field", () => { + const field = mock({ + type: "text", + autoCompleteType: "off", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + + it("is structured on a page with a single non-visible password field", () => { + const field = mock({ + type: "text", + autoCompleteType: "off", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + viewable: false, + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + + it("has a non-disabled autoCompleteType and is structured on a page with no other password fields", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + }); + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + }); + + describe("has a parent form element", () => { + let form: MockProxy; + + beforeEach(() => { + form = mock({ opid: "validFormId" }); + pageDetails.forms = { + validFormId: form, + }; + }); + + it("is structured on a page with a single password field", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + + it("is structured on a page with a with no visible password fields and a non-disabled autocomplete type", () => { + const field = mock({ + type: "text", + autoCompleteType: "", + htmlID: "user-username", + htmlName: "user-username", + placeholder: "user-username", + form: "validFormId", + }); + const passwordField = mock({ + type: "password", + autoCompleteType: "current-password", + htmlID: "user-password", + htmlName: "user-password", + placeholder: "user-password", + form: "validFormId", + viewable: false, + }); + pageDetails.fields = [field, passwordField]; + + expect( + inlineMenuFieldQualificationService.isFieldForLoginForm(field, pageDetails), + ).toBe(true); + }); + }); + }); + }); + }); +}); diff --git a/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts new file mode 100644 index 0000000000..582f8889da --- /dev/null +++ b/apps/browser/src/autofill/services/inline-menu-field-qualification.service.ts @@ -0,0 +1,438 @@ +import AutofillField from "../models/autofill-field"; +import AutofillPageDetails from "../models/autofill-page-details"; +import { sendExtensionMessage } from "../utils"; + +import { InlineMenuFieldQualificationsService as InlineMenuFieldQualificationsServiceInterface } from "./abstractions/inline-menu-field-qualifications.service"; +import { AutoFillConstants } from "./autofill-constants"; + +export class InlineMenuFieldQualificationService + implements InlineMenuFieldQualificationsServiceInterface +{ + private searchFieldNamesSet = new Set(AutoFillConstants.SearchFieldNames); + private excludedAutofillLoginTypesSet = new Set(AutoFillConstants.ExcludedAutofillLoginTypes); + private usernameFieldTypes = new Set(["text", "email", "number", "tel"]); + private usernameAutocompleteValues = new Set(["username", "email"]); + private fieldIgnoreListString = AutoFillConstants.FieldIgnoreList.join(","); + private passwordFieldExcludeListString = AutoFillConstants.PasswordFieldExcludeList.join(","); + private autofillFieldKeywordsMap: WeakMap = new WeakMap(); + private autocompleteDisabledValues = new Set(["off", "false"]); + private newFieldKeywords = new Set(["new", "change", "neue", "ändern"]); + private inlineMenuFieldQualificationFlagSet = false; + + constructor() { + void sendExtensionMessage("getInlineMenuFieldQualificationFeatureFlag").then( + (getInlineMenuFieldQualificationFlag) => + (this.inlineMenuFieldQualificationFlagSet = !!getInlineMenuFieldQualificationFlag?.result), + ); + } + + /** + * Validates the provided field as a field for a login form. + * + * @param field - The field to validate, should be a username or password field. + * @param pageDetails - The details of the page that the field is on. + */ + isFieldForLoginForm(field: AutofillField, pageDetails: AutofillPageDetails): boolean { + if (!this.inlineMenuFieldQualificationFlagSet) { + return this.isFieldForLoginFormFallback(field); + } + + const isCurrentPasswordField = this.isCurrentPasswordField(field); + if (isCurrentPasswordField) { + return this.isPasswordFieldForLoginForm(field, pageDetails); + } + + const isUsernameField = this.isUsernameField(field); + if (!isUsernameField) { + return false; + } + + return this.isUsernameFieldForLoginForm(field, pageDetails); + } + + /** + * Validates the provided field as a password field for a login form. + * + * @param field - The field to validate + * @param pageDetails - The details of the page that the field is on. + */ + private isPasswordFieldForLoginForm( + field: AutofillField, + pageDetails: AutofillPageDetails, + ): boolean { + // If the provided field is set with an autocomplete value of "current-password", we should assume that + // the page developer intends for this field to be interpreted as a password field for a login form. + if (field.autoCompleteType === "current-password") { + return true; + } + + const usernameFieldsInPageDetails = pageDetails.fields.filter(this.isUsernameField); + const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isCurrentPasswordField); + + // If a single username and a single password field exists on the page, we + // should assume that this field is part of a login form. + if (usernameFieldsInPageDetails.length === 1 && passwordFieldsInPageDetails.length === 1) { + return true; + } + + // If the field is not structured within a form, we need to identify if the field is present on + // a page with multiple password fields. If that isn't the case, we can assume this is a login form field. + const parentForm = pageDetails.forms[field.form]; + if (!parentForm) { + // If no parent form is found, and multiple password fields are present, we should assume that + // the passed field belongs to a user account creation form. + if (passwordFieldsInPageDetails.length > 1) { + return false; + } + + // If multiple username fields exist on the page, we should assume that + // the provided field is part of an account creation form. + const visibleUsernameFields = usernameFieldsInPageDetails.filter((f) => f.viewable); + if (visibleUsernameFields.length > 1) { + return false; + } + + // If a single username field or less is present on the page, then we can assume that the + // provided field is for a login form. This will only be the case if the field does not + // explicitly have its autocomplete attribute set to "off" or "false". + return !this.autocompleteDisabledValues.has(field.autoCompleteType); + } + + // If the field has a form parent and there are multiple visible password fields + // in the form, this is not a login form field + const visiblePasswordFieldsInPageDetails = passwordFieldsInPageDetails.filter( + (f) => f.form === field.form && f.viewable, + ); + if (visiblePasswordFieldsInPageDetails.length > 1) { + return false; + } + + // If the form has any visible username fields, we should treat the field as part of a login form + const visibleUsernameFields = usernameFieldsInPageDetails.filter( + (f) => f.form === field.form && f.viewable, + ); + if (visibleUsernameFields.length > 0) { + return true; + } + + // If the field has a form parent and no username field exists and the field has an + // autocomplete attribute set to "off" or "false", this is not a password field + return !this.autocompleteDisabledValues.has(field.autoCompleteType); + } + + /** + * Validates the provided field as a username field for a login form. + * + * @param field - The field to validate + * @param pageDetails - The details of the page that the field is on. + */ + private isUsernameFieldForLoginForm( + field: AutofillField, + pageDetails: AutofillPageDetails, + ): boolean { + // If the provided field is set with an autocomplete of "username", we should assume that + // the page developer intends for this field to be interpreted as a username field. + if (this.usernameAutocompleteValues.has(field.autoCompleteType)) { + const newPasswordFieldsInPageDetails = pageDetails.fields.filter(this.isNewPasswordField); + return newPasswordFieldsInPageDetails.length === 0; + } + + // If any keywords in the field's data indicates that this is a field for a "new" or "changed" + // username, we should assume that this field is not for a login form. + if (this.keywordsFoundInFieldData(field, [...this.newFieldKeywords])) { + return false; + } + + // If the field is not explicitly set as a username field, we need to qualify + // the field based on the other fields that are present on the page. + const parentForm = pageDetails.forms[field.form]; + const passwordFieldsInPageDetails = pageDetails.fields.filter(this.isCurrentPasswordField); + + // If the field is not structured within a form, we need to identify if the field is used in conjunction + // with a password field. If that's the case, then we should assume that it is a form field element. + if (!parentForm) { + // If a formless field is present in a webpage with a single password field, we + // should assume that it is part of a login workflow. + const visiblePasswordFieldsInPageDetails = passwordFieldsInPageDetails.filter( + (passwordField) => passwordField.viewable, + ); + if (visiblePasswordFieldsInPageDetails.length === 1) { + return true; + } + + // If more than a single password field exists on the page, we should assume that the field + // is part of an account creation form. + if (visiblePasswordFieldsInPageDetails.length > 1) { + return false; + } + + // If no visible fields are found on the page, but we have a single password + // field we should assume that the field is part of a login form. + if (passwordFieldsInPageDetails.length === 1) { + return true; + } + + // If the page does not contain any password fields, it might be part of a multistep login form. + // That will only be the case if the field does not explicitly have its autocomplete attribute + // set to "off" or "false". + return !this.autocompleteDisabledValues.has(field.autoCompleteType); + } + + // If the field is structured within a form, but no password fields are present in the form, + // we need to consider whether the field is part of a multistep login form. + if (passwordFieldsInPageDetails.length === 0) { + // If the field's autocomplete is set to a disabled value, we should assume that the field is + // not part of a login form. + if (this.autocompleteDisabledValues.has(field.autoCompleteType)) { + return false; + } + + // If the form that contains the field has more than one visible field, we should assume + // that the field is part of an account creation form. + const fieldsWithinForm = pageDetails.fields.filter( + (pageDetailsField) => pageDetailsField.form === field.form && pageDetailsField.viewable, + ); + return fieldsWithinForm.length === 1; + } + + // If a single password field exists within the page details, and that password field is part of + // the same form as the provided field, we should assume that the field is part of a login form. + const visiblePasswordFieldsInPageDetails = passwordFieldsInPageDetails.filter( + (passwordField) => passwordField.form === field.form && passwordField.viewable, + ); + if (visiblePasswordFieldsInPageDetails.length === 1) { + return true; + } + + // If multiple visible password fields exist within the page details, we need to assume that the + // provided field is part of an account creation form. + if (visiblePasswordFieldsInPageDetails.length > 1) { + return false; + } + + // If no visible password fields are found, this field might be part of a multipart form. + // Check for an invalid autocompleteType to determine if the field is part of a login form. + return !this.autocompleteDisabledValues.has(field.autoCompleteType); + } + + /** + * Validates the provided field as a username field. + * + * @param field - The field to validate + */ + private isUsernameField = (field: AutofillField): boolean => { + if ( + !this.usernameFieldTypes.has(field.type) || + this.isExcludedFieldType(field, this.excludedAutofillLoginTypesSet) + ) { + return false; + } + + return this.keywordsFoundInFieldData(field, AutoFillConstants.UsernameFieldNames); + }; + + /** + * Validates the provided field as a current password field. + * + * @param field - The field to validate + */ + private isCurrentPasswordField = (field: AutofillField): boolean => { + if (field.autoCompleteType === "new-password") { + return false; + } + + return this.isPasswordField(field); + }; + + /** + * Validates the provided field as a new password field. + * + * @param field - The field to validate + */ + private isNewPasswordField = (field: AutofillField): boolean => { + if (field.autoCompleteType === "current-password") { + return false; + } + + return this.isPasswordField(field); + }; + + /** + * Validates the provided field as a password field. + * + * @param field - The field to validate + */ + private isPasswordField = (field: AutofillField): boolean => { + const isInputPasswordType = field.type === "password"; + if ( + (!isInputPasswordType && + this.isExcludedFieldType(field, this.excludedAutofillLoginTypesSet)) || + this.fieldHasDisqualifyingAttributeValue(field) + ) { + return false; + } + + return isInputPasswordType || this.isLikePasswordField(field); + }; + + /** + * Validates the provided field as a field to indicate if the + * field potentially acts as a password field. + * + * @param field - The field to validate + */ + private isLikePasswordField(field: AutofillField): boolean { + if (field.type !== "text") { + return false; + } + + const testedValues = [field.htmlID, field.htmlName, field.placeholder]; + for (let i = 0; i < testedValues.length; i++) { + if (this.valueIsLikePassword(testedValues[i])) { + return true; + } + } + + return false; + } + + /** + * Validates the provided value to indicate if the value is like a password. + * + * @param value - The value to validate + */ + private valueIsLikePassword(value: string): boolean { + if (value == null) { + return false; + } + // Removes all whitespace, _ and - characters + const cleanedValue = value.toLowerCase().replace(/[\s_-]/g, ""); + + if (cleanedValue.indexOf("password") < 0) { + return false; + } + + return !(this.passwordFieldExcludeListString.indexOf(cleanedValue) > -1); + } + + /** + * Validates the provided field to indicate if the field has a + * disqualifying attribute that would impede autofill entirely. + * + * @param field - The field to validate + */ + private fieldHasDisqualifyingAttributeValue(field: AutofillField): boolean { + const checkedAttributeValues = [field.htmlID, field.htmlName, field.placeholder]; + + for (let i = 0; i < checkedAttributeValues.length; i++) { + const checkedAttributeValue = checkedAttributeValues[i]; + const cleanedValue = checkedAttributeValue?.toLowerCase().replace(/[\s_-]/g, ""); + + if (cleanedValue && this.fieldIgnoreListString.indexOf(cleanedValue) > -1) { + return true; + } + } + + return false; + } + + /** + * Validates the provided field to indicate if the field is excluded from autofill. + * + * @param field - The field to validate + * @param excludedTypes - The set of excluded types + */ + private isExcludedFieldType(field: AutofillField, excludedTypes: Set): boolean { + if (excludedTypes.has(field.type)) { + return true; + } + + return this.isSearchField(field); + } + + /** + * Validates the provided field to indicate if the field is a search field. + * + * @param field - The field to validate + */ + private isSearchField(field: AutofillField): boolean { + const matchFieldAttributeValues = [field.type, field.htmlName, field.htmlID, field.placeholder]; + for (let attrIndex = 0; attrIndex < matchFieldAttributeValues.length; attrIndex++) { + if (!matchFieldAttributeValues[attrIndex]) { + continue; + } + + // Separate camel case words and case them to lower case values + const camelCaseSeparatedFieldAttribute = matchFieldAttributeValues[attrIndex] + .replace(/([a-z])([A-Z])/g, "$1 $2") + .toLowerCase(); + // Split the attribute by non-alphabetical characters to get the keywords + const attributeKeywords = camelCaseSeparatedFieldAttribute.split(/[^a-z]/gi); + + for (let keywordIndex = 0; keywordIndex < attributeKeywords.length; keywordIndex++) { + if (this.searchFieldNamesSet.has(attributeKeywords[keywordIndex])) { + return true; + } + } + } + + return false; + } + + /** + * Validates the provided field to indicate if the field has any of the provided keywords. + * + * @param autofillFieldData - The field data to search for keywords + * @param keywords - The keywords to search for + */ + private keywordsFoundInFieldData(autofillFieldData: AutofillField, keywords: string[]) { + const searchedString = this.getAutofillFieldDataKeywords(autofillFieldData); + return keywords.some((keyword) => searchedString.includes(keyword)); + } + + /** + * Retrieves the keywords from the provided autofill field data. + * + * @param autofillFieldData - The field data to search for keywords + */ + private getAutofillFieldDataKeywords(autofillFieldData: AutofillField) { + if (this.autofillFieldKeywordsMap.has(autofillFieldData)) { + return this.autofillFieldKeywordsMap.get(autofillFieldData); + } + + const keywordValues = [ + autofillFieldData.htmlID, + autofillFieldData.htmlName, + autofillFieldData.htmlClass, + autofillFieldData.type, + autofillFieldData.title, + autofillFieldData.placeholder, + autofillFieldData.autoCompleteType, + autofillFieldData["label-data"], + autofillFieldData["label-aria"], + autofillFieldData["label-left"], + autofillFieldData["label-right"], + autofillFieldData["label-tag"], + autofillFieldData["label-top"], + ] + .join(",") + .toLowerCase(); + this.autofillFieldKeywordsMap.set(autofillFieldData, keywordValues); + + return keywordValues; + } + + /** + * This method represents the previous rudimentary approach to qualifying fields for login forms. + * + * @param field - The field to validate + * @deprecated - This method will only be used when the fallback flag is set to true. + */ + private isFieldForLoginFormFallback(field: AutofillField): boolean { + if (field.type === "password") { + return true; + } + + return this.isUsernameField(field); + } +} diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index e5d20cf9f5..873012d1db 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -7,7 +7,10 @@ import { FillableFormFieldElement, FormFieldElement } from "../types"; * @param callback - The callback function to run when the browser is idle. * @param options - The options to pass to the requestIdleCallback function. */ -export function requestIdleCallbackPolyfill(callback: () => void, options?: Record) { +export function requestIdleCallbackPolyfill( + callback: () => void, + options?: Record, +): number | NodeJS.Timeout { if ("requestIdleCallback" in globalThis) { return globalThis.requestIdleCallback(() => callback(), options); } @@ -15,6 +18,19 @@ export function requestIdleCallbackPolyfill(callback: () => void, options?: Reco return globalThis.setTimeout(() => callback(), 1); } +/** + * Polyfills the cancelIdleCallback API with a clearTimeout fallback. + * + * @param id - The ID of the idle callback to cancel. + */ +export function cancelIdleCallbackPolyfill(id: NodeJS.Timeout | number) { + if ("cancelIdleCallback" in globalThis) { + return globalThis.cancelIdleCallback(id as number); + } + + return globalThis.clearTimeout(id); +} + /** * Generates a random string of characters that formatted as a custom element name. */ diff --git a/apps/browser/src/background/runtime.background.ts b/apps/browser/src/background/runtime.background.ts index a1a5de54d2..94e96e2dc8 100644 --- a/apps/browser/src/background/runtime.background.ts +++ b/apps/browser/src/background/runtime.background.ts @@ -69,6 +69,7 @@ export default class RuntimeBackground { const messagesWithResponse = [ "biometricUnlock", "getUseTreeWalkerApiForPageDetailsCollectionFeatureFlag", + "getInlineMenuFieldQualificationFeatureFlag", ]; if (messagesWithResponse.includes(msg.command)) { @@ -186,6 +187,9 @@ export default class RuntimeBackground { FeatureFlag.UseTreeWalkerApiForPageDetailsCollection, ); } + case "getInlineMenuFieldQualificationFeatureFlag": { + return await this.configService.getFeatureFlag(FeatureFlag.InlineMenuFieldQualification); + } } } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index ec93dfcb2a..552712f4d0 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -18,6 +18,7 @@ export enum FeatureFlag { UseTreeWalkerApiForPageDetailsCollection = "use-tree-walker-api-for-page-details-collection", BulkDeviceApproval = "bulk-device-approval", EmailVerification = "email-verification", + InlineMenuFieldQualification = "inline-menu-field-qualification", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -46,6 +47,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.UseTreeWalkerApiForPageDetailsCollection]: FALSE, [FeatureFlag.BulkDeviceApproval]: FALSE, [FeatureFlag.EmailVerification]: FALSE, + [FeatureFlag.InlineMenuFieldQualification]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; From 26186618f5489428c0bcc3a74789236c1f31bd2e Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Mon, 17 Jun 2024 21:38:35 +0100 Subject: [PATCH 16/31] [PM-245] Fixed validation on navigate back on browser send add edit (#9605) * Fixed validation on navigate back on browser send add edit * simplified expression using nullish-resolution --- apps/browser/src/tools/popup/send/send-add-edit.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/browser/src/tools/popup/send/send-add-edit.component.ts b/apps/browser/src/tools/popup/send/send-add-edit.component.ts index c20bf7cb8d..5ff3621e35 100644 --- a/apps/browser/src/tools/popup/send/send-add-edit.component.ts +++ b/apps/browser/src/tools/popup/send/send-add-edit.component.ts @@ -124,7 +124,8 @@ export class SendAddEditComponent extends BaseAddEditComponent { cancel() { // If true, the window was pop'd out on the add-send page. location.back will not work - if ((window as any).previousPopupUrl.startsWith("/add-send")) { + const isPopup = (window as any)?.previousPopupUrl?.startsWith("/add-send") ?? false; + if (!isPopup) { // FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling. // eslint-disable-next-line @typescript-eslint/no-floating-promises this.router.navigate(["tabs/send"]); From 0c6e296dc37c1ee1e9fd0240031619117747087b Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Mon, 17 Jun 2024 17:23:25 -0400 Subject: [PATCH 17/31] add validation to form (#9691) --- apps/web/src/app/auth/recover-two-factor.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/web/src/app/auth/recover-two-factor.component.ts b/apps/web/src/app/auth/recover-two-factor.component.ts index 4996dbe0a5..28296aa89d 100644 --- a/apps/web/src/app/auth/recover-two-factor.component.ts +++ b/apps/web/src/app/auth/recover-two-factor.component.ts @@ -42,6 +42,11 @@ export class RecoverTwoFactorComponent { } submit = async () => { + this.formGroup.markAllAsTouched(); + if (this.formGroup.invalid) { + return; + } + const request = new TwoFactorRecoveryRequest(); request.recoveryCode = this.recoveryCode.replace(/\s/g, "").toLowerCase(); request.email = this.email.trim().toLowerCase(); From 8440759602484aecd477808dde33e50e85ddb4c9 Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Mon, 17 Jun 2024 17:25:58 -0400 Subject: [PATCH 18/31] add back env selector to 2fa (#9701) --- apps/web/src/app/oss-routing.module.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/web/src/app/oss-routing.module.ts b/apps/web/src/app/oss-routing.module.ts index 810cba453b..0c038b76a3 100644 --- a/apps/web/src/app/oss-routing.module.ts +++ b/apps/web/src/app/oss-routing.module.ts @@ -258,11 +258,21 @@ const routes: Routes = [ }, { path: "2fa", - component: TwoFactorComponent, canActivate: [unauthGuardFn()], + children: [ + { + path: "", + component: TwoFactorComponent, + }, + { + path: "", + component: EnvironmentSelectorComponent, + outlet: "environment-selector", + }, + ], data: { pageTitle: "verifyIdentity", - }, + } satisfies DataProperties & AnonLayoutWrapperData, }, { path: "recover-2fa", From 75615902a3c111cf2e7042cef669dbbae62e3526 Mon Sep 17 00:00:00 2001 From: Jake Fink Date: Mon, 17 Jun 2024 17:26:52 -0400 Subject: [PATCH 19/31] fix email 2fa validation (#9702) --- .../settings/two-factor-base.component.ts | 28 +++++++++++++++++++ .../settings/two-factor-email.component.ts | 20 ++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/apps/web/src/app/auth/settings/two-factor-base.component.ts b/apps/web/src/app/auth/settings/two-factor-base.component.ts index c349b80aa2..ac8906641d 100644 --- a/apps/web/src/app/auth/settings/two-factor-base.component.ts +++ b/apps/web/src/app/auth/settings/two-factor-base.component.ts @@ -41,6 +41,7 @@ export abstract class TwoFactorBaseComponent { this.authed = true; } + /** @deprecated used for formPromise flows.*/ protected async enable(enableFunction: () => Promise) { try { await enableFunction(); @@ -50,6 +51,10 @@ export abstract class TwoFactorBaseComponent { } } + /** + * @deprecated used for formPromise flows. + * TODO: Remove this method when formPromises are removed from all flows. + * */ protected async disable(promise: Promise) { const confirmed = await this.dialogService.openSimpleDialog({ title: { key: "disable" }, @@ -78,6 +83,29 @@ export abstract class TwoFactorBaseComponent { } } + protected async disableMethod() { + const confirmed = await this.dialogService.openSimpleDialog({ + title: { key: "disable" }, + content: { key: "twoStepDisableDesc" }, + type: "warning", + }); + + if (!confirmed) { + return; + } + + const request = await this.buildRequestModel(TwoFactorProviderRequest); + request.type = this.type; + if (this.organizationId != null) { + await this.apiService.putTwoFactorOrganizationDisable(this.organizationId, request); + } else { + await this.apiService.putTwoFactorDisable(request); + } + this.enabled = false; + this.platformUtilsService.showToast("success", null, this.i18nService.t("twoStepDisabled")); + this.onUpdated.emit(false); + } + protected async buildRequestModel( requestClass: new () => T, ) { diff --git a/apps/web/src/app/auth/settings/two-factor-email.component.ts b/apps/web/src/app/auth/settings/two-factor-email.component.ts index b0b7c0a64f..20ee284be0 100644 --- a/apps/web/src/app/auth/settings/two-factor-email.component.ts +++ b/apps/web/src/app/auth/settings/two-factor-email.component.ts @@ -27,7 +27,6 @@ export class TwoFactorEmailComponent extends TwoFactorBaseComponent { @Output() onChangeStatus: EventEmitter = new EventEmitter(); type = TwoFactorProviderType.Email; sentEmail: string; - formPromise: Promise; emailPromise: Promise; override componentName = "app-two-factor-email"; formGroup = this.formBuilder.group({ @@ -79,21 +78,22 @@ export class TwoFactorEmailComponent extends TwoFactorBaseComponent { } submit = async () => { - this.formGroup.markAllAsTouched(); - if (this.formGroup.invalid) { - return; - } if (this.enabled) { await this.disableEmail(); this.onChangeStatus.emit(false); } else { + this.formGroup.markAllAsTouched(); + if (this.formGroup.invalid) { + return; + } + await this.enable(); this.onChangeStatus.emit(true); } }; private disableEmail() { - return super.disable(this.formPromise); + return super.disableMethod(); } sendEmail = async () => { @@ -109,11 +109,9 @@ export class TwoFactorEmailComponent extends TwoFactorBaseComponent { request.email = this.email; request.token = this.token; - return super.enable(async () => { - this.formPromise = this.apiService.putTwoFactorEmail(request); - const response = await this.formPromise; - await this.processResponse(response); - }); + const response = await this.apiService.putTwoFactorEmail(request); + await this.processResponse(response); + this.onUpdated.emit(true); } onClose = () => { From 2a0e21b4bb63a8c2f18d3ec92d7e6afa161182d3 Mon Sep 17 00:00:00 2001 From: rr-bw <102181210+rr-bw@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:56:24 -0700 Subject: [PATCH 20/31] [PM-5085] Create InputPasswordComponent (#9630) * setup for InputPasswordComponent and basic story * add all input fields * add translated error messages * update validation * add password-callout * update hint text * use PolicyService in component * setup SetPasswordComponent * remove div * add default button text * add mocks for InputPassword storybook * simplify ngOnInit * change param and use PolicyApiService * check for breaches and validate against policy * user toastService * use useValue for mocks * hash before emitting * validation cleanup and use PreloadedEnglishI18nModule * add ngOnDestroy * create validateFormInputsDoNotMatch fn * update validateFormInputsComparison and add deprecation jsdocs * rename validator fn * fix bugs in validation fn * cleanup and re-introduce services/logic * toggle password inputs together * update hint help text * remove SetPassword test * remove master key creation / hashing * add translations to browser/desktop * mock basic password-strength functionality * add check for controls * hash before emitting * type the EventEmitter * use DEFAULT_KDF_CONFIG * emit master key * clarify comment * update password mininum help text to match org policy requirement --- apps/browser/src/_locales/en/messages.json | 13 ++ apps/desktop/src/locales/en/messages.json | 13 ++ apps/web/src/locales/en/messages.json | 13 ++ .../inputs-field-match.validator.ts | 116 ++++++++++- libs/auth/src/angular/index.ts | 1 + .../input-password.component.html | 73 +++++++ .../input-password.component.ts | 192 ++++++++++++++++++ .../input-password/input-password.stories.ts | 116 +++++++++++ 8 files changed, 534 insertions(+), 3 deletions(-) create mode 100644 libs/auth/src/angular/input-password/input-password.component.html create mode 100644 libs/auth/src/angular/input-password/input-password.component.ts create mode 100644 libs/auth/src/angular/input-password/input-password.stories.ts diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 79ea4d4856..4d786ddcbb 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -49,6 +49,19 @@ "masterPassHintDesc": { "message": "A master password hint can help you remember your password if you forget it." }, + "masterPassHintText": { + "message": "If you forget your password, the password hint can be sent to your email. $CURRENT$/$MAXIMUM$ character maximum.", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "maximum": { + "content": "$2", + "example": "50" + } + } + }, "reTypeMasterPass": { "message": "Re-type master password" }, diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 73e1bc56e6..d0589116fb 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -526,6 +526,19 @@ "masterPassHint": { "message": "Master password hint (optional)" }, + "masterPassHintText": { + "message": "If you forget your password, the password hint can be sent to your email. $CURRENT$/$MAXIMUM$ character maximum.", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "maximum": { + "content": "$2", + "example": "50" + } + } + }, "settings": { "message": "Settings" }, diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index c248b04dc0..87c66f9b73 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -767,6 +767,19 @@ "masterPassHintLabel": { "message": "Master password hint" }, + "masterPassHintText": { + "message": "If you forget your password, the password hint can be sent to your email. $CURRENT$/$MAXIMUM$ character maximum.", + "placeholders": { + "current": { + "content": "$1", + "example": "0" + }, + "maximum": { + "content": "$2", + "example": "50" + } + } + }, "settings": { "message": "Settings" }, diff --git a/libs/angular/src/auth/validators/inputs-field-match.validator.ts b/libs/angular/src/auth/validators/inputs-field-match.validator.ts index 9c91007d0c..5f3acd73bc 100644 --- a/libs/angular/src/auth/validators/inputs-field-match.validator.ts +++ b/libs/angular/src/auth/validators/inputs-field-match.validator.ts @@ -1,9 +1,13 @@ -import { AbstractControl, UntypedFormGroup, ValidatorFn } from "@angular/forms"; +import { AbstractControl, UntypedFormGroup, ValidationErrors, ValidatorFn } from "@angular/forms"; import { FormGroupControls } from "../../platform/abstractions/form-validation-errors.service"; export class InputsFieldMatch { - //check to ensure two fields do not have the same value + /** + * Check to ensure two fields do not have the same value + * + * @deprecated Use compareInputs() instead + */ static validateInputsDoesntMatch(matchTo: string, errorMessage: string): ValidatorFn { return (control: AbstractControl) => { if (control.parent && control.parent.controls) { @@ -37,7 +41,18 @@ export class InputsFieldMatch { }; } - //checks the formGroup if two fields have the same value and validation is controlled from either field + /** + * Checks the formGroup if two fields have the same value and validation is controlled from either field + * + * @deprecated + * Use compareInputs() instead. + * + * For more info on deprecation + * - Do not use untyped `options` object in formBuilder.group() {@link https://angular.dev/api/forms/UntypedFormBuilder} + * - Use formBuilder.group() overload with AbstractControlOptions type instead {@link https://angular.dev/api/forms/AbstractControlOptions} + * + * Remove this method after deprecated instances are replaced + */ static validateFormInputsMatch(field: string, fieldMatchTo: string, errorMessage: string) { return (formGroup: UntypedFormGroup) => { const fieldCtrl = formGroup.controls[field]; @@ -54,4 +69,99 @@ export class InputsFieldMatch { } }; } + + /** + * Checks whether two form controls do or do not have the same input value (except for empty string values). + * + * - Validation is controlled from either form control. + * - The error message is displayed under controlB by default, but can be set to controlA. + * + * @param validationGoal Whether you want to verify that the form control input values match or do not match + * @param controlNameA The name of the first form control to compare. + * @param controlNameB The name of the second form control to compare. + * @param errorMessage The error message to display if there is an error. This will probably + * be an i18n translated string. + * @param showErrorOn The control under which you want to display the error (default is controlB). + */ + static compareInputs( + validationGoal: "match" | "doNotMatch", + controlNameA: string, + controlNameB: string, + errorMessage: string, + showErrorOn: "controlA" | "controlB" = "controlB", + ): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const controlA = control.get(controlNameA); + const controlB = control.get(controlNameB); + + if (!controlA || !controlB) { + return null; + } + + const controlThatShowsError = showErrorOn === "controlA" ? controlA : controlB; + + // Don't compare empty strings + if (controlA.value === "" && controlB.value === "") { + return pass(); + } + + const controlValuesMatch = controlA.value === controlB.value; + + if (validationGoal === "match") { + if (controlValuesMatch) { + return pass(); + } else { + return fail(); + } + } + + if (validationGoal === "doNotMatch") { + if (!controlValuesMatch) { + return pass(); + } else { + return fail(); + } + } + + return null; // default return + + function fail() { + controlThatShowsError.setErrors({ + // Preserve any pre-existing errors + ...controlThatShowsError.errors, + // Add new inputMatchError + inputMatchError: { + message: errorMessage, + }, + }); + + return { + inputMatchError: { + message: errorMessage, + }, + }; + } + + function pass(): null { + // Get the current errors object + const errorsObj = controlThatShowsError?.errors; + + if (errorsObj != null) { + // Remove any inputMatchError if it exists, since that is the sole error we are targeting with this validator + if (errorsObj?.inputMatchError) { + delete errorsObj.inputMatchError; + } + + // Check if the errorsObj is now empty + const isEmptyObj = Object.keys(errorsObj).length === 0; + + // If the errorsObj is empty, set errors to null, otherwise set the errors to an object of pre-existing errors (other than inputMatchError) + controlThatShowsError.setErrors(isEmptyObj ? null : errorsObj); + } + + // Return null for this validator + return null; + } + }; + } } diff --git a/libs/auth/src/angular/index.ts b/libs/auth/src/angular/index.ts index 9c660413cd..6cb08db6f7 100644 --- a/libs/auth/src/angular/index.ts +++ b/libs/auth/src/angular/index.ts @@ -8,6 +8,7 @@ export * from "./icons"; export * from "./anon-layout/anon-layout.component"; export * from "./anon-layout/anon-layout-wrapper.component"; export * from "./fingerprint-dialog/fingerprint-dialog.component"; +export * from "./input-password/input-password.component"; export * from "./password-callout/password-callout.component"; // user verification diff --git a/libs/auth/src/angular/input-password/input-password.component.html b/libs/auth/src/angular/input-password/input-password.component.html new file mode 100644 index 0000000000..e6c36914cf --- /dev/null +++ b/libs/auth/src/angular/input-password/input-password.component.html @@ -0,0 +1,73 @@ +
+ + +
+ + {{ "masterPassword" | i18n }} + + + + {{ "important" | i18n }} + {{ "masterPassImportant" | i18n }} + {{ minPasswordMsg }}. + + + + +
+ + + {{ "confirmMasterPassword" | i18n }} + + + + + + {{ "masterPassHintLabel" | i18n }} + + + {{ "masterPassHintText" | i18n: formGroup.value.hint.length : maxHintLength.toString() }} + + + + + + {{ "checkForBreaches" | i18n }} + + + + + +
diff --git a/libs/auth/src/angular/input-password/input-password.component.ts b/libs/auth/src/angular/input-password/input-password.component.ts new file mode 100644 index 0000000000..cc91e2a255 --- /dev/null +++ b/libs/auth/src/angular/input-password/input-password.component.ts @@ -0,0 +1,192 @@ +import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { ReactiveFormsModule, FormBuilder, Validators } from "@angular/forms"; + +import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { AuditService } from "@bitwarden/common/abstractions/audit.service"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +import { PBKDF2KdfConfig } from "@bitwarden/common/auth/models/domain/kdf-config"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; +import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/platform/enums"; +import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { MasterKey } from "@bitwarden/common/types/key"; +import { + AsyncActionsModule, + ButtonModule, + CheckboxModule, + DialogService, + FormFieldModule, + IconButtonModule, + InputModule, + ToastService, +} from "@bitwarden/components"; + +import { InputsFieldMatch } from "../../../../angular/src/auth/validators/inputs-field-match.validator"; +import { SharedModule } from "../../../../components/src/shared"; +import { PasswordCalloutComponent } from "../password-callout/password-callout.component"; + +export interface PasswordInputResult { + masterKey: MasterKey; + masterKeyHash: string; + kdfConfig: PBKDF2KdfConfig; + hint: string; +} + +@Component({ + standalone: true, + selector: "auth-input-password", + templateUrl: "./input-password.component.html", + imports: [ + AsyncActionsModule, + ButtonModule, + CheckboxModule, + FormFieldModule, + IconButtonModule, + InputModule, + ReactiveFormsModule, + SharedModule, + PasswordCalloutComponent, + JslibModule, + ], +}) +export class InputPasswordComponent implements OnInit { + @Output() onPasswordFormSubmit = new EventEmitter(); + + @Input({ required: true }) email: string; + @Input() protected buttonText: string; + @Input() private orgId: string; + + private minHintLength = 0; + protected maxHintLength = 50; + + protected minPasswordLength = Utils.minimumPasswordLength; + protected minPasswordMsg = ""; + protected masterPasswordPolicy: MasterPasswordPolicyOptions; + protected passwordStrengthResult: any; + protected showErrorSummary = false; + protected showPassword = false; + + protected formGroup = this.formBuilder.group( + { + password: ["", [Validators.required, Validators.minLength(this.minPasswordLength)]], + confirmedPassword: ["", Validators.required], + hint: [ + "", // must be string (not null) because we check length in validation + [Validators.minLength(this.minHintLength), Validators.maxLength(this.maxHintLength)], + ], + checkForBreaches: true, + }, + { + validators: [ + InputsFieldMatch.compareInputs( + "match", + "password", + "confirmedPassword", + this.i18nService.t("masterPassDoesntMatch"), + ), + InputsFieldMatch.compareInputs( + "doNotMatch", + "password", + "hint", + this.i18nService.t("hintEqualsPassword"), + ), + ], + }, + ); + + constructor( + private auditService: AuditService, + private cryptoService: CryptoService, + private dialogService: DialogService, + private formBuilder: FormBuilder, + private i18nService: I18nService, + private policyService: PolicyService, + private toastService: ToastService, + private policyApiService: PolicyApiServiceAbstraction, + ) {} + + async ngOnInit() { + this.masterPasswordPolicy = await this.policyApiService.getMasterPasswordPolicyOptsForOrgUser( + this.orgId, + ); + + if (this.masterPasswordPolicy != null && this.masterPasswordPolicy.minLength > 0) { + this.minPasswordMsg = this.i18nService.t( + "characterMinimum", + this.masterPasswordPolicy.minLength, + ); + } else { + this.minPasswordMsg = this.i18nService.t("characterMinimum", this.minPasswordLength); + } + } + + getPasswordStrengthResult(result: any) { + this.passwordStrengthResult = result; + } + + protected submit = async () => { + this.formGroup.markAllAsTouched(); + + if (this.formGroup.invalid) { + this.showErrorSummary = true; + return; + } + + const password = this.formGroup.controls.password.value; + + // Check if password is breached (if breached, user chooses to accept and continue or not) + const passwordIsBreached = + this.formGroup.controls.checkForBreaches.value && + (await this.auditService.passwordLeaked(password)); + + if (passwordIsBreached) { + const userAcceptedDialog = await this.dialogService.openSimpleDialog({ + title: { key: "exposedMasterPassword" }, + content: { key: "exposedMasterPasswordDesc" }, + type: "warning", + }); + + if (!userAcceptedDialog) { + return; + } + } + + // Check if password meets org policy requirements + if ( + this.masterPasswordPolicy != null && + !this.policyService.evaluateMasterPassword( + this.passwordStrengthResult.score, + password, + this.masterPasswordPolicy, + ) + ) { + this.toastService.showToast({ + variant: "error", + title: this.i18nService.t("errorOccurred"), + message: this.i18nService.t("masterPasswordPolicyRequirementsNotMet"), + }); + + return; + } + + // Create and hash new master key + const kdfConfig = DEFAULT_KDF_CONFIG; + + const masterKey = await this.cryptoService.makeMasterKey( + password, + this.email.trim().toLowerCase(), + kdfConfig, + ); + + const masterKeyHash = await this.cryptoService.hashMasterKey(password, masterKey); + + this.onPasswordFormSubmit.emit({ + masterKey, + masterKeyHash, + kdfConfig, + hint: this.formGroup.controls.hint.value, + }); + }; +} diff --git a/libs/auth/src/angular/input-password/input-password.stories.ts b/libs/auth/src/angular/input-password/input-password.stories.ts new file mode 100644 index 0000000000..6144e39e64 --- /dev/null +++ b/libs/auth/src/angular/input-password/input-password.stories.ts @@ -0,0 +1,116 @@ +import { importProvidersFrom } from "@angular/core"; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; +import { action } from "@storybook/addon-actions"; +import { Meta, StoryObj, applicationConfig } from "@storybook/angular"; +import { of } from "rxjs"; +import { ZXCVBNResult } from "zxcvbn"; + +import { AuditService } from "@bitwarden/common/abstractions/audit.service"; +import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction"; +import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; +import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options"; +import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service"; +import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength"; +import { DialogService, ToastService } from "@bitwarden/components"; + +import { PreloadedEnglishI18nModule } from "../../../../../apps/web/src/app/core/tests"; + +import { InputPasswordComponent } from "./input-password.component"; + +const mockMasterPasswordPolicyOptions = { + minComplexity: 4, + minLength: 14, + requireUpper: true, + requireLower: true, + requireNumbers: true, + requireSpecial: true, +} as MasterPasswordPolicyOptions; + +export default { + title: "Auth/Input Password", + component: InputPasswordComponent, + decorators: [ + applicationConfig({ + providers: [ + importProvidersFrom(PreloadedEnglishI18nModule), + importProvidersFrom(BrowserAnimationsModule), + { + provide: AuditService, + useValue: { + passwordLeaked: () => Promise.resolve(1), + } as Partial, + }, + { + provide: CryptoService, + useValue: { + makeMasterKey: () => Promise.resolve("example-master-key"), + hashMasterKey: () => Promise.resolve("example-master-key-hash"), + }, + }, + { + provide: DialogService, + useValue: { + openSimpleDialog: () => Promise.resolve(true), + } as Partial, + }, + { + provide: PolicyApiServiceAbstraction, + useValue: { + getMasterPasswordPolicyOptsForOrgUser: () => mockMasterPasswordPolicyOptions, + } as Partial, + }, + { + provide: PolicyService, + useValue: { + masterPasswordPolicyOptions$: () => of(mockMasterPasswordPolicyOptions), + evaluateMasterPassword: (score) => { + if (score < 4) { + return false; + } + return true; + }, + } as Partial, + }, + { + provide: PasswordStrengthServiceAbstraction, + useValue: { + getPasswordStrength: (password) => { + let score = 0; + + if (password.length === 0) { + score = null; + } else if (password.length <= 4) { + score = 1; + } else if (password.length <= 8) { + score = 2; + } else if (password.length <= 12) { + score = 3; + } else { + score = 4; + } + + return { score } as ZXCVBNResult; + }, + } as Partial, + }, + { + provide: ToastService, + useValue: { + showToast: action("ToastService.showToast"), + } as Partial, + }, + ], + }), + ], +} as Meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args) => ({ + props: args, + template: ` + + `, + }), +}; From 6091958d222f66b82025f38f4026784d6ff00bd2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:56:01 +0000 Subject: [PATCH 21/31] [PM-8955][deps] Tools: Update electron to v30.1.1 (#9683) * [deps] Tools: Update electron to v30.1.1 * Bump version in electron-builder --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Daniel James Smith --- apps/desktop/electron-builder.json | 2 +- package-lock.json | 18 +++++------------- package.json | 2 +- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/apps/desktop/electron-builder.json b/apps/desktop/electron-builder.json index fd92d0007f..462a33a1b8 100644 --- a/apps/desktop/electron-builder.json +++ b/apps/desktop/electron-builder.json @@ -24,7 +24,7 @@ "**/node_modules/argon2/package.json", "**/node_modules/argon2/lib/binding/napi-v3/argon2.node" ], - "electronVersion": "30.1.0", + "electronVersion": "30.1.1", "generateUpdatesFilesForAllChannels": true, "publish": { "provider": "generic", diff --git a/package-lock.json b/package-lock.json index 28ceeeb83e..9bed226549 100644 --- a/package-lock.json +++ b/package-lock.json @@ -132,7 +132,7 @@ "copy-webpack-plugin": "12.0.2", "cross-env": "7.0.3", "css-loader": "6.10.0", - "electron": "30.1.0", + "electron": "30.1.1", "electron-builder": "24.13.3", "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", @@ -18563,11 +18563,12 @@ } }, "node_modules/electron": { - "version": "30.1.0", - "resolved": "https://registry.npmjs.org/electron/-/electron-30.1.0.tgz", - "integrity": "sha512-9O8m7kinjwMH5Df0hpXbwUaqI6pk3aJm1sKQUkQGCF7NDbNkGhu2BXgqaicPU6oe26zQPc5vtwWnHmiKlh1hYA==", + "version": "30.1.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-30.1.1.tgz", + "integrity": "sha512-D9blhgVoNx82Nsbms+ufX/Az/yJAulkrHZh0CM7hL79TvG35mqJFMNjh8GlJSRK42rVGNGyH3NfhS0VRaGCPcw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^20.9.0", @@ -18774,15 +18775,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/electron/node_modules/@types/node": { - "version": "20.12.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.13.tgz", - "integrity": "sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/emitter-component": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/emitter-component/-/emitter-component-1.1.2.tgz", diff --git a/package.json b/package.json index 0ceaa5fa30..d1bf3a3da5 100644 --- a/package.json +++ b/package.json @@ -93,7 +93,7 @@ "copy-webpack-plugin": "12.0.2", "cross-env": "7.0.3", "css-loader": "6.10.0", - "electron": "30.1.0", + "electron": "30.1.1", "electron-builder": "24.13.3", "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", From 93f3d5517d2345644fe2880f276b8e8b9db0b1f9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 18 Jun 2024 12:58:09 +0200 Subject: [PATCH 22/31] [deps] Tools: Update electron-updater to v6.2.1 (#9684) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package-lock.json | 27 +++++++++------------------ package.json | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9bed226549..362abf0412 100644 --- a/package-lock.json +++ b/package-lock.json @@ -137,7 +137,7 @@ "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", "electron-store": "8.2.0", - "electron-updater": "6.1.8", + "electron-updater": "6.2.1", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", @@ -18715,12 +18715,13 @@ "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==" }, "node_modules/electron-updater": { - "version": "6.1.8", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.8.tgz", - "integrity": "sha512-hhOTfaFAd6wRHAfUaBhnAOYc+ymSGCWJLtFkw4xJqOvtpHmIdNHnXDV9m1MHC+A6q08Abx4Ykgyz/R5DGKNAMQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.2.1.tgz", + "integrity": "sha512-83eKIPW14qwZqUUM6wdsIRwVKZyjmHxQ4/8G+1C6iS5PdDt7b1umYQyj1/qPpH510GmHEQe4q0kCPe3qmb3a0Q==", "dev": true, + "license": "MIT", "dependencies": { - "builder-util-runtime": "9.2.3", + "builder-util-runtime": "9.2.4", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", @@ -18734,26 +18735,15 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/electron-updater/node_modules/builder-util-runtime": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz", - "integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==", "dev": true, - "dependencies": { - "debug": "^4.3.4", - "sax": "^1.2.4" - }, - "engines": { - "node": ">=12.0.0" - } + "license": "Python-2.0" }, "node_modules/electron-updater/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -18768,6 +18758,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, diff --git a/package.json b/package.json index d1bf3a3da5..e1d3362a00 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", "electron-store": "8.2.0", - "electron-updater": "6.1.8", + "electron-updater": "6.2.1", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", From 5bfedb81a799a2b73e31fe4a2e44c141ac033ccb Mon Sep 17 00:00:00 2001 From: Daniel James Smith <2670567+djsmith85@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:42:14 +0200 Subject: [PATCH 23/31] Revert "[deps] Tools: Update electron-updater to v6.2.1 (#9684)" (#9712) This reverts commit 93f3d5517d2345644fe2880f276b8e8b9db0b1f9. --- package-lock.json | 27 ++++++++++++++++++--------- package.json | 2 +- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 362abf0412..9bed226549 100644 --- a/package-lock.json +++ b/package-lock.json @@ -137,7 +137,7 @@ "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", "electron-store": "8.2.0", - "electron-updater": "6.2.1", + "electron-updater": "6.1.8", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", @@ -18715,13 +18715,12 @@ "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==" }, "node_modules/electron-updater": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.2.1.tgz", - "integrity": "sha512-83eKIPW14qwZqUUM6wdsIRwVKZyjmHxQ4/8G+1C6iS5PdDt7b1umYQyj1/qPpH510GmHEQe4q0kCPe3qmb3a0Q==", + "version": "6.1.8", + "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.8.tgz", + "integrity": "sha512-hhOTfaFAd6wRHAfUaBhnAOYc+ymSGCWJLtFkw4xJqOvtpHmIdNHnXDV9m1MHC+A6q08Abx4Ykgyz/R5DGKNAMQ==", "dev": true, - "license": "MIT", "dependencies": { - "builder-util-runtime": "9.2.4", + "builder-util-runtime": "9.2.3", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0", "lazy-val": "^1.0.5", @@ -18735,15 +18734,26 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/electron-updater/node_modules/builder-util-runtime": { + "version": "9.2.3", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.3.tgz", + "integrity": "sha512-FGhkqXdFFZ5dNC4C+yuQB9ak311rpGAw+/ASz8ZdxwODCv1GGMWgLDeofRkdi0F3VCHQEWy/aXcJQozx2nOPiw==", "dev": true, - "license": "Python-2.0" + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } }, "node_modules/electron-updater/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -18758,7 +18768,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, diff --git a/package.json b/package.json index e1d3362a00..d1bf3a3da5 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "electron-log": "5.0.1", "electron-reload": "2.0.0-alpha.1", "electron-store": "8.2.0", - "electron-updater": "6.2.1", + "electron-updater": "6.1.8", "eslint": "8.57.0", "eslint-config-prettier": "9.1.0", "eslint-import-resolver-typescript": "3.6.1", From c219addc1c44453bb78d8f39325d2949606444fc Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:23:02 -0500 Subject: [PATCH 24/31] [PM-2664] Hide Owners column below desktop viewports (#8923) * hide owners row below desktop viewports * hide collection owner on smaller screens --- .../components/vault-items/vault-cipher-row.component.html | 2 +- .../vault-items/vault-collection-row.component.html | 2 +- .../vault/components/vault-items/vault-items.component.html | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html index ae22d89f7f..af2a8443ed 100644 --- a/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html +++ b/apps/web/src/app/vault/components/vault-items/vault-cipher-row.component.html @@ -49,7 +49,7 @@
{{ cipher.subTitle }} - + - + - {{ "name" | i18n }} - {{ "owner" | i18n }} + {{ "name" | i18n }} + + {{ "owner" | i18n }} + {{ "collections" | i18n }} {{ "groups" | i18n }} From 2bec2c560593f57eed1f1d156fc3e8f44d7a1e04 Mon Sep 17 00:00:00 2001 From: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:15:38 -0500 Subject: [PATCH 25/31] fix sync service provider (#9713) --- .../navigation-switcher/navigation-switcher.stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts index 48a45deba8..cd1a77a9ec 100644 --- a/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts +++ b/apps/web/src/app/layouts/product-switcher/navigation-switcher/navigation-switcher.stories.ts @@ -87,7 +87,7 @@ export default { providers: [ { provide: OrganizationService, useClass: MockOrganizationService }, { provide: ProviderService, useClass: MockProviderService }, - { provide: MockSyncService, useClass: MockSyncService }, + { provide: SyncService, useClass: MockSyncService }, ProductSwitcherService, { provide: I18nPipe, From 96f1aa073c6d9c772aa87abd7bb0057b69d95e8f Mon Sep 17 00:00:00 2001 From: Merissa Weinstein Date: Tue, 18 Jun 2024 12:11:10 -0500 Subject: [PATCH 26/31] [PM-8391] turn on enableCipherKeyEncryption flag (#9362) * turn on enableCipherKeyEncryption flag * turn enableCipherKeyEncryption flag on in desktop config --------- Co-authored-by: bnagawiecki <107435978+bnagawiecki@users.noreply.github.com> --- apps/browser/config/base.json | 2 +- apps/browser/config/development.json | 2 +- apps/browser/config/production.json | 2 +- apps/cli/config/development.json | 2 +- apps/cli/config/production.json | 2 +- apps/desktop/config/base.json | 2 +- apps/desktop/config/development.json | 2 +- apps/desktop/config/production.json | 2 +- apps/web/config/base.json | 2 +- apps/web/config/cloud.json | 2 +- apps/web/config/development.json | 2 +- apps/web/config/euprd.json | 2 +- apps/web/config/qa.json | 2 +- apps/web/config/selfhosted.json | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/browser/config/base.json b/apps/browser/config/base.json index 6c428c43d2..b6f24bf9ae 100644 --- a/apps/browser/config/base.json +++ b/apps/browser/config/base.json @@ -2,7 +2,7 @@ "devFlags": {}, "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false, + "enableCipherKeyEncryption": true, "accountSwitching": false } } diff --git a/apps/browser/config/development.json b/apps/browser/config/development.json index e0925ebecc..950c5372d8 100644 --- a/apps/browser/config/development.json +++ b/apps/browser/config/development.json @@ -7,7 +7,7 @@ }, "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false, + "enableCipherKeyEncryption": true, "accountSwitching": true } } diff --git a/apps/browser/config/production.json b/apps/browser/config/production.json index 027003f6c7..64c6cb92a3 100644 --- a/apps/browser/config/production.json +++ b/apps/browser/config/production.json @@ -1,6 +1,6 @@ { "flags": { - "enableCipherKeyEncryption": false, + "enableCipherKeyEncryption": true, "accountSwitching": true } } diff --git a/apps/cli/config/development.json b/apps/cli/config/development.json index f57c3d9bc3..bc06f69d65 100644 --- a/apps/cli/config/development.json +++ b/apps/cli/config/development.json @@ -1,5 +1,5 @@ { "flags": { - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/cli/config/production.json b/apps/cli/config/production.json index f57c3d9bc3..bc06f69d65 100644 --- a/apps/cli/config/production.json +++ b/apps/cli/config/production.json @@ -1,5 +1,5 @@ { "flags": { - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/desktop/config/base.json b/apps/desktop/config/base.json index 1f4f624dc8..2c7b4dcae1 100644 --- a/apps/desktop/config/base.json +++ b/apps/desktop/config/base.json @@ -2,6 +2,6 @@ "devFlags": {}, "flags": { "multithreadDecryption": false, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/desktop/config/development.json b/apps/desktop/config/development.json index 7a8659feff..7f18c63878 100644 --- a/apps/desktop/config/development.json +++ b/apps/desktop/config/development.json @@ -1,6 +1,6 @@ { "devFlags": {}, "flags": { - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/desktop/config/production.json b/apps/desktop/config/production.json index f57c3d9bc3..bc06f69d65 100644 --- a/apps/desktop/config/production.json +++ b/apps/desktop/config/production.json @@ -1,5 +1,5 @@ { "flags": { - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/web/config/base.json b/apps/web/config/base.json index 5dc03a4633..b9102a769d 100644 --- a/apps/web/config/base.json +++ b/apps/web/config/base.json @@ -12,6 +12,6 @@ }, "flags": { "showPasswordless": false, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/web/config/cloud.json b/apps/web/config/cloud.json index 3faa292692..c8ba07e755 100644 --- a/apps/web/config/cloud.json +++ b/apps/web/config/cloud.json @@ -18,6 +18,6 @@ }, "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/web/config/development.json b/apps/web/config/development.json index 44391a7450..3fcd8641b3 100644 --- a/apps/web/config/development.json +++ b/apps/web/config/development.json @@ -21,7 +21,7 @@ ], "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true }, "devFlags": {} } diff --git a/apps/web/config/euprd.json b/apps/web/config/euprd.json index 72f0c1857d..2d554e5704 100644 --- a/apps/web/config/euprd.json +++ b/apps/web/config/euprd.json @@ -12,6 +12,6 @@ }, "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/web/config/qa.json b/apps/web/config/qa.json index ac36b10784..f03d47fe4e 100644 --- a/apps/web/config/qa.json +++ b/apps/web/config/qa.json @@ -28,6 +28,6 @@ ], "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } diff --git a/apps/web/config/selfhosted.json b/apps/web/config/selfhosted.json index 7e916a1116..121f59ba0b 100644 --- a/apps/web/config/selfhosted.json +++ b/apps/web/config/selfhosted.json @@ -8,6 +8,6 @@ }, "flags": { "showPasswordless": true, - "enableCipherKeyEncryption": false + "enableCipherKeyEncryption": true } } From efe4d4a2145a49dd67ce3cf535080748d0db2b2b Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:33:13 -0400 Subject: [PATCH 27/31] Bumped client version(s) (#9716) --- apps/browser/package.json | 2 +- apps/browser/src/manifest.json | 2 +- apps/browser/src/manifest.v3.json | 2 +- package-lock.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/browser/package.json b/apps/browser/package.json index 9cef485e48..b1f8f76f7f 100644 --- a/apps/browser/package.json +++ b/apps/browser/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/browser", - "version": "2024.6.1", + "version": "2024.6.2", "scripts": { "build": "cross-env MANIFEST_VERSION=3 webpack", "build:mv2": "webpack", diff --git a/apps/browser/src/manifest.json b/apps/browser/src/manifest.json index da9c1574ef..dac2b01921 100644 --- a/apps/browser/src/manifest.json +++ b/apps/browser/src/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.6.1", + "version": "2024.6.2", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/apps/browser/src/manifest.v3.json b/apps/browser/src/manifest.v3.json index 8f3ee73e39..562a4b54f8 100644 --- a/apps/browser/src/manifest.v3.json +++ b/apps/browser/src/manifest.v3.json @@ -3,7 +3,7 @@ "minimum_chrome_version": "102.0", "name": "__MSG_extName__", "short_name": "__MSG_appName__", - "version": "2024.6.1", + "version": "2024.6.2", "description": "__MSG_extDesc__", "default_locale": "en", "author": "Bitwarden Inc.", diff --git a/package-lock.json b/package-lock.json index 9bed226549..23f6c9815a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -197,7 +197,7 @@ }, "apps/browser": { "name": "@bitwarden/browser", - "version": "2024.6.1" + "version": "2024.6.2" }, "apps/cli": { "name": "@bitwarden/cli", From 9696b640fd597d9c627ef922a8dd7b461fcac9cf Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Tue, 18 Jun 2024 14:50:28 -0400 Subject: [PATCH 28/31] Bumped client version(s) (#9719) --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index c78b72cf26..b541ea7b5b 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": "2024.6.3", + "version": "2024.6.4", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index 560e812de8..a7fbaf27c3 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.6.3", + "version": "2024.6.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.6.3", + "version": "2024.6.4", "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 d836b89498..463ceb7cfd 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": "2024.6.3", + "version": "2024.6.4", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index 23f6c9815a..352803ce9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -237,7 +237,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.6.3", + "version": "2024.6.4", "hasInstallScript": true, "license": "GPL-3.0" }, From 08cdecf5145fa3e646ebeed6cb82f608ed1edb46 Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Tue, 18 Jun 2024 15:10:10 -0400 Subject: [PATCH 29/31] Bumped client version(s) (#9720) --- apps/web/package.json | 2 +- package-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 82c447c9b4..da1bd9c4da 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2024.6.2", + "version": "2024.6.3", "scripts": { "build:oss": "webpack", "build:bit": "webpack -c ../../bitwarden_license/bit-web/webpack.config.js", diff --git a/package-lock.json b/package-lock.json index 352803ce9f..8a2c2f6019 100644 --- a/package-lock.json +++ b/package-lock.json @@ -251,7 +251,7 @@ }, "apps/web": { "name": "@bitwarden/web-vault", - "version": "2024.6.2" + "version": "2024.6.3" }, "libs/admin-console": { "name": "@bitwarden/admin-console", From 1a37d025564e4d47a119069d0df7b3fe648f7c7b Mon Sep 17 00:00:00 2001 From: aj-rosado <109146700+aj-rosado@users.noreply.github.com> Date: Tue, 18 Jun 2024 22:13:55 +0100 Subject: [PATCH 30/31] [AC-2504] Add new members access report card (#9335) * Added new report card and FeatureFlag for MemberAccessReport * Add new "isEnterpriseOrgGuard" * Add member access icon * Show upgrade organization dialog for enterprise on member access report click * verify member access featureflag on enterprise org guard * add comment with TODO information for follow up task * Improved readability, removed path to wrong component and refactored buildReports to use the productType * added TODO to remove the feature flag on cleanup * changing ProductType to ProductTierType on isEnterpriseOrgGuard --- .../guards/is-enterprise-org.guard.ts | 67 +++++++++++++++++++ .../reporting/reports-home.component.ts | 38 ++++++++--- .../icons/report-member-access.icon.ts | 14 ++++ apps/web/src/app/tools/reports/reports.ts | 8 +++ .../reports/shared/models/report-variant.ts | 1 + apps/web/src/locales/en/messages.json | 12 ++++ libs/common/src/enums/feature-flag.enum.ts | 2 + 7 files changed, 134 insertions(+), 8 deletions(-) create mode 100644 apps/web/src/app/admin-console/organizations/guards/is-enterprise-org.guard.ts create mode 100644 apps/web/src/app/tools/reports/icons/report-member-access.icon.ts diff --git a/apps/web/src/app/admin-console/organizations/guards/is-enterprise-org.guard.ts b/apps/web/src/app/admin-console/organizations/guards/is-enterprise-org.guard.ts new file mode 100644 index 0000000000..8e35c60db9 --- /dev/null +++ b/apps/web/src/app/admin-console/organizations/guards/is-enterprise-org.guard.ts @@ -0,0 +1,67 @@ +import { Injectable } from "@angular/core"; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from "@angular/router"; +import { firstValueFrom } from "rxjs"; + +import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { ProductTierType } from "@bitwarden/common/billing/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; +import { DialogService } from "@bitwarden/components"; + +@Injectable({ + providedIn: "root", +}) +export class IsEnterpriseOrgGuard implements CanActivate { + constructor( + private router: Router, + private organizationService: OrganizationService, + private dialogService: DialogService, + private configService: ConfigService, + ) {} + + async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { + const isMemberAccessReportEnabled = await firstValueFrom( + this.configService.getFeatureFlag$(FeatureFlag.MemberAccessReport), + ); + + // TODO: Remove on "MemberAccessReport" feature flag cleanup + if (!isMemberAccessReportEnabled) { + return this.router.createUrlTree(["/"]); + } + + const org = await this.organizationService.get(route.params.organizationId); + + if (org == null) { + return this.router.createUrlTree(["/"]); + } + + if (org.productTierType != ProductTierType.Enterprise) { + // Users without billing permission can't access billing + if (!org.canEditSubscription) { + await this.dialogService.openSimpleDialog({ + title: { key: "upgradeOrganizationEnterprise" }, + content: { key: "onlyAvailableForEnterpriseOrganization" }, + acceptButtonText: { key: "ok" }, + cancelButtonText: null, + type: "info", + }); + return false; + } else { + const upgradeConfirmed = await this.dialogService.openSimpleDialog({ + title: { key: "upgradeOrganizationEnterprise" }, + content: { key: "onlyAvailableForEnterpriseOrganization" }, + acceptButtonText: { key: "upgradeOrganization" }, + type: "info", + icon: "bwi-arrow-circle-up", + }); + if (upgradeConfirmed) { + await this.router.navigate(["organizations", org.id, "billing", "subscription"], { + queryParams: { upgrade: true }, + }); + } + } + } + + return org.productTierType == ProductTierType.Enterprise; + } +} diff --git a/apps/web/src/app/admin-console/organizations/reporting/reports-home.component.ts b/apps/web/src/app/admin-console/organizations/reporting/reports-home.component.ts index 765637be39..c89ff280dd 100644 --- a/apps/web/src/app/admin-console/organizations/reporting/reports-home.component.ts +++ b/apps/web/src/app/admin-console/organizations/reporting/reports-home.component.ts @@ -1,8 +1,11 @@ import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; -import { filter, map, Observable, startWith, concatMap } from "rxjs"; +import { filter, map, Observable, startWith, concatMap, firstValueFrom } from "rxjs"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +import { ProductTierType } from "@bitwarden/common/billing/enums"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { ReportVariant, reports, ReportType, ReportEntry } from "../../../tools/reports"; @@ -14,13 +17,21 @@ export class ReportsHomeComponent implements OnInit { reports$: Observable; homepage$: Observable; + private isMemberAccessReportEnabled: boolean; + constructor( private route: ActivatedRoute, private organizationService: OrganizationService, private router: Router, + private configService: ConfigService, ) {} - ngOnInit() { + async ngOnInit() { + // TODO: Remove on "MemberAccessReport" feature flag cleanup + this.isMemberAccessReportEnabled = await firstValueFrom( + this.configService.getFeatureFlag$(FeatureFlag.MemberAccessReport), + ); + this.homepage$ = this.router.events.pipe( filter((event) => event instanceof NavigationEnd), map((event) => this.isReportsHomepageRouteUrl((event as NavigationEnd).urlAfterRedirects)), @@ -29,16 +40,15 @@ export class ReportsHomeComponent implements OnInit { this.reports$ = this.route.params.pipe( concatMap((params) => this.organizationService.get$(params.organizationId)), - map((org) => this.buildReports(org.isFreeOrg)), + map((org) => this.buildReports(org.productTierType)), ); } - private buildReports(upgradeRequired: boolean): ReportEntry[] { - const reportRequiresUpgrade = upgradeRequired - ? ReportVariant.RequiresUpgrade - : ReportVariant.Enabled; + private buildReports(productType: ProductTierType): ReportEntry[] { + const reportRequiresUpgrade = + productType == ProductTierType.Free ? ReportVariant.RequiresUpgrade : ReportVariant.Enabled; - return [ + const reportsArray = [ { ...reports[ReportType.ExposedPasswords], variant: reportRequiresUpgrade, @@ -60,6 +70,18 @@ export class ReportsHomeComponent implements OnInit { variant: reportRequiresUpgrade, }, ]; + + if (this.isMemberAccessReportEnabled) { + reportsArray.push({ + ...reports[ReportType.MemberAccessReport], + variant: + productType == ProductTierType.Enterprise + ? ReportVariant.Enabled + : ReportVariant.RequiresEnterprise, + }); + } + + return reportsArray; } private isReportsHomepageRouteUrl(url: string): boolean { diff --git a/apps/web/src/app/tools/reports/icons/report-member-access.icon.ts b/apps/web/src/app/tools/reports/icons/report-member-access.icon.ts new file mode 100644 index 0000000000..825968cd0c --- /dev/null +++ b/apps/web/src/app/tools/reports/icons/report-member-access.icon.ts @@ -0,0 +1,14 @@ +import { svgIcon } from "@bitwarden/components"; + +export const MemberAccess = svgIcon` + + + + + + + + + + +`; diff --git a/apps/web/src/app/tools/reports/reports.ts b/apps/web/src/app/tools/reports/reports.ts index 6f802e5478..500ae23e5c 100644 --- a/apps/web/src/app/tools/reports/reports.ts +++ b/apps/web/src/app/tools/reports/reports.ts @@ -1,6 +1,7 @@ import { ReportBreach } from "./icons/report-breach.icon"; import { ReportExposedPasswords } from "./icons/report-exposed-passwords.icon"; import { ReportInactiveTwoFactor } from "./icons/report-inactive-two-factor.icon"; +import { MemberAccess } from "./icons/report-member-access.icon"; import { ReportReusedPasswords } from "./icons/report-reused-passwords.icon"; import { ReportUnsecuredWebsites } from "./icons/report-unsecured-websites.icon"; import { ReportWeakPasswords } from "./icons/report-weak-passwords.icon"; @@ -13,6 +14,7 @@ export enum ReportType { UnsecuredWebsites = "unsecuredWebsites", Inactive2fa = "inactive2fa", DataBreach = "dataBreach", + MemberAccessReport = "memberAccessReport", } type ReportWithoutVariant = Omit; @@ -54,4 +56,10 @@ export const reports: Record = { route: "breach-report", icon: ReportBreach, }, + [ReportType.MemberAccessReport]: { + title: "memberAccessReport", + description: "memberAccessReportDesc", + route: "member-access-report", + icon: MemberAccess, + }, }; diff --git a/apps/web/src/app/tools/reports/shared/models/report-variant.ts b/apps/web/src/app/tools/reports/shared/models/report-variant.ts index d011d106c6..3beba65f7d 100644 --- a/apps/web/src/app/tools/reports/shared/models/report-variant.ts +++ b/apps/web/src/app/tools/reports/shared/models/report-variant.ts @@ -2,4 +2,5 @@ export enum ReportVariant { Enabled = "Enabled", RequiresPremium = "RequiresPremium", RequiresUpgrade = "RequiresUpgrade", + RequiresEnterprise = "RequiresEnterprise", } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index 87c66f9b73..bd8345ce81 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -8384,6 +8384,12 @@ "message": "This email address will receive all invoices pertaining to this provider", "description": "A hint that shows up on the Provider setup page to inform the admin the billing email will receive the provider's invoices." }, + "upgradeOrganizationEnterprise": { + "message": "Identify security risks by auditing member access" + }, + "onlyAvailableForEnterpriseOrganization": { + "message": "Quickly view member access across the organization by upgrading to an Enterprise plan." + }, "date": { "message": "Date" }, @@ -8393,5 +8399,11 @@ "invoiceNumberHeader": { "message": "Invoice number", "description": "A table header for an invoice's number" + }, + "memberAccessReport": { + "message": "Member access" + }, + "memberAccessReportDesc": { + "message": "Ensure members have access to the right credentials and their accounts are secure. Use this report to obtain a CSV of member access and account configurations." } } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 552712f4d0..5a06dbae20 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -19,6 +19,7 @@ export enum FeatureFlag { BulkDeviceApproval = "bulk-device-approval", EmailVerification = "email-verification", InlineMenuFieldQualification = "inline-menu-field-qualification", + MemberAccessReport = "ac-2059-member-access-report", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -48,6 +49,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.BulkDeviceApproval]: FALSE, [FeatureFlag.EmailVerification]: FALSE, [FeatureFlag.InlineMenuFieldQualification]: FALSE, + [FeatureFlag.MemberAccessReport]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; From 4a25db4ec088fdf74b1c182aa530889510afd28f Mon Sep 17 00:00:00 2001 From: Bitwarden DevOps <106330231+bitwarden-devops-bot@users.noreply.github.com> Date: Tue, 18 Jun 2024 19:30:19 -0400 Subject: [PATCH 31/31] Bumped client version(s) (#9725) --- apps/desktop/package.json | 2 +- apps/desktop/src/package-lock.json | 4 ++-- apps/desktop/src/package.json | 2 +- package-lock.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index b541ea7b5b..749726b1d6 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": "2024.6.4", + "version": "2024.6.5", "keywords": [ "bitwarden", "password", diff --git a/apps/desktop/src/package-lock.json b/apps/desktop/src/package-lock.json index a7fbaf27c3..a6858632b9 100644 --- a/apps/desktop/src/package-lock.json +++ b/apps/desktop/src/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/desktop", - "version": "2024.6.4", + "version": "2024.6.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bitwarden/desktop", - "version": "2024.6.4", + "version": "2024.6.5", "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 463ceb7cfd..e556b04afd 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": "2024.6.4", + "version": "2024.6.5", "author": "Bitwarden Inc. (https://bitwarden.com)", "homepage": "https://bitwarden.com", "license": "GPL-3.0", diff --git a/package-lock.json b/package-lock.json index 8a2c2f6019..a9b9ec054a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -237,7 +237,7 @@ }, "apps/desktop": { "name": "@bitwarden/desktop", - "version": "2024.6.4", + "version": "2024.6.5", "hasInstallScript": true, "license": "GPL-3.0" },