Merge remote-tracking branch 'origin/main' into auth/pm-7392/token-service-add-secure-storage-fallback + merge conflict resolutions

This commit is contained in:
Jared Snider 2024-05-13 18:29:05 -04:00
commit 48fabc1601
No known key found for this signature in database
GPG Key ID: A149DDD612516286
233 changed files with 4798 additions and 1266 deletions

View File

@ -2,10 +2,10 @@
"name": "@bitwarden/browser",
"version": "2024.5.0",
"scripts": {
"build": "webpack",
"build:mv3": "cross-env MANIFEST_VERSION=3 webpack",
"build:watch": "webpack --watch",
"build:watch:mv3": "cross-env MANIFEST_VERSION=3 webpack --watch",
"build": "cross-env MANIFEST_VERSION=3 webpack",
"build:mv2": "webpack",
"build:watch": "cross-env MANIFEST_VERSION=3 webpack --watch",
"build:watch:mv2": "webpack --watch",
"build:prod": "cross-env NODE_ENV=production webpack",
"build:prod:beta": "cross-env BETA_BUILD=1 NODE_ENV=production webpack",
"build:prod:watch": "cross-env NODE_ENV=production webpack --watch",

View File

@ -374,12 +374,21 @@
"other": {
"message": "الأخرى"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "أعدنّ طريقة إلغاء القُفْل لتغيير إجراء مهلة المخزن الخاص بك."
},
"unlockMethodNeeded": {
"message": "إعداد طريقة إلغاء القفل في الإعدادات"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "قيِّم هذه الإضافة"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -3,11 +3,11 @@
"message": "Bitwarden"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden Parol Meneceri",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Bitwarden evdə və ya işdə olarkən bütün parol, keçid açarı və həssas məlumatlarınızı asanlıqla qoruyur",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Digər"
},
"unlockMethods": {
"message": "Kilid açma seçimləri"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Anbar vaxt bitməsi əməliyyatınızı dəyişdirmək üçün bir kilid açma üsulu qurun."
},
"unlockMethodNeeded": {
"message": "Ayarlarda bir kilid açma üsulu qurun"
},
"sessionTimeoutHeader": {
"message": "Seans vaxt bitməsi"
},
"otherOptions": {
"message": "Digər seçimlər"
},
"rateExtension": {
"message": "Uzantını qiymətləndir"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Konsolu"
},
"accountSecurity": {
"message": "Hesab güvənliyi"
},
"notifications": {
"message": "Bildirişlər"
},
"appearance": {
"message": "Görünüş"
},
"errorAssigningTargetCollection": {
"message": "Hədəf kolleksiyaya təyin etmə xətası."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Iншае"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Наладзіць метад разблакіроўкі для змянення дзеяння часу чакання вашага сховішча."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Ацаніць пашырэнне"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -3,11 +3,11 @@
"message": "Битуорден (Bitwarden)"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden — управител на пароли",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "У дома, на работа или на път Битуорден защитава всички Ваши пароли, секретни ключове и лична информация",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Други"
},
"unlockMethods": {
"message": "Настройки за отключване"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Задайте метод за отключване, за да може да промените действието при изтичане на времето за достъп до трезора."
},
"unlockMethodNeeded": {
"message": "Задайте метод за отключване в Настройките"
},
"sessionTimeoutHeader": {
"message": "Изтичане на времето за сесията"
},
"otherOptions": {
"message": "Други настройки"
},
"rateExtension": {
"message": "Оценяване на разширението"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Административна конзола"
},
"accountSecurity": {
"message": "Защита на регистрацията"
},
"notifications": {
"message": "Известия"
},
"appearance": {
"message": "Външен вид"
},
"errorAssigningTargetCollection": {
"message": "Грешка при задаването на целева колекция."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "অন্যান্য"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "এক্সটেনশনটি মূল্যায়ন করুন"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Altres"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configura un mètode de desbloqueig per canviar l'acció del temps d'espera de la caixa forta."
},
"unlockMethodNeeded": {
"message": "Configura un mètode de desbloqueig a Configuració"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Valora aquesta extensió"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Consola d'administració"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "S'ha produït un error en assignar la col·lecció de destinació."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Ostatní"
},
"unlockMethods": {
"message": "Volby odemknutí"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Nastavte metodu odemknutí, abyste změnili časový limit Vašeho trezoru."
},
"unlockMethodNeeded": {
"message": "Nastavit metodu odemknutí v Nastavení"
},
"sessionTimeoutHeader": {
"message": "Časový limit relace"
},
"otherOptions": {
"message": "Další volby"
},
"rateExtension": {
"message": "Ohodnotit rozšíření"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Konzole správce"
},
"accountSecurity": {
"message": "Zabezpečení účtu"
},
"notifications": {
"message": "Oznámení"
},
"appearance": {
"message": "Vzhled"
},
"errorAssigningTargetCollection": {
"message": "Chyba při přiřazování cílové kolekce."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Gosodiadau eraill"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rhoi eich barn ar yr estyniad"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -3,11 +3,11 @@
"message": "Bitwarden"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden Adgangskodehåndtering",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Hjemme, på arbejde eller på farten sikrer Bitwarden nemt alle adgangskoder, adgangskort og sensitive oplysninger",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Andre"
},
"unlockMethods": {
"message": "Oplåsningsmuligheder"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Opsæt en oplåsningsmetode til at ændre bokstimeouthandlingen."
},
"unlockMethodNeeded": {
"message": "Opsæt en oplåsningsmetode i Indstillinger"
},
"sessionTimeoutHeader": {
"message": "Sessionstimeout"
},
"otherOptions": {
"message": "Andre innstillinger"
},
"rateExtension": {
"message": "Bedøm udvidelsen"
},
@ -2390,7 +2399,7 @@
"message": "Generelt"
},
"display": {
"message": "Display"
"message": "Skærm"
},
"accountSuccessfullyCreated": {
"message": "Konto oprettet!"
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin-konsol"
},
"accountSecurity": {
"message": "Kontosikkerhed"
},
"notifications": {
"message": "Notifikationer"
},
"appearance": {
"message": "Udseende"
},
"errorAssigningTargetCollection": {
"message": "Fejl ved tildeling af målsamling."
},

View File

@ -7,7 +7,7 @@
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Zu Hause, am Arbeitsplatz oder unterwegs schützt Bitwarden Passwörter, Passkeys und vertrauliche Informationen",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Sonstige"
},
"unlockMethods": {
"message": "Entsperroptionen"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Richte eine Entsperrmethode ein, um deine Aktion bei Timeout-Timeout zu ändern."
},
"unlockMethodNeeded": {
"message": "Lege eine Entsperrmethode in den Einstellungen fest"
},
"sessionTimeoutHeader": {
"message": "Sitzungs-Timeout"
},
"otherOptions": {
"message": "Andere Optionen"
},
"rateExtension": {
"message": "Erweiterung bewerten"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Administrator-Konsole"
},
"accountSecurity": {
"message": "Kontosicherheit"
},
"notifications": {
"message": "Benachrichtigungen"
},
"appearance": {
"message": "Aussehen"
},
"errorAssigningTargetCollection": {
"message": "Fehler beim Zuweisen der Ziel-Sammlung."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Άλλες"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Ρυθμίστε μια μέθοδο ξεκλειδώματος για να αλλάξετε την ενέργεια χρονικού ορίου θησαυ/κιου."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Βαθμολογήστε την επέκταση"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -2186,6 +2186,108 @@
"forwardedEmailDesc": {
"message": "Generate an email alias with an external forwarding service."
},
"forwarderError": {
"message": "$SERVICENAME$ error: $ERRORMESSAGE$",
"description": "Reports an error returned by a forwarding service to the user.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Invalid characters in domain name."
}
}
},
"forwarderGeneratedBy": {
"message": "Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen."
},
"forwarderGeneratedByWithWebsite": {
"message": "Website: $WEBSITE$. Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen.",
"placeholders": {
"WEBSITE": {
"content": "$1",
"example": "www.example.com"
}
}
},
"forwaderInvalidToken": {
"message": "Invalid $SERVICENAME$ API token",
"description": "Displayed when the user's API token is empty or rejected by the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwaderInvalidTokenWithMessage": {
"message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$",
"description": "Displayed when the user's API token is rejected by the forwarding service with an error message.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Please verify your email address to continue."
}
}
},
"forwarderNoAccountId": {
"message": "Unable to obtain $SERVICENAME$ masked email account ID.",
"description": "Displayed when the forwarding service fails to return an account ID.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoDomain": {
"message": "Invalid $SERVICENAME$ domain.",
"description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoUrl": {
"message": "Invalid $SERVICENAME$ url.",
"description": "Displayed when the url of the forwarding service wasn't supplied.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownError": {
"message": "Unknown $SERVICENAME$ error occurred.",
"description": "Displayed when the forwarding service failed due to an unknown error.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownForwarder": {
"message": "Unknown forwarder: '$SERVICENAME$'.",
"description": "Displayed when the forwarding service is not supported.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "JustTrust.us"
}
}
},
"hostname": {
"message": "Hostname",
"description": "Part of a URL."
@ -3046,7 +3148,7 @@
},
"notifications": {
"message": "Notifications"
},
},
"appearance": {
"message": "Appearance"
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -7,7 +7,7 @@
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "En casa, el trabajo o el viaje, Bitwarden asegura todas sus contraseñas, claves e información confidencial",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Otros"
},
"unlockMethods": {
"message": "Opciones de desbloqueo"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configura un método de desbloqueo para cambiar tu acción de cierre de la bóveda."
},
"unlockMethodNeeded": {
"message": "Configure un método de desbloqueo en Configuración"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Otras opciones"
},
"rateExtension": {
"message": "Valora la extensión"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Consola de administrador"
},
"accountSecurity": {
"message": "Seguridad de la cuenta"
},
"notifications": {
"message": "Notificaciones"
},
"appearance": {
"message": "Apariencia"
},
"errorAssigningTargetCollection": {
"message": "Error al asignar la colección de destino."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Muu"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Hoidla ajalõpu tegevuse muutmiseks vali esmalt lahtilukustamise meetod."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Hinda seda laiendust"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Bestelakoak"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Baloratu gehigarria"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "ساير"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "یک روش بازگشایی برای پایان زمان مجاز تنظیم کنید."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "به این افزونه امتیاز دهید"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Muut"
},
"unlockMethods": {
"message": "Avausasetukset"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Muuta holvisi aikakatkaisutoimintoa määrittämällä lukituksen avaustapa."
},
"unlockMethodNeeded": {
"message": "Määritä avaustapa asetuksista"
},
"sessionTimeoutHeader": {
"message": "Istunnon aikakatkaisu"
},
"otherOptions": {
"message": "Muut asetukset"
},
"rateExtension": {
"message": "Arvioi laajennus"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Hallintapaneelista"
},
"accountSecurity": {
"message": "Tilin suojaus"
},
"notifications": {
"message": "Ilmoitukset"
},
"appearance": {
"message": "Ulkoasu"
},
"errorAssigningTargetCollection": {
"message": "Virhe määritettäessä kohdekokoelmaa."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Iba pa"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Mag-set up ng paraan ng pag-unlock upang baguhin ang iyong pagkilos sa pag-timeout ng vault."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "I-rate ang extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Autre"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configurez une méthode de déverrouillage pour changer le délai d'expiration de votre coffre."
},
"unlockMethodNeeded": {
"message": "Configurer une méthode de déverrouillage dans les Paramètres"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Noter l'extension"
},
@ -3010,7 +3019,7 @@
"message": "Notice: Unassigned organization items are no longer visible in the All Vaults view and only accessible via the Admin Console."
},
"unassignedItemsBannerSelfHostNotice": {
"message": "Notice: On May 16, 2024, unassigned organization items will no longer be visible in the All Vaults view and will only be accessible via the Admin Console."
"message": "Remarque : À partir du 16 mai 2024, les éléments d'organisation non assignés ne seront plus visibles dans votre vue Tous les coffres sur les appareils et ne seront maintenant accessibles que via la Console Admin."
},
"unassignedItemsBannerCTAPartOne": {
"message": "Ajouter ces éléments à une collection depuis la",
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Console Admin"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -3,15 +3,15 @@
"message": "Bitwarden"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden - Xestor de contrasinais",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Na casa, no traballo ou en ruta, Bitwarden protexe os teus contrasinais, chaves de acceso e datos sensíbeis",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
"message": "Log in or create a new account to access your secure vault."
"message": "Rexístrate ou crea unha nova conta para acceder á túa caixa forte."
},
"createAccount": {
"message": "Crea unha conta"
@ -20,7 +20,7 @@
"message": "Iniciar sesión"
},
"enterpriseSingleSignOn": {
"message": "Enterprise single sign-on"
"message": "Inicio de sesión único empresarial"
},
"cancel": {
"message": "Cancelar"
@ -29,7 +29,7 @@
"message": "Pechar"
},
"submit": {
"message": "Submit"
"message": "Enviar"
},
"emailAddress": {
"message": "Enderezo de correo electrónico"
@ -38,142 +38,142 @@
"message": "Contrasinal mestre"
},
"masterPassDesc": {
"message": "The master password is the password you use to access your vault. It is very important that you do not forget your master password. There is no way to recover the password in the event that you forget it."
"message": "O contrasinal mestre é a chave que empregas para acceder á túa caixa forte. É moi importante que non esquezas o teu contrasinal mestre. Non hai xeito de recuperala se a esqueces."
},
"masterPassHintDesc": {
"message": "A master password hint can help you remember your password if you forget it."
"message": "Unha pista do contrasinal mestre pode axudarte a lembrar o teu contrasinal se o esqueces."
},
"reTypeMasterPass": {
"message": "Re-type master password"
"message": "Reescriba o contrasinal mestre"
},
"masterPassHint": {
"message": "Master password hint (optional)"
"message": "Pista do contrasinal mestre (opcional)"
},
"tab": {
"message": "Tab"
"message": "Separador"
},
"vault": {
"message": "Vault"
"message": "Caixa forte"
},
"myVault": {
"message": "My vault"
"message": "A miña caixa forte"
},
"allVaults": {
"message": "All vaults"
"message": "Todas as caixas fortes"
},
"tools": {
"message": "Tools"
"message": "Ferramentas"
},
"settings": {
"message": "Settings"
"message": "Axustes"
},
"currentTab": {
"message": "Current tab"
"message": "Separador actual"
},
"copyPassword": {
"message": "Copy password"
"message": "Copiar contrasinal"
},
"copyNote": {
"message": "Copy note"
"message": "Copiar nota"
},
"copyUri": {
"message": "Copy URI"
"message": "Copiar URI"
},
"copyUsername": {
"message": "Copy username"
"message": "Copiar nome de usuario"
},
"copyNumber": {
"message": "Copy number"
"message": "Copiar número"
},
"copySecurityCode": {
"message": "Copy security code"
"message": "Copiar código de seguranza"
},
"autoFill": {
"message": "Auto-fill"
"message": "Auto-encher"
},
"autoFillLogin": {
"message": "Auto-fill login"
"message": "Encher automaticamente inicio de sesión"
},
"autoFillCard": {
"message": "Auto-fill card"
"message": "Encher automaticamente tarxeta"
},
"autoFillIdentity": {
"message": "Auto-fill identity"
"message": "Encher automaticamente identidade"
},
"generatePasswordCopied": {
"message": "Generate password (copied)"
"message": "Xerar contrasinal (copiado)"
},
"copyElementIdentifier": {
"message": "Copy custom field name"
"message": "Copiar nome de campo personalizado"
},
"noMatchingLogins": {
"message": "No matching logins"
"message": "Sen inicios de sesión coincidentes"
},
"noCards": {
"message": "No cards"
"message": "Sen tarxetas"
},
"noIdentities": {
"message": "No identities"
"message": "Sen identidades"
},
"addLoginMenu": {
"message": "Add login"
"message": "Engadir inicio de sesión"
},
"addCardMenu": {
"message": "Add card"
"message": "Engadir tarxeta"
},
"addIdentityMenu": {
"message": "Add identity"
"message": "Engadir identidade"
},
"unlockVaultMenu": {
"message": "Unlock your vault"
"message": "Desbloquear a súa caixa forte"
},
"loginToVaultMenu": {
"message": "Log in to your vault"
"message": "Rexistrarse na súa caixa forte"
},
"autoFillInfo": {
"message": "There are no logins available to auto-fill for the current browser tab."
"message": "Non hai inicios de sesión dispoñíbeis para encher automaticamente para o separador actual do navegador."
},
"addLogin": {
"message": "Add a login"
"message": "Engadir inicio de sesión"
},
"addItem": {
"message": "Add item"
"message": "Engadir elemento"
},
"passwordHint": {
"message": "Password hint"
"message": "Pista do contrasinal"
},
"enterEmailToGetHint": {
"message": "Enter your account email address to receive your master password hint."
"message": "Introduce a dirección de correo da túa conta para recibir a pista do contrasinal mestre."
},
"getMasterPasswordHint": {
"message": "Get master password hint"
"message": "Obter pista do contrasinal mestre"
},
"continue": {
"message": "Continue"
"message": "Continuar"
},
"sendVerificationCode": {
"message": "Send a verification code to your email"
"message": "Envía un código de verificación ao teu correo"
},
"sendCode": {
"message": "Send code"
"message": "Enviar código"
},
"codeSent": {
"message": "Code sent"
"message": "Código enviado"
},
"verificationCode": {
"message": "Verification code"
"message": "Código de verificación"
},
"confirmIdentity": {
"message": "Confirm your identity to continue."
"message": "Confirma a túa identidade para continuar."
},
"account": {
"message": "Account"
"message": "Conta"
},
"changeMasterPassword": {
"message": "Change master password"
"message": "Cambiar o contrasinal mestre"
},
"continueToWebApp": {
"message": "Continue to web app?"
"message": "Continuar á aplicación web?"
},
"changeMasterPasswordOnWebConfirmation": {
"message": "You can change your master password on the Bitwarden web app."
@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "אחר"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "דירוג הרחבה"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "अन्य"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the Extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Ostalo"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Za promjenu vremena isteka trezora, odredi način otključavanja."
},
"unlockMethodNeeded": {
"message": "Postavi način otključavanja u Postavkama"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Ocijeni proširenje"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Egyéb"
},
"unlockMethods": {
"message": "Feloldási opciók"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Állítsunk be egy feloldási módot a széf időkifutási műveletének módosításához."
},
"unlockMethodNeeded": {
"message": "Feloldási mód beállítása a Beállításokban"
},
"sessionTimeoutHeader": {
"message": "Munkamenet időkifutás"
},
"otherOptions": {
"message": "Egyéb opciók"
},
"rateExtension": {
"message": "Bővítmény értékelése"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Adminisztrátori konzol"
},
"accountSecurity": {
"message": "Fiókbiztonság"
},
"notifications": {
"message": "Értesítések"
},
"appearance": {
"message": "Megjelenés"
},
"errorAssigningTargetCollection": {
"message": "Hiba történt a célgyűjtemény hozzárendelése során."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Lainnya"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Nilai Ekstensi"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Altro"
},
"unlockMethods": {
"message": "Opzioni di sblocco"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Imposta un metodo di sblocco per modificare l'azione timeout cassaforte."
},
"unlockMethodNeeded": {
"message": "Imposta un metodo di sblocco in Impostazioni"
},
"sessionTimeoutHeader": {
"message": "Timeout della sessione"
},
"otherOptions": {
"message": "Altre opzioni"
},
"rateExtension": {
"message": "Valuta l'estensione"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Console di amministrazione"
},
"accountSecurity": {
"message": "Sicurezza dell'account"
},
"notifications": {
"message": "Notifiche"
},
"appearance": {
"message": "Aspetto"
},
"errorAssigningTargetCollection": {
"message": "Errore nell'assegnazione della raccolta di destinazione."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "その他"
},
"unlockMethods": {
"message": "ロック解除オプション"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "保管庫のタイムアウト動作を変更するには、ロック解除方法を設定してください。"
},
"unlockMethodNeeded": {
"message": "設定でロック解除方法をセットアップ"
},
"sessionTimeoutHeader": {
"message": "セッションタイムアウト"
},
"otherOptions": {
"message": "その他のオプション"
},
"rateExtension": {
"message": "拡張機能の評価"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "管理コンソール"
},
"accountSecurity": {
"message": "アカウントのセキュリティ"
},
"notifications": {
"message": "通知"
},
"appearance": {
"message": "外観"
},
"errorAssigningTargetCollection": {
"message": "ターゲットコレクションの割り当てに失敗しました。"
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "სხვა"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "ಇತರೆ"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "ವಿಸ್ತರಣೆಯನ್ನು ರೇಟ್ ಮಾಡಿ"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "기타"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "잠금 해제 방법을 설정하여 보관함의 시간 초과 동작을 변경하세요."
},
"unlockMethodNeeded": {
"message": "설정에서 잠금 해제 수단 설정하기"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "확장 프로그램 평가"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Kita"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Nustatyk atrakinimo būdą, kad pakeistum saugyklos laiko limito veiksmą."
},
"unlockMethodNeeded": {
"message": "Nustatykite nustatymuose atrakinimo metodą"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Įvertinkite šį plėtinį"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Administratoriaus konsolės"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Klaida priskiriant tikslinę kolekciją."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Cits"
},
"unlockMethods": {
"message": "Atslēgšanas iespējas"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Jāuzstāda atslēgšanas veids, lai mainītu glabātavas noildzes darbību."
},
"unlockMethodNeeded": {
"message": "Jāuzstāda atslēgšanas veids iestatījumos"
},
"sessionTimeoutHeader": {
"message": "Sesijas noildze"
},
"otherOptions": {
"message": "Citas iespējas"
},
"rateExtension": {
"message": "Novērtēt paplašinājumu"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "pārvaldības konsolē,"
},
"accountSecurity": {
"message": "Konta drošība"
},
"notifications": {
"message": "Paziņojumi"
},
"appearance": {
"message": "Izskats"
},
"errorAssigningTargetCollection": {
"message": "Kļūda mērķa krājuma piešķiršanā."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "മറ്റുള്ളവ"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "എക്സ്റ്റൻഷൻ റേറ്റ് ചെയ്യുക "
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "इतर"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "विस्तारकाचे मूल्यांकन करा"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Annet"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Gi denne utvidelsen en vurdering"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Overig"
},
"unlockMethods": {
"message": "Ontgrendelopties"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Stel een ontgrendelingsmethode in om je kluis time-out actie te wijzigen."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Sessietime-out"
},
"otherOptions": {
"message": "Andere opties"
},
"rateExtension": {
"message": "Deze extensie beoordelen"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Accountbeveiliging"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Voorkomen"
},
"errorAssigningTargetCollection": {
"message": "Fout bij toewijzen doelverzameling."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Inne"
},
"unlockMethods": {
"message": "Odblokuj Opcje"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Ustaw metodę odblokowania, aby zmienić czas blokowania sejfu."
},
"unlockMethodNeeded": {
"message": "Ustaw metodę odblokowania w Ustawieniach"
},
"sessionTimeoutHeader": {
"message": "Limit czasu sesji"
},
"otherOptions": {
"message": "Pozostałe opcje"
},
"rateExtension": {
"message": "Oceń rozszerzenie"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Konsola Administracyjna"
},
"accountSecurity": {
"message": "Bezpieczeństwo konta"
},
"notifications": {
"message": "Powiadomienia"
},
"appearance": {
"message": "Wygląd"
},
"errorAssigningTargetCollection": {
"message": "Wystąpił błąd podczas przypisywania kolekcji."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Outros"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configure um método de desbloqueio para alterar o tempo limite do cofre."
},
"unlockMethodNeeded": {
"message": "Configure um método de desbloqueio nas Configurações"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Avaliar a Extensão"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Painel de administração"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Erro ao atribuir coleção de destino."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Outros"
},
"unlockMethods": {
"message": "Opções de desbloqueio"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configure um método de desbloqueio para alterar a ação de tempo limite do seu cofre."
},
"unlockMethodNeeded": {
"message": "Definir um método de desbloqueio nas Definições"
},
"sessionTimeoutHeader": {
"message": "Tempo limite da sessão"
},
"otherOptions": {
"message": "Outras opções"
},
"rateExtension": {
"message": "Avaliar a extensão"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Consola de administração"
},
"accountSecurity": {
"message": "Segurança da conta"
},
"notifications": {
"message": "Notificações"
},
"appearance": {
"message": "Aparência"
},
"errorAssigningTargetCollection": {
"message": "Erro ao atribuir a coleção de destino."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Altele"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Configurați metoda de deblocare care să schimbe acțiunea de expirare a seifului."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Evaluare extensie"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -3,11 +3,11 @@
"message": "Bitwarden"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden - Менеджер паролей",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Дома, на работе или в пути - Bitwarden всегда защитит ваши пароли, passkeys и конфиденциальную информацию",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Прочее"
},
"unlockMethods": {
"message": "Настройки разблокировки"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Настройте способ разблокировки для изменения действия по тайм-ауту хранилища."
},
"unlockMethodNeeded": {
"message": "Установите способ разблокировки в настройках"
},
"sessionTimeoutHeader": {
"message": "Тайм-аут сессии"
},
"otherOptions": {
"message": "Прочие настройки"
},
"rateExtension": {
"message": "Оценить расширение"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "консоли администратора"
},
"accountSecurity": {
"message": "Безопасность аккаунта"
},
"notifications": {
"message": "Уведомления"
},
"appearance": {
"message": "Внешний вид"
},
"errorAssigningTargetCollection": {
"message": "Ошибка при назначении целевой коллекции."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "වෙනත්"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "දිගුව අනුපාතය"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Ostatné"
},
"unlockMethods": {
"message": "Možnosti odomknutia"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Nastavte metódu odomknutia, aby ste zmenili akciu pri vypršaní času trezoru."
},
"unlockMethodNeeded": {
"message": "Nastavte metódu odomknutia v Nastaveniach"
},
"sessionTimeoutHeader": {
"message": "Časový limit relácie"
},
"otherOptions": {
"message": "Ďalšie možnosti"
},
"rateExtension": {
"message": "Ohodnotiť rozšírenie"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Správcovská konzola"
},
"accountSecurity": {
"message": "Zabezpečenie účtu"
},
"notifications": {
"message": "Upozornenia"
},
"appearance": {
"message": "Vzhľad"
},
"errorAssigningTargetCollection": {
"message": "Chyba pri priraďovaní cieľovej kolekcie."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Drugo"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Da spremenite časovne omejitve trezorja, nastavite metodo odklepanja."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Ocenite to razširitev"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Остало"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Подесите метод откључавања да бисте променили радњу временског ограничења сефа."
},
"unlockMethodNeeded": {
"message": "Подесите метод откључавања у подешавањима"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Оцени овај додатак"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Администраторска конзола"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Грешка при додељивању циљне колекције."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Annat"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Ställ in en upplåsningsmetod i Inställningar"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Betygsätt tillägget"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Utseende"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Other"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "อื่น ๆ"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Set up an unlock method to change your vault timeout action."
},
"unlockMethodNeeded": {
"message": "Set up an unlock method in Settings"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Rate the Extension"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Diğer"
},
"unlockMethods": {
"message": "Kilit açma seçenekleri"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Kasa zaman aşımı eyleminizi değiştirmek için kilit açma yönteminizi ayarlayın."
},
"unlockMethodNeeded": {
"message": "Ayarlar'da bir kilit açma yöntemi ayarlayın"
},
"sessionTimeoutHeader": {
"message": "Oturum zaman aşımı"
},
"otherOptions": {
"message": "Diğer seçenekler"
},
"rateExtension": {
"message": "Uzantıyı değerlendirin"
},
@ -3023,10 +3032,19 @@
"adminConsole": {
"message": "Yönetici Konsolu"
},
"accountSecurity": {
"message": "Hesap güvenliği"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
"message": "Hedef koleksiyonu atama hatası."
},
"errorAssigningTargetFolder": {
"message": "Error assigning target folder."
"message": "Hedef klasörü atama hatası."
}
}

View File

@ -3,11 +3,11 @@
"message": "Bitwarden"
},
"extName": {
"message": "Bitwarden Password Manager",
"message": "Bitwarden менеджер паролів",
"description": "Extension name, MUST be less than 40 characters (Safari restriction)"
},
"extDesc": {
"message": "At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information",
"message": "Вдома, на роботі чи в дорозі, Bitwarden захищає ваші паролі, ключі доступу та конфіденційну інформацію",
"description": "Extension description, MUST be less than 112 characters (Safari restriction)"
},
"loginOrCreateNewAccount": {
@ -374,12 +374,21 @@
"other": {
"message": "Інше"
},
"unlockMethods": {
"message": "Налаштування розблокування"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Налаштуйте спосіб розблокування, щоб змінити час очікування сховища."
},
"unlockMethodNeeded": {
"message": "Встановіть спосіб розблокування в налаштуваннях"
},
"sessionTimeoutHeader": {
"message": "Час очікування сеансу"
},
"otherOptions": {
"message": "Інші налаштування"
},
"rateExtension": {
"message": "Оцінити розширення"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "консолі адміністратора,"
},
"accountSecurity": {
"message": "Безпека облікового запису"
},
"notifications": {
"message": "Сповіщення"
},
"appearance": {
"message": "Вигляд"
},
"errorAssigningTargetCollection": {
"message": "Помилка призначення цільової збірки."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "Khác"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "Thiết lập phương thức mở khóa để thay đổi hành động hết thời gian chờ của vault."
},
"unlockMethodNeeded": {
"message": "Thiết lập phương pháp mở khóa trong Cài đặt"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "Đánh giá tiện ích mở rộng"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Bảng điều khiển dành cho quản trị viên"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "其他"
},
"unlockMethods": {
"message": "解锁选项"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "设置一个解锁方式以更改您的密码库超时动作。"
},
"unlockMethodNeeded": {
"message": "在设置中设置一个解锁方式"
},
"sessionTimeoutHeader": {
"message": "会话超时"
},
"otherOptions": {
"message": "其他选项"
},
"rateExtension": {
"message": "为本扩展打分"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "管理控制台"
},
"accountSecurity": {
"message": "账户安全"
},
"notifications": {
"message": "通知"
},
"appearance": {
"message": "外观"
},
"errorAssigningTargetCollection": {
"message": "分配目标集合时出错。"
},

View File

@ -374,12 +374,21 @@
"other": {
"message": "其他"
},
"unlockMethods": {
"message": "Unlock options"
},
"unlockMethodNeededToChangeTimeoutActionDesc": {
"message": "設定一個解鎖方式來變更您的密碼庫逾時動作。"
},
"unlockMethodNeeded": {
"message": "設定中設定解鎖"
},
"sessionTimeoutHeader": {
"message": "Session timeout"
},
"otherOptions": {
"message": "Other options"
},
"rateExtension": {
"message": "為本套件評分"
},
@ -3023,6 +3032,15 @@
"adminConsole": {
"message": "Admin Console"
},
"accountSecurity": {
"message": "Account security"
},
"notifications": {
"message": "Notifications"
},
"appearance": {
"message": "Appearance"
},
"errorAssigningTargetCollection": {
"message": "Error assigning target collection."
},

View File

@ -4,6 +4,10 @@ import {
policyServiceFactory,
PolicyServiceInitOptions,
} from "../../../admin-console/background/service-factories/policy-service.factory";
import {
vaultTimeoutSettingsServiceFactory,
VaultTimeoutSettingsServiceInitOptions,
} from "../../../background/service-factories/vault-timeout-settings-service.factory";
import {
apiServiceFactory,
ApiServiceInitOptions,
@ -108,6 +112,7 @@ export type LoginStrategyServiceInitOptions = LoginStrategyServiceFactoryOptions
UserDecryptionOptionsServiceInitOptions &
GlobalStateProviderInitOptions &
BillingAccountProfileStateServiceInitOptions &
VaultTimeoutSettingsServiceInitOptions &
KdfConfigServiceInitOptions;
export function loginStrategyServiceFactory(
@ -142,6 +147,7 @@ export function loginStrategyServiceFactory(
await internalUserDecryptionOptionServiceFactory(cache, opts),
await globalStateProviderFactory(cache, opts),
await billingAccountProfileStateServiceFactory(cache, opts),
await vaultTimeoutSettingsServiceFactory(cache, opts),
await kdfConfigServiceFactory(cache, opts),
),
);

View File

@ -31,6 +31,11 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { BiometricStateService } from "@bitwarden/common/platform/biometrics/biometric-state.service";
import {
VaultTimeout,
VaultTimeoutOption,
VaultTimeoutStringType,
} from "@bitwarden/common/types/vault-timeout.type";
import { DialogService } from "@bitwarden/components";
import { BiometricErrors, BiometricErrorTypes } from "../../../models/biometricErrors";
@ -50,7 +55,7 @@ export class AccountSecurityComponent implements OnInit {
protected readonly VaultTimeoutAction = VaultTimeoutAction;
availableVaultTimeoutActions: VaultTimeoutAction[] = [];
vaultTimeoutOptions: any[];
vaultTimeoutOptions: VaultTimeoutOption[];
vaultTimeoutPolicyCallout: Observable<{
timeout: { hours: number; minutes: number };
action: VaultTimeoutAction;
@ -60,7 +65,7 @@ export class AccountSecurityComponent implements OnInit {
accountSwitcherEnabled = false;
form = this.formBuilder.group({
vaultTimeout: [null as number | null],
vaultTimeout: [null as VaultTimeout | null],
vaultTimeoutAction: [VaultTimeoutAction.Lock],
pin: [null as boolean | null],
biometric: false,
@ -118,20 +123,31 @@ export class AccountSecurityComponent implements OnInit {
{ name: this.i18nService.t("thirtyMinutes"), value: 30 },
{ name: this.i18nService.t("oneHour"), value: 60 },
{ name: this.i18nService.t("fourHours"), value: 240 },
// { name: i18nService.t('onIdle'), value: -4 },
// { name: i18nService.t('onSleep'), value: -3 },
];
if (showOnLocked) {
this.vaultTimeoutOptions.push({ name: this.i18nService.t("onLocked"), value: -2 });
this.vaultTimeoutOptions.push({
name: this.i18nService.t("onLocked"),
value: VaultTimeoutStringType.OnLocked,
});
}
this.vaultTimeoutOptions.push({ name: this.i18nService.t("onRestart"), value: -1 });
this.vaultTimeoutOptions.push({ name: this.i18nService.t("never"), value: null });
this.vaultTimeoutOptions.push({
name: this.i18nService.t("onRestart"),
value: VaultTimeoutStringType.OnRestart,
});
this.vaultTimeoutOptions.push({
name: this.i18nService.t("never"),
value: VaultTimeoutStringType.Never,
});
let timeout = await this.vaultTimeoutSettingsService.getVaultTimeout();
if (timeout === -2 && !showOnLocked) {
timeout = -1;
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
let timeout = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(activeAccount.id),
);
if (timeout === VaultTimeoutStringType.OnLocked && !showOnLocked) {
timeout = VaultTimeoutStringType.OnRestart;
}
this.form.controls.vaultTimeout.valueChanges
@ -159,7 +175,7 @@ export class AccountSecurityComponent implements OnInit {
const initialValues = {
vaultTimeout: timeout,
vaultTimeoutAction: await firstValueFrom(
this.vaultTimeoutSettingsService.vaultTimeoutAction$(),
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
),
pin: await this.pinService.isPinSet(userId),
biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(),
@ -203,7 +219,7 @@ export class AccountSecurityComponent implements OnInit {
switchMap(() =>
combineLatest([
this.vaultTimeoutSettingsService.availableVaultTimeoutActions$(),
this.vaultTimeoutSettingsService.vaultTimeoutAction$(),
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
]),
),
takeUntil(this.destroy$),
@ -237,8 +253,8 @@ export class AccountSecurityComponent implements OnInit {
});
}
async saveVaultTimeout(previousValue: number, newValue: number) {
if (newValue == null) {
async saveVaultTimeout(previousValue: VaultTimeout, newValue: VaultTimeout) {
if (newValue === VaultTimeoutStringType.Never) {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "warning" },
content: { key: "neverLockWarning" },
@ -262,11 +278,18 @@ export class AccountSecurityComponent implements OnInit {
return;
}
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
newValue,
await firstValueFrom(this.vaultTimeoutSettingsService.vaultTimeoutAction$()),
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
const vaultTimeoutAction = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
);
if (newValue == null) {
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
activeAccount.id,
newValue,
vaultTimeoutAction,
);
if (newValue === VaultTimeoutStringType.Never) {
this.messagingService.send("bgReseedStorage");
}
}
@ -296,7 +319,10 @@ export class AccountSecurityComponent implements OnInit {
return;
}
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
activeAccount.id,
this.form.value.vaultTimeout,
newValue,
);

View File

@ -1,5 +1,6 @@
import { Region } from "@bitwarden/common/platform/abstractions/environment.service";
import { VaultTimeoutAction } from "@bitwarden/common/src/enums/vault-timeout-action.enum";
import { VaultTimeout } from "@bitwarden/common/types/vault-timeout.type";
import { CipherType } from "@bitwarden/common/vault/enums";
export type UserSettings = {
@ -31,7 +32,7 @@ export type UserSettings = {
utcDate: string;
version: string;
};
vaultTimeout: number;
vaultTimeout: VaultTimeout;
vaultTimeoutAction: VaultTimeoutAction;
};

View File

@ -1,9 +1,11 @@
import { firstValueFrom } from "rxjs";
import { NotificationsService } from "@bitwarden/common/abstractions/notifications.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { BrowserStateService } from "../platform/services/abstractions/browser-state.service";
@ -19,6 +21,7 @@ export default class IdleBackground {
private stateService: BrowserStateService,
private notificationsService: NotificationsService,
private accountService: AccountService,
private vaultTimeoutSettingsService: VaultTimeoutSettingsService,
) {
this.idle = chrome.idle || (browser != null ? browser.idle : null);
}
@ -54,10 +57,14 @@ export default class IdleBackground {
const allUsers = await firstValueFrom(this.accountService.accounts$);
for (const userId in allUsers) {
// If the screen is locked or the screensaver activates
const timeout = await this.stateService.getVaultTimeout({ userId: userId });
if (timeout === -2) {
const timeout = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(userId),
);
if (timeout === VaultTimeoutStringType.OnLocked) {
// On System Lock vault timeout option
const action = await this.stateService.getVaultTimeoutAction({ userId: userId });
const action = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(userId),
);
if (action === VaultTimeoutAction.LogOut) {
await this.vaultTimeoutService.logOut(userId);
} else {

View File

@ -126,6 +126,7 @@ import { DefaultActiveUserStateProvider } from "@bitwarden/common/platform/state
import { DefaultGlobalStateProvider } from "@bitwarden/common/platform/state/implementations/default-global-state.provider";
import { DefaultSingleUserStateProvider } from "@bitwarden/common/platform/state/implementations/default-single-user-state.provider";
import { DefaultStateProvider } from "@bitwarden/common/platform/state/implementations/default-state.provider";
import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state";
import { StateEventRegistrarService } from "@bitwarden/common/platform/state/state-event-registrar.service";
/* eslint-enable import/no-restricted-paths */
import { DefaultThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
@ -154,6 +155,7 @@ import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-st
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
import { InternalSendService as InternalSendServiceAbstraction } from "@bitwarden/common/tools/send/services/send.service.abstraction";
import { UserId } from "@bitwarden/common/types/guid";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService as CollectionServiceAbstraction } from "@bitwarden/common/vault/abstractions/collection.service";
import { Fido2AuthenticatorService as Fido2AuthenticatorServiceAbstraction } from "@bitwarden/common/vault/abstractions/fido2/fido2-authenticator.service.abstraction";
@ -225,7 +227,6 @@ import I18nService from "../platform/services/i18n.service";
import { LocalBackedSessionStorageService } from "../platform/services/local-backed-session-storage.service";
import { BackgroundPlatformUtilsService } from "../platform/services/platform-utils/background-platform-utils.service";
import { BrowserPlatformUtilsService } from "../platform/services/platform-utils/browser-platform-utils.service";
import { BackgroundDerivedStateProvider } from "../platform/state/background-derived-state.provider";
import { BackgroundMemoryStorageService } from "../platform/storage/background-memory-storage.service";
import { BrowserStorageServiceProvider } from "../platform/storage/browser-storage-service.provider";
import { ForegroundMemoryStorageService } from "../platform/storage/foreground-memory-storage.service";
@ -505,7 +506,7 @@ export default class MainBackground {
this.accountService,
this.singleUserStateProvider,
);
this.derivedStateProvider = new BackgroundDerivedStateProvider();
this.derivedStateProvider = new InlineDerivedStateProvider();
this.stateProvider = new DefaultStateProvider(
this.activeUserStateProvider,
this.singleUserStateProvider,
@ -592,15 +593,33 @@ export default class MainBackground {
);
this.appIdService = new AppIdService(this.globalStateProvider);
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
this.organizationService = new OrganizationService(this.stateProvider);
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
this.accountService,
this.pinService,
this.userDecryptionOptionsService,
this.cryptoService,
this.tokenService,
this.policyService,
this.biometricStateService,
this.stateProvider,
this.logService,
VaultTimeoutStringType.OnRestart, // default vault timeout
);
this.apiService = new ApiService(
this.tokenService,
this.platformUtilsService,
this.environmentService,
this.appIdService,
this.stateService,
refreshAccessTokenErrorCallback,
this.logService,
(logoutReason: LogoutReason, userId?: UserId) => this.logout(logoutReason, userId),
this.vaultTimeoutSettingsService,
);
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
@ -617,8 +636,7 @@ export default class MainBackground {
this.stateProvider,
);
this.syncNotifierService = new SyncNotifierService();
this.organizationService = new OrganizationService(this.stateProvider);
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.autofillSettingsService = new AutofillSettingsService(
this.stateProvider,
this.policyService,
@ -724,17 +742,6 @@ export default class MainBackground {
);
this.folderApiService = new FolderApiService(this.folderService, this.apiService);
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
this.accountService,
this.pinService,
this.userDecryptionOptionsService,
this.cryptoService,
this.tokenService,
this.policyService,
this.stateService,
this.biometricStateService,
);
this.userVerificationService = new UserVerificationService(
this.stateService,
this.cryptoService,
@ -1070,6 +1077,7 @@ export default class MainBackground {
this.stateService,
this.notificationsService,
this.accountService,
this.vaultTimeoutSettingsService,
);
this.usernameGenerationService = new UsernameGenerationService(
@ -1277,7 +1285,7 @@ export default class MainBackground {
]);
//Needs to be checked before state is cleaned
const needStorageReseed = await this.needsStorageReseed();
const needStorageReseed = await this.needsStorageReseed(userId);
const newActiveUser =
userBeingLoggedOut === activeUserId
@ -1321,9 +1329,11 @@ export default class MainBackground {
await this.systemService.startProcessReload(this.authService);
}
private async needsStorageReseed(): Promise<boolean> {
const currentVaultTimeout = await this.stateService.getVaultTimeout();
return currentVaultTimeout == null ? false : true;
private async needsStorageReseed(userId: UserId): Promise<boolean> {
const currentVaultTimeout = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(userId),
);
return currentVaultTimeout == VaultTimeoutStringType.Never ? false : true;
}
async collectPageDetailsForContentScript(tab: any, sender: string, frameId: number = null) {

View File

@ -1,5 +1,6 @@
import { VaultTimeoutSettingsService as AbstractVaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vault-timeout/vault-timeout-settings.service";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import {
policyServiceFactory,
@ -35,9 +36,13 @@ import {
FactoryOptions,
} from "../../platform/background/service-factories/factory-options";
import {
StateServiceInitOptions,
stateServiceFactory,
} from "../../platform/background/service-factories/state-service.factory";
logServiceFactory,
LogServiceInitOptions,
} from "../../platform/background/service-factories/log-service.factory";
import {
StateProviderInitOptions,
stateProviderFactory,
} from "../../platform/background/service-factories/state-provider.factory";
type VaultTimeoutSettingsServiceFactoryOptions = FactoryOptions;
@ -48,8 +53,9 @@ export type VaultTimeoutSettingsServiceInitOptions = VaultTimeoutSettingsService
CryptoServiceInitOptions &
TokenServiceInitOptions &
PolicyServiceInitOptions &
StateServiceInitOptions &
BiometricStateServiceInitOptions;
BiometricStateServiceInitOptions &
StateProviderInitOptions &
LogServiceInitOptions;
export function vaultTimeoutSettingsServiceFactory(
cache: { vaultTimeoutSettingsService?: AbstractVaultTimeoutSettingsService } & CachedServices,
@ -67,8 +73,10 @@ export function vaultTimeoutSettingsServiceFactory(
await cryptoServiceFactory(cache, opts),
await tokenServiceFactory(cache, opts),
await policyServiceFactory(cache, opts),
await stateServiceFactory(cache, opts),
await biometricStateServiceFactory(cache, opts),
await stateProviderFactory(cache, opts),
await logServiceFactory(cache, opts),
VaultTimeoutStringType.OnRestart, // default vault timeout
),
);
}

View File

@ -1,28 +1,12 @@
import { Jsonify } from "type-fest";
import {
Account as BaseAccount,
AccountSettings as BaseAccountSettings,
} from "@bitwarden/common/platform/models/domain/account";
import { Account as BaseAccount } from "@bitwarden/common/platform/models/domain/account";
import { BrowserComponentState } from "./browserComponentState";
import { BrowserGroupingsComponentState } from "./browserGroupingsComponentState";
import { BrowserSendComponentState } from "./browserSendComponentState";
export class AccountSettings extends BaseAccountSettings {
vaultTimeout = -1; // On Restart
static fromJSON(json: Jsonify<AccountSettings>): AccountSettings {
if (json == null) {
return null;
}
return Object.assign(new AccountSettings(), json, super.fromJSON(json));
}
}
export class Account extends BaseAccount {
settings?: AccountSettings = new AccountSettings();
groupings?: BrowserGroupingsComponentState;
send?: BrowserSendComponentState;
ciphers?: BrowserComponentState;
@ -30,10 +14,7 @@ export class Account extends BaseAccount {
constructor(init: Partial<Account>) {
super(init);
Object.assign(this.settings, {
...new AccountSettings(),
...this.settings,
});
this.groupings = init?.groupings ?? new BrowserGroupingsComponentState();
this.send = init?.send ?? new BrowserSendComponentState();
this.ciphers = init?.ciphers ?? new BrowserComponentState();
@ -46,7 +27,6 @@ export class Account extends BaseAccount {
}
return Object.assign(new Account({}), json, super.fromJSON(json), {
settings: AccountSettings.fromJSON(json.settings),
groupings: BrowserGroupingsComponentState.fromJSON(json.groupings),
send: BrowserSendComponentState.fromJSON(json.send),
ciphers: BrowserComponentState.fromJSON(json.ciphers),

View File

@ -7,6 +7,10 @@ import {
tokenServiceFactory,
TokenServiceInitOptions,
} from "../../../auth/background/service-factories/token-service.factory";
import {
vaultTimeoutSettingsServiceFactory,
VaultTimeoutSettingsServiceInitOptions,
} from "../../../background/service-factories/vault-timeout-settings-service.factory";
import {
CachedServices,
factory,
@ -23,7 +27,6 @@ import {
PlatformUtilsServiceInitOptions,
platformUtilsServiceFactory,
} from "./platform-utils-service.factory";
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
type ApiServiceFactoryOptions = FactoryOptions & {
apiServiceOptions: {
@ -38,8 +41,8 @@ export type ApiServiceInitOptions = ApiServiceFactoryOptions &
PlatformUtilsServiceInitOptions &
EnvironmentServiceInitOptions &
AppIdServiceInitOptions &
StateServiceInitOptions &
LogServiceInitOptions;
LogServiceInitOptions &
VaultTimeoutSettingsServiceInitOptions;
export function apiServiceFactory(
cache: { apiService?: AbstractApiService } & CachedServices,
@ -55,13 +58,13 @@ export function apiServiceFactory(
await platformUtilsServiceFactory(cache, opts),
await environmentServiceFactory(cache, opts),
await appIdServiceFactory(cache, opts),
await stateServiceFactory(cache, opts),
opts.apiServiceOptions.refreshAccessTokenErrorCallback ??
(() => {
return Promise.reject("No callback");
}),
await logServiceFactory(cache, opts),
opts.apiServiceOptions.logoutCallback,
await vaultTimeoutSettingsServiceFactory(cache, opts),
opts.apiServiceOptions.customUserAgent,
),
);

View File

@ -1,6 +1,6 @@
import { DerivedStateProvider } from "@bitwarden/common/platform/state";
import { BackgroundDerivedStateProvider } from "../../state/background-derived-state.provider";
// eslint-disable-next-line import/no-restricted-paths -- For dependency creation
import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state";
import { CachedServices, FactoryOptions, factory } from "./factory-options";
@ -12,10 +12,5 @@ export async function derivedStateProviderFactory(
cache: { derivedStateProvider?: DerivedStateProvider } & CachedServices,
opts: DerivedStateProviderInitOptions,
): Promise<DerivedStateProvider> {
return factory(
cache,
"derivedStateProvider",
opts,
async () => new BackgroundDerivedStateProvider(),
);
return factory(cache, "derivedStateProvider", opts, async () => new InlineDerivedStateProvider());
}

View File

@ -1,12 +1,16 @@
import { CommonModule } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import BrowserPopupUtils from "../../platform/popup/browser-popup-utils";
import BrowserPopupUtils from "../browser-popup-utils";
@Component({
selector: "app-pop-out",
templateUrl: "pop-out.component.html",
standalone: true,
imports: [CommonModule, JslibModule],
})
export class PopOutComponent implements OnInit {
@Input() show = true;
@ -24,9 +28,7 @@ export class PopOutComponent implements OnInit {
}
}
expand() {
// 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
BrowserPopupUtils.openCurrentPagePopout(window);
async expand() {
await BrowserPopupUtils.openCurrentPagePopout(window);
}
}

View File

@ -1,23 +0,0 @@
import { Observable } from "rxjs";
import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- extending this class for this client
import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider";
import { DerivedStateDependencies } from "@bitwarden/common/src/types/state";
import { BackgroundDerivedState } from "./background-derived-state";
export class BackgroundDerivedStateProvider extends DefaultDerivedStateProvider {
override buildDerivedState<TFrom, TTo, TDeps extends DerivedStateDependencies>(
parentState$: Observable<TFrom>,
deriveDefinition: DeriveDefinition<TFrom, TTo, TDeps>,
dependencies: TDeps,
): DerivedState<TTo> {
return new BackgroundDerivedState(
parentState$,
deriveDefinition,
deriveDefinition.buildCacheKey(),
dependencies,
);
}
}

View File

@ -1,107 +0,0 @@
import { Observable, Subscription, concatMap } from "rxjs";
import { Jsonify } from "type-fest";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { DeriveDefinition } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- extending this class for this client
import { DefaultDerivedState } from "@bitwarden/common/platform/state/implementations/default-derived-state";
import { DerivedStateDependencies } from "@bitwarden/common/types/state";
import { BrowserApi } from "../browser/browser-api";
export class BackgroundDerivedState<
TFrom,
TTo,
TDeps extends DerivedStateDependencies,
> extends DefaultDerivedState<TFrom, TTo, TDeps> {
private portSubscriptions: Map<chrome.runtime.Port, Subscription> = new Map();
constructor(
parentState$: Observable<TFrom>,
deriveDefinition: DeriveDefinition<TFrom, TTo, TDeps>,
portName: string,
dependencies: TDeps,
) {
super(parentState$, deriveDefinition, dependencies);
// listen for foreground derived states to connect
BrowserApi.addListener(chrome.runtime.onConnect, (port) => {
if (port.name !== portName) {
return;
}
const listenerCallback = this.onMessageFromForeground.bind(this);
port.onDisconnect.addListener(() => {
this.portSubscriptions.get(port)?.unsubscribe();
this.portSubscriptions.delete(port);
port.onMessage.removeListener(listenerCallback);
});
port.onMessage.addListener(listenerCallback);
const stateSubscription = this.state$
.pipe(
concatMap(async (state) => {
await this.sendMessage(
{
action: "nextState",
data: JSON.stringify(state),
id: Utils.newGuid(),
},
port,
);
}),
)
.subscribe();
this.portSubscriptions.set(port, stateSubscription);
});
}
private async onMessageFromForeground(message: DerivedStateMessage, port: chrome.runtime.Port) {
if (message.originator === "background") {
return;
}
switch (message.action) {
case "nextState": {
const dataObj = JSON.parse(message.data) as Jsonify<TTo>;
const data = this.deriveDefinition.deserialize(dataObj);
await this.forceValue(data);
await this.sendResponse(
message,
{
action: "resolve",
},
port,
);
break;
}
}
}
private async sendResponse(
originalMessage: DerivedStateMessage,
response: Omit<DerivedStateMessage, "originator" | "id">,
port: chrome.runtime.Port,
) {
// 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.sendMessage(
{
...response,
id: originalMessage.id,
},
port,
);
}
private async sendMessage(
message: Omit<DerivedStateMessage, "originator">,
port: chrome.runtime.Port,
) {
port.postMessage({
...message,
originator: "background",
});
}
}

View File

@ -1,117 +0,0 @@
/**
* need to update test environment so structuredClone works appropriately
* @jest-environment ../../libs/shared/test.environment.ts
*/
import { NgZone } from "@angular/core";
import { mock } from "jest-mock-extended";
import { Subject, firstValueFrom } from "rxjs";
import { DeriveDefinition } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- needed to define a derive definition
import { StateDefinition } from "@bitwarden/common/platform/state/state-definition";
import { awaitAsync, trackEmissions, ObservableTracker } from "@bitwarden/common/spec";
import { mockPorts } from "../../../spec/mock-port.spec-util";
import { BackgroundDerivedState } from "./background-derived-state";
import { ForegroundDerivedState } from "./foreground-derived-state";
const stateDefinition = new StateDefinition("test", "memory");
const deriveDefinition = new DeriveDefinition(stateDefinition, "test", {
derive: (dateString: string) => (dateString == null ? null : new Date(dateString)),
deserializer: (dateString: string) => (dateString == null ? null : new Date(dateString)),
cleanupDelayMs: 1000,
});
// Mock out the runInsideAngular operator so we don't have to deal with zone.js
jest.mock("../browser/run-inside-angular.operator", () => {
return {
runInsideAngular: (ngZone: any) => (source: any) => source,
};
});
describe("foreground background derived state interactions", () => {
let foreground: ForegroundDerivedState<Date>;
let background: BackgroundDerivedState<string, Date, Record<string, unknown>>;
let parentState$: Subject<string>;
const initialParent = "2020-01-01";
const ngZone = mock<NgZone>();
const portName = "testPort";
beforeEach(() => {
mockPorts();
parentState$ = new Subject<string>();
background = new BackgroundDerivedState(parentState$, deriveDefinition, portName, {});
foreground = new ForegroundDerivedState(deriveDefinition, portName, ngZone);
});
afterEach(() => {
parentState$.complete();
jest.resetAllMocks();
});
it("should connect between foreground and background", async () => {
const foregroundEmissions = trackEmissions(foreground.state$);
const backgroundEmissions = trackEmissions(background.state$);
parentState$.next(initialParent);
await awaitAsync(10);
expect(backgroundEmissions).toEqual([new Date(initialParent)]);
expect(foregroundEmissions).toEqual([new Date(initialParent)]);
});
it("should initialize a late-connected foreground", async () => {
const newForeground = new ForegroundDerivedState(deriveDefinition, portName, ngZone);
const backgroundTracker = new ObservableTracker(background.state$);
parentState$.next(initialParent);
const foregroundTracker = new ObservableTracker(newForeground.state$);
expect(await backgroundTracker.expectEmission()).toEqual(new Date(initialParent));
expect(await foregroundTracker.expectEmission()).toEqual(new Date(initialParent));
});
describe("forceValue", () => {
it("should force the value to the background", async () => {
const dateString = "2020-12-12";
const emissions = trackEmissions(background.state$);
await foreground.forceValue(new Date(dateString));
await awaitAsync();
expect(emissions).toEqual([new Date(dateString)]);
});
it("should not create new ports if already connected", async () => {
// establish port with subscription
trackEmissions(foreground.state$);
const connectMock = chrome.runtime.connect as jest.Mock;
const initialConnectCalls = connectMock.mock.calls.length;
expect(foreground["port"]).toBeDefined();
const newDate = new Date();
await foreground.forceValue(newDate);
await awaitAsync();
expect(connectMock.mock.calls.length).toBe(initialConnectCalls);
expect(await firstValueFrom(background.state$)).toEqual(newDate);
});
it("should create a port if not connected", async () => {
const connectMock = chrome.runtime.connect as jest.Mock;
const initialConnectCalls = connectMock.mock.calls.length;
expect(foreground["port"]).toBeUndefined();
const newDate = new Date();
await foreground.forceValue(newDate);
await awaitAsync();
expect(connectMock.mock.calls.length).toBe(initialConnectCalls + 1);
expect(foreground["port"]).toBeNull();
expect(await firstValueFrom(background.state$)).toEqual(newDate);
});
});
});

View File

@ -1,26 +0,0 @@
import { NgZone } from "@angular/core";
import { Observable } from "rxjs";
import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- extending this class for this client
import { DefaultDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/default-derived-state.provider";
import { DerivedStateDependencies } from "@bitwarden/common/src/types/state";
import { ForegroundDerivedState } from "./foreground-derived-state";
export class ForegroundDerivedStateProvider extends DefaultDerivedStateProvider {
constructor(private ngZone: NgZone) {
super();
}
override buildDerivedState<TFrom, TTo, TDeps extends DerivedStateDependencies>(
_parentState$: Observable<TFrom>,
deriveDefinition: DeriveDefinition<TFrom, TTo, TDeps>,
_dependencies: TDeps,
): DerivedState<TTo> {
return new ForegroundDerivedState(
deriveDefinition,
deriveDefinition.buildCacheKey(),
this.ngZone,
);
}
}

View File

@ -1,61 +0,0 @@
import { NgZone } from "@angular/core";
import { awaitAsync } from "@bitwarden/common/../spec";
import { mock } from "jest-mock-extended";
import { DeriveDefinition } from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- needed to define a derive definition
import { StateDefinition } from "@bitwarden/common/platform/state/state-definition";
import { mockPorts } from "../../../spec/mock-port.spec-util";
import { ForegroundDerivedState } from "./foreground-derived-state";
const stateDefinition = new StateDefinition("test", "memory");
const deriveDefinition = new DeriveDefinition(stateDefinition, "test", {
derive: (dateString: string) => (dateString == null ? null : new Date(dateString)),
deserializer: (dateString: string) => (dateString == null ? null : new Date(dateString)),
cleanupDelayMs: 1,
});
// Mock out the runInsideAngular operator so we don't have to deal with zone.js
jest.mock("../browser/run-inside-angular.operator", () => {
return {
runInsideAngular: (ngZone: any) => (source: any) => source,
};
});
describe("ForegroundDerivedState", () => {
let sut: ForegroundDerivedState<Date>;
const portName = "testPort";
const ngZone = mock<NgZone>();
beforeEach(() => {
mockPorts();
sut = new ForegroundDerivedState(deriveDefinition, portName, ngZone);
});
afterEach(() => {
jest.resetAllMocks();
});
it("should not connect a port until subscribed", async () => {
expect(sut["port"]).toBeUndefined();
const subscription = sut.state$.subscribe();
expect(sut["port"]).toBeDefined();
subscription.unsubscribe();
});
it("should disconnect its port when unsubscribed", async () => {
const subscription = sut.state$.subscribe();
expect(sut["port"]).toBeDefined();
const disconnectSpy = jest.spyOn(sut["port"], "disconnect");
subscription.unsubscribe();
// wait for the cleanup delay
await awaitAsync(deriveDefinition.cleanupDelayMs * 2);
expect(disconnectSpy).toHaveBeenCalled();
expect(sut["port"]).toBeNull();
});
});

View File

@ -1,115 +0,0 @@
import { NgZone } from "@angular/core";
import {
Observable,
ReplaySubject,
defer,
filter,
firstValueFrom,
map,
of,
share,
switchMap,
tap,
timer,
} from "rxjs";
import { Jsonify } from "type-fest";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { DeriveDefinition, DerivedState } from "@bitwarden/common/platform/state";
import { DerivedStateDependencies } from "@bitwarden/common/types/state";
import { fromChromeEvent } from "../browser/from-chrome-event";
import { runInsideAngular } from "../browser/run-inside-angular.operator";
export class ForegroundDerivedState<TTo> implements DerivedState<TTo> {
private port: chrome.runtime.Port;
private backgroundResponses$: Observable<DerivedStateMessage>;
state$: Observable<TTo>;
constructor(
private deriveDefinition: DeriveDefinition<unknown, TTo, DerivedStateDependencies>,
private portName: string,
private ngZone: NgZone,
) {
const latestValueFromPort$ = (port: chrome.runtime.Port) => {
return fromChromeEvent(port.onMessage).pipe(
map(([message]) => message as DerivedStateMessage),
filter((message) => message.originator === "background" && message.action === "nextState"),
map((message) => {
const json = JSON.parse(message.data) as Jsonify<TTo>;
return this.deriveDefinition.deserialize(json);
}),
);
};
this.state$ = defer(() => of(this.initializePort())).pipe(
switchMap(() => latestValueFromPort$(this.port)),
share({
connector: () => new ReplaySubject<TTo>(1),
resetOnRefCountZero: () =>
timer(this.deriveDefinition.cleanupDelayMs).pipe(tap(() => this.tearDownPort())),
}),
runInsideAngular(this.ngZone),
);
}
async forceValue(value: TTo): Promise<TTo> {
let cleanPort = false;
if (this.port == null) {
this.initializePort();
cleanPort = true;
}
await this.delegateToBackground("nextState", value);
if (cleanPort) {
this.tearDownPort();
}
return value;
}
private initializePort() {
if (this.port != null) {
return;
}
this.port = chrome.runtime.connect({ name: this.portName });
this.backgroundResponses$ = fromChromeEvent(this.port.onMessage).pipe(
map(([message]) => message as DerivedStateMessage),
filter((message) => message.originator === "background"),
);
return this.backgroundResponses$;
}
private async delegateToBackground(action: DerivedStateActions, data: TTo): Promise<void> {
const id = Utils.newGuid();
// listen for response before request
const response = firstValueFrom(
this.backgroundResponses$.pipe(filter((message) => message.id === id)),
);
this.sendMessage({
id,
action,
data: JSON.stringify(data),
});
await response;
}
private sendMessage(message: Omit<DerivedStateMessage, "originator">) {
this.port.postMessage({
...message,
originator: "foreground",
});
}
private tearDownPort() {
if (this.port == null) {
return;
}
this.port.disconnect();
this.port = null;
this.backgroundResponses$ = null;
}
}

View File

@ -41,6 +41,7 @@ import { AutofillComponent } from "../autofill/popup/settings/autofill.component
import { ExcludedDomainsComponent } from "../autofill/popup/settings/excluded-domains.component";
import { NotifcationsSettingsComponent } from "../autofill/popup/settings/notifications.component";
import { PremiumComponent } from "../billing/popup/settings/premium.component";
import { PopOutComponent } from "../platform/popup/components/pop-out.component";
import { HeaderComponent } from "../platform/popup/header.component";
import { PopupFooterComponent } from "../platform/popup/layout/popup-footer.component";
import { PopupHeaderComponent } from "../platform/popup/layout/popup-header.component";
@ -81,7 +82,6 @@ import { VaultSettingsComponent } from "../vault/popup/settings/vault-settings.c
import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { PopOutComponent } from "./components/pop-out.component";
import { UserVerificationComponent } from "./components/user-verification.component";
import { ServicesModule } from "./services/services.module";
import { HelpAndFeedbackComponent } from "./settings/help-and-feedback.component";
@ -118,6 +118,7 @@ import "../platform/popup/locales";
AccountComponent,
ButtonModule,
ExportScopeCalloutComponent,
PopOutComponent,
PopupPageComponent,
PopupTabNavigationComponent,
PopupFooterComponent,
@ -157,7 +158,6 @@ import "../platform/popup/locales";
GeneratorComponent,
PasswordGeneratorHistoryComponent,
PasswordHistoryComponent,
PopOutComponent,
PremiumComponent,
RegisterComponent,
SendAddEditComponent,

View File

@ -12,6 +12,7 @@ import {
OBSERVABLE_MEMORY_STORAGE,
SYSTEM_THEME_OBSERVABLE,
SafeInjectionToken,
DEFAULT_VAULT_TIMEOUT,
INTRAPROCESS_MESSAGING_SUBJECT,
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens";
@ -78,8 +79,11 @@ import {
GlobalStateProvider,
StateProvider,
} from "@bitwarden/common/platform/state";
// eslint-disable-next-line import/no-restricted-paths -- Used for dependency injection
import { InlineDerivedStateProvider } from "@bitwarden/common/platform/state/implementations/inline-derived-state";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { UsernameGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/username";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { FolderService as FolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@ -112,7 +116,6 @@ import { BrowserScriptInjectorService } from "../../platform/services/browser-sc
import { DefaultBrowserStateService } from "../../platform/services/default-browser-state.service";
import I18nService from "../../platform/services/i18n.service";
import { ForegroundPlatformUtilsService } from "../../platform/services/platform-utils/foreground-platform-utils.service";
import { ForegroundDerivedStateProvider } from "../../platform/state/foreground-derived-state.provider";
import { BrowserStorageServiceProvider } from "../../platform/storage/browser-storage-service.provider";
import { ForegroundMemoryStorageService } from "../../platform/storage/foreground-memory-storage.service";
import { fromChromeRuntimeMessaging } from "../../platform/utils/from-chrome-runtime-messaging";
@ -160,6 +163,10 @@ const safeProviders: SafeProvider[] = [
safeProvider(DebounceNavigationService),
safeProvider(DialogService),
safeProvider(PopupCloseWarningService),
safeProvider({
provide: DEFAULT_VAULT_TIMEOUT,
useValue: VaultTimeoutStringType.OnRestart,
}),
safeProvider({
provide: APP_INITIALIZER as SafeInjectionToken<() => Promise<void>>,
useFactory: (initService: InitService) => initService.init(),
@ -512,8 +519,8 @@ const safeProviders: SafeProvider[] = [
}),
safeProvider({
provide: DerivedStateProvider,
useClass: ForegroundDerivedStateProvider,
deps: [NgZone],
useClass: InlineDerivedStateProvider,
deps: [],
}),
safeProvider({
provide: AutofillSettingsServiceAbstraction,

View File

@ -118,58 +118,55 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden Parol Meneceri</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Bitwarden evdə və ya işdə olarkən bütün parol, keçid açarı və həssas məlumatlarınızı asanlıqla qoruyur.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
<value>PCMag, WIRED, The Verge, CNET, G2 və daha çoxu tərəfindən ən yaxşı parol meneceri olaraq tanındı!
SECURE YOUR DIGITAL LIFE
Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access.
RƏQƏMSAL HƏYATINIZI GÜVƏNDƏ SAXLAYIN
Hər hesab üçün unikal, güclü parollar yaradıb saxlayaraq rəqəmsal həyatınızı güvəndə saxlatyın və məlumat pozuntularına qarşı qorunun. Hər şeyi yalnız sizin müraciət edə biləcəyiniz ucdan uca şifrələnmiş parol anbarında saxlayın.
ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE
Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions.
DATANIZA HƏR YERDƏN, HƏR CİHAZDAN, İSTƏNİLƏN VAXT MÜRACİƏT EDİN
Limitsiz parolları limitsiz cihazlarda məhdudiyyət olmadan asanlıqla idarə edin, saxlayın, güvənlə qoruyun və paylaşın.
EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE
Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features.
HƏR KƏS İNTERNETDƏ GÜVƏNDƏ QALMAQ ÜÇÜN ALƏTLƏRƏ SAHİB OLMALIDIR
Bitwarden-i heç bir reklam və ya satış datası olmadan ödənişsiz istifadə edin. Bitwarden hesab edir ki, hər kəs internetdə güvəndə qalmaq bacarığına sahib olmalıdır. Premium planlar qabaqcıl özəlliklərə müraciət təklif edir.
EMPOWER YOUR TEAMS WITH BITWARDEN
Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more.
BITWARDEN İLƏ KOMANDALARINIZI GÜCLƏNDİRİN
Komanda və Müəssisələr üçün planlar, professional biznes özəllikləri ilə birgə gəlir. Bəzi nümunələrə SSO inteqrasiyası, öz-özünə sahiblik, kataloq inteqrasiyası və SCIM təqdim etmə, qlobal siyasətlər, API müraciəti, olay jurnalları və daha çoxu daxildir.
Use Bitwarden to secure your workforce and share sensitive information with colleagues.
İş gücünüzün güvənliyini qorumaq və həssas məlumatları həmkarlarınızla paylaşmaq üçün Bitwarden-i istifadə edin.
Bitwarden-i seçmək üçün daha çox səbəb:
Dünya səviyyəli şifrələmə
Parollar, qabaqcıl ucdan uca şifrələmə (AES-256 bit, salted hashtag və PBKDF2 SHA-256) ilə qorunur, beləliklə datanız güvəndə və məxfi qalır.
More reasons to choose Bitwarden:
3-cü tərəf auditləri
Bitwarden, müntəzəm olaraq tanınmış təhlükəsizlik firmaları ilə hərtərəfli üçüncü tərəf təhlükəsizlik auditləri keçirir. Bu illik auditlərə Bitwarden IP-ləri, serverləri və veb tətbiqləri arasında mənbə kodu qiymətləndirmələri və nüfuz testi daxildir.
World-Class Encryption
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private.
3rd-party Audits
Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications.
Advanced 2FA
Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey.
Qabaqcıl 2FA
Giriş məlumatlarınızı üçüncü tərəf autentifikatoru, e-poçtla göndərilən kodlar və ya avadanlıq güvənlik açarı və ya keçid açarı kimi FIDO2 WebAuthn kimlik məlumatları ilə güvəndə saxlayın.
Bitwarden Send
Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure.
Ucdan-uca şifrələmə güvənliyini qoruyarkən və pozuntunu məhdudlaşdırarkən dataları birbaşa başqalarına göndərin.
Built-in Generator
Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy.
Daxili Generator
Ziyarət etdiyiniz hər sayt üçün uzun, mürəkkəb və fərqli parollar və unikal istifadəçi adları yaradın. Əlavə məxfilik üçün e-poçt ləqəb provayderləri ilə inteqrasiya edin.
Global Translations
Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin.
Qlobal Tərcümələr
Bitwarden tərcümələri 60-dan çox dildə mövcuddur, Crowdin vasitəsilə qlobal icma tərəfindən tərcümə edilmişdir.
Cross-Platform Applications
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
Çarpaz Platforma Tətbiqləri
İstənilən brauzerdən, mobil cihazdan və ya masaüstü əməliyyat sistemindən və daha çoxundan Bitwarden Anbarınızdakı həssas dataları güvəndə saxlayın və paylaşın.
Bitwarden secures more than just passwords
End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev!
</value>
Bitwarden parollardan daha çox qoruyur
Bitwarden-nin ucdan-uca şifrələnmiş kimlik məlumatlarını idarəetmə həlləri, təşkilatlara hər şeyi, o cümlədən tərtibatçı sirrlərini və keçid açarı təcrübələrini qorumaq gücü verir. Bitwarden Sirr Meneceri və Bitwarden Passwordless.dev haqqında daha ətraflı öyrənmək üçün Bitwarden.com saytını ziyarət edin!</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Bitwarden evdə və ya işdə olarkən bütün parol, keçid açarı və həssas məlumatlarınızı asanlıqla qoruyur.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Anbarınıza bir neçə cihazdan eyniləşdirərək müraciət edin</value>

View File

@ -118,10 +118,10 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden — управител на пароли</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>У дома, на работа или на път Битуорден защитава всички Ваши пароли, секретни ключове и лична информация.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
@ -169,7 +169,7 @@ End-to-end encrypted credential management solutions from Bitwarden empower orga
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>У дома, на работа или на път Битуорден защитава всички Ваши пароли, секретни ключове и лична информация.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Удобен достъп до трезора, който се синхронизира от всички устройства</value>

View File

@ -118,58 +118,58 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden Adgangskodehåndtering</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Hjemme, på arbejde eller på farten sikrer Bitwarden nemt alle adgangskoder, adgangskort og sensitive oplysninger.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
<value>Anerkendt som den bedste adgangskodehåndtering af PCMag, WIRED, The Verge, CNET, G2 og flere!
SECURE YOUR DIGITAL LIFE
Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access.
SIKR DIT DIGITALE LIV
Sikr dit digitale liv og vær beskyttet mod dataindbrud ved at generere og gemme unikke, stærke adgangskoder til hver konto. Vedligehold alt i en ende-til-ende krypteret adgangskodeboks, som kun du har adgang til.
ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE
Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions.
FÅ ADGANG TIL DATAENE, hvor som helst, når som helst, PÅ ENHVER ENHED
Håndtér, gem, beskyt og del nemt et ubegrænset antal adgangskoder på tværs af et ubegrænset antal enheder uden restriktioner.
EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE
Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features.
ALLE BØR HAVE VÆRKTØJERNE TIL AT KUNNE VÆRE SIKKER ONLINE
Brug Bitwarden gratis uden annoncer eller salgsdata. Bitwarden mener, at alle bør have muligheden for at forblive sikre online. Premium-abonnementer giver adgang til avancerede funktioner.
EMPOWER YOUR TEAMS WITH BITWARDEN
Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more.
STYRK DINE HOLD MED BITWARDEN
Abonnementer til Teams og Enterprise kommer med professionelle forretningsfunktioner, f.eks. SSO-integration, selvhosting, katalogintegration og SCIM-klargøring, globale politikker, API-adgang, hændelseslogfiler og mere.
Use Bitwarden to secure your workforce and share sensitive information with colleagues.
Brug Bitwarden til at sikre arbejdsstyrken og dele sensitive oplysninger med kolleger.
More reasons to choose Bitwarden:
Flere grunde til at vælge Bitwarden:
World-Class Encryption
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private.
Kryptering i verdensklasse
Adgangskoder er beskyttet med avanceret ende-til-ende-kryptering (AES-256 bit, saltet hashtag og PBKDF2 SHA-256), så dataene forbliver sikre og private.
3rd-party Audits
Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications.
Tredjepartsrevisioner
Bitwarden udfører regelmæssigt omfattende tredjeparts sikkerhedsrevisioner med velrenommerede sikkerhedsfirmaer. Disse årlige revisioner inkluderer kildekodevurderinger og penetrationstest på tværs af Bitwarden IP'er, servere og webapplikationer.
Advanced 2FA
Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey.
Avanceret 2FA
Sikre dit login med en tredjepartsgodkendelse, e-mailede koder eller FIDO2 WebAuthn-legitimationsoplysninger, såsom en hardwaresikkerhedsnøgle eller adgangsnøgle.
Bitwarden Send
Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure.
Overfør data direkte til andre, mens ende-til-ende krypteret sikkerhed opretholdes og begrænser eksponeringen.
Built-in Generator
Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy.
Indbygget generator
Opret lange, komplekse og distinkte adgangskoder og unikke brugernavne til hvert websted, som besøges. Integrér med udbydere af e-mailalias for yderligere fortrolighed.
Global Translations
Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin.
Globale oversættelser
Bitwarden-lokaliseringer findes til flere end 60 sprog, oversat af det globale fællesskab via Crowdin.
Cross-Platform Applications
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
Applikationer på tværs af platforme
Sikr og del følsomme data i Bitwarden Vault fra enhver webbrowser, mobilenhed eller computer-OS og mere.
Bitwarden secures more than just passwords
End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev!
Bitwarden sikrer mere end blot adgangskoder
Ende-til-ende krypterede legitimationshåndteringsløsninger fra Bitwarden giver organisationer mulighed for at sikre alt, herunder udviklerhemmeligheder og adgangsnøgleoplevelser. Besøg Bitwarden.com for at læse mere om Bitwarden Secrets Manager og Bitwarden Passwordless.dev!
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Hjemme, på arbejde eller på farten sikrer Bitwarden nemt alle adgangskoder, adgangskort og sensitive oplysninger.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Synkroniser og få adgang til din boks fra flere enheder</value>

View File

@ -118,10 +118,10 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden Xestor de contrasinais</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>En casa, no traballo ou mentres estás a viaxar, Bitwarden protexe doadamente todos os teus contrasinais, chaves de paso, e información sensíbel.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
@ -169,7 +169,7 @@ End-to-end encrypted credential management solutions from Bitwarden empower orga
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>En casa, no traballo ou mentres estás a viaxar, Bitwarden protexe doadamente todos os teus contrasinais, chaves de paso, e información sensíbel.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Sincroniza e accede á túa caixa forte desde múltiples dispositivos</value>

View File

@ -118,10 +118,10 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden - Менеджер паролей</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Дома, на работе или в пути - Bitwarden всегда защитит ваши пароли, passkeys и конфиденциальную информацию.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
@ -169,7 +169,7 @@ End-to-end encrypted credential management solutions from Bitwarden empower orga
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Дома, на работе или в пути - Bitwarden всегда защитит ваши пароли, passkeys и конфиденциальную информацию.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Синхронизация и доступ к хранилищу с нескольких устройств</value>

View File

@ -118,58 +118,58 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Name" xml:space="preserve">
<value>Bitwarden Password Manager</value>
<value>Bitwarden менеджер паролів</value>
</data>
<data name="Summary" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Вдома, на роботі чи в дорозі, Bitwarden захищає ваші паролі, ключі доступу та конфіденційну інформацію.</value>
</data>
<data name="Description" xml:space="preserve">
<value>Recognized as the best password manager by PCMag, WIRED, The Verge, CNET, G2, and more!
<value>Визнаний найкращим менеджером паролів за версією PCMag, WIRED, The Verge, CNET, G2 та інших!
SECURE YOUR DIGITAL LIFE
Secure your digital life and protect against data breaches by generating and saving unique, strong passwords for every account. Maintain everything in an end-to-end encrypted password vault that only you can access.
ЗАХИСТІТЬ СВОЄ ЦИФРОВЕ ЖИТТЯ
Убезпечте своє цифрове життя та захистіться від витоку даних, створивши та зберігши унікальні, надійні паролі для кожного облікового запису. Зберігайте всі дані в наскрізному зашифрованому сховищі паролів, доступ до якого маєте лише ви.
ACCESS YOUR DATA, ANYWHERE, ANYTIME, ON ANY DEVICE
Easily manage, store, secure, and share unlimited passwords across unlimited devices without restrictions.
ОТРИМУВАТИ ДОСТУП ДО СВОЇХ ДАНИХ БУДЬ-ДЕ, БУДЬ-КОЛИ, БУДЬ НА ЯКОМУ ПРИСТРОЇ
Легко керуйте, зберігайте, захищайте та діліться необмеженою кількістю паролів на необмеженій кількості пристроїв без обмежень.
EVERYONE SHOULD HAVE THE TOOLS TO STAY SAFE ONLINE
Utilize Bitwarden for free with no ads or selling data. Bitwarden believes everyone should have the ability to stay safe online. Premium plans offer access to advanced features.
КОЖЕН ПОВИНЕН МАТИ ІНСТРУМЕНТИ, ЩОБ ЗАЛИШАТИСЯ В БЕЗПЕЦІ В ІНТЕРНЕТІ
Користуйтеся Bitwarden безкоштовно, без реклами і без продажу даних. Bitwarden вважає, що кожен повинен мати можливість залишатися в безпеці в Інтернеті. Преміум-плани пропонують доступ до розширених функцій.
EMPOWER YOUR TEAMS WITH BITWARDEN
Plans for Teams and Enterprise come with professional business features. Some examples include SSO integration, self-hosting, directory integration and SCIM provisioning, global policies, API access, event logs, and more.
РОЗШИРЮЙТЕ МОЖЛИВОСТІ СВОЇХ КОМАНД ЗА ДОПОМОГОЮ BITWARDEN
Плани для Команд та Підприємства містять професійні бізнес-функції. Деякі приклади включають інтеграцію SSO, самостійний хостинг, інтеграцію каталогів і забезпечення SCIM, глобальні політики, доступ до API, журнали подій і багато іншого.
Use Bitwarden to secure your workforce and share sensitive information with colleagues.
Використовуйте Bitwarden, щоб захистити своїх співробітників і ділитися конфіденційною інформацією з колегами.
More reasons to choose Bitwarden:
Більше причин вибрати Bitwarden:
World-Class Encryption
Passwords are protected with advanced end-to-end encryption (AES-256 bit, salted hashtag, and PBKDF2 SHA-256) so your data stays secure and private.
Шифрування світового класу
Паролі захищені вдосконаленим наскрізним шифруванням (біт AES-256, солоний хештег і PBKDF2 SHA-256), тому ваші дані залишаються надійно захищеними та конфіденційними.
3rd-party Audits
Bitwarden regularly conducts comprehensive third-party security audits with notable security firms. These annual audits include source code assessments and penetration testing across Bitwarden IPs, servers, and web applications.
Аудит третьої сторони
Bitwarden регулярно проводить комплексні сторонні аудити безпеки з відомими компаніями, що займаються безпекою. Ці щорічні аудити включають оцінку вихідного коду та тестування на проникнення на всіх IP-адресах, серверах і веб-додатках Bitwarden.
Advanced 2FA
Secure your login with a third-party authenticator, emailed codes, or FIDO2 WebAuthn credentials such as a hardware security key or passkey.
Розширений 2FA
Захистіть свій вхід за допомогою стороннього автентифікатора, кодів, надісланих електронною поштою, або облікових даних FIDO2 WebAuthn, наприклад, апаратного ключа безпеки або пароля.
Bitwarden Send
Transmit data directly to others while maintaining end-to-end encrypted security and limiting exposure.
Передавайте дані безпосередньо іншим, зберігаючи при цьому наскрізну зашифровану безпеку та обмежуючи вразливість.
Built-in Generator
Create long, complex, and distinct passwords and unique usernames for every site you visit. Integrate with email alias providers for additional privacy.
Вбудований генератор
Створюйте довгі, складні та відмінні паролі та унікальні імена користувачів для кожного сайту, який ви відвідуєте. Інтеграція з провайдерами псевдонімів електронної пошти для додаткової конфіденційності.
Global Translations
Bitwarden translations exist for more than 60 languages, translated by the global community though Crowdin.
Глобальні переклади
Переклади Bitwarden існують для більш ніж 60 мов, перекладені світовою спільнотою за допомогою Crowdin.
Cross-Platform Applications
Secure and share sensitive data within your Bitwarden Vault from any browser, mobile device, or desktop OS, and more.
Крос-платформні додатки
Захищайте конфіденційні дані у своєму сховищі Bitwarden Vault та діліться ними з будь-якого браузера, мобільного пристрою, настільної операційної системи тощо.
Bitwarden secures more than just passwords
End-to-end encrypted credential management solutions from Bitwarden empower organizations to secure everything, including developer secrets and passkey experiences. Visit Bitwarden.com to learn more about Bitwarden Secrets Manager and Bitwarden Passwordless.dev!
Bitwarden захищає більше, ніж просто паролі
Наскрізні рішення для управління зашифрованими обліковими даними від Bitwarden дозволяють організаціям захистити все, включаючи секрети розробників і досвід роботи з ключами. Відвідайте Bitwarden.com, щоб дізнатися більше про Bitwarden Secrets Manager і Bitwarden Passwordless.dev!
</value>
</data>
<data name="AssetTitle" xml:space="preserve">
<value>At home, at work, or on the go, Bitwarden easily secures all your passwords, passkeys, and sensitive information.</value>
<value>Вдома, на роботі чи в дорозі, Bitwarden захищає ваші паролі, ключі доступу та конфіденційну інформацію.</value>
</data>
<data name="ScreenshotSync" xml:space="preserve">
<value>Синхронізуйте й отримуйте доступ до свого сховища на різних пристроях</value>

View File

@ -71,7 +71,7 @@
"papaparse": "5.4.1",
"proper-lockfile": "4.1.2",
"rxjs": "7.8.1",
"tldts": "6.1.18",
"tldts": "6.1.20",
"zxcvbn": "4.4.2"
}
}

View File

@ -116,6 +116,7 @@ import { SendApiService } from "@bitwarden/common/tools/send/services/send-api.s
import { SendStateProvider } from "@bitwarden/common/tools/send/services/send-state.provider";
import { SendService } from "@bitwarden/common/tools/send/services/send.service";
import { UserId } from "@bitwarden/common/types/guid";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/services/collection.service";
@ -274,7 +275,7 @@ export class Main {
this.secureStorageService = new NodeEnvSecureStorageService(
this.storageService,
this.logService,
() => this.cryptoService,
this.encryptService,
);
this.memoryStorageService = new MemoryStorageService();
@ -410,16 +411,34 @@ export class Main {
const refreshAccessTokenErrorCallback = () => {
throw new Error("Refresh Access token error");
};
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
this.organizationService = new OrganizationService(this.stateProvider);
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
this.accountService,
this.pinService,
this.userDecryptionOptionsService,
this.cryptoService,
this.tokenService,
this.policyService,
this.biometricStateService,
this.stateProvider,
this.logService,
VaultTimeoutStringType.Never, // default vault timeout
);
this.apiService = new NodeApiService(
this.tokenService,
this.platformUtilsService,
this.environmentService,
this.appIdService,
this.stateService,
refreshAccessTokenErrorCallback,
this.logService,
logoutCallback,
this.vaultTimeoutSettingsService,
customUserAgent,
);
@ -464,12 +483,8 @@ export class Main {
this.providerService = new ProviderService(this.stateProvider);
this.organizationService = new OrganizationService(this.stateProvider);
this.organizationUserService = new OrganizationUserServiceImplementation(this.apiService);
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
this.policyApiService = new PolicyApiService(this.policyService, this.apiService);
this.keyConnectorService = new KeyConnectorService(
@ -499,8 +514,6 @@ export class Main {
this.stateService,
);
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
this.devicesApiService = new DevicesApiServiceImplementation(this.apiService);
this.deviceTrustService = new DeviceTrustService(
this.keyGenerationService,
@ -553,6 +566,7 @@ export class Main {
this.userDecryptionOptionsService,
this.globalStateProvider,
this.billingAccountProfileStateService,
this.vaultTimeoutSettingsService,
this.kdfConfigService,
);
@ -600,19 +614,6 @@ export class Main {
const lockedCallback = async (userId?: string) =>
await this.cryptoService.clearStoredUserKey(KeySuffixOptions.Auto);
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
this.accountService,
this.pinService,
this.userDecryptionOptionsService,
this.cryptoService,
this.tokenService,
this.policyService,
this.stateService,
this.biometricStateService,
);
this.userVerificationService = new UserVerificationService(
this.stateService,
this.cryptoService,

View File

@ -58,5 +58,107 @@
},
"errorAssigningTargetFolder": {
"message": "Error assigning target folder."
},
"forwarderError": {
"message": "$SERVICENAME$ error: $ERRORMESSAGE$",
"description": "Reports an error returned by a forwarding service to the user.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Invalid characters in domain name."
}
}
},
"forwarderGeneratedBy": {
"message": "Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen."
},
"forwarderGeneratedByWithWebsite": {
"message": "Website: $WEBSITE$. Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen.",
"placeholders": {
"WEBSITE": {
"content": "$1",
"example": "www.example.com"
}
}
},
"forwaderInvalidToken": {
"message": "Invalid $SERVICENAME$ API token",
"description": "Displayed when the user's API token is empty or rejected by the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwaderInvalidTokenWithMessage": {
"message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$",
"description": "Displayed when the user's API token is rejected by the forwarding service with an error message.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Please verify your email address to continue."
}
}
},
"forwarderNoAccountId": {
"message": "Unable to obtain $SERVICENAME$ masked email account ID.",
"description": "Displayed when the forwarding service fails to return an account ID.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoDomain": {
"message": "Invalid $SERVICENAME$ domain.",
"description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoUrl": {
"message": "Invalid $SERVICENAME$ url.",
"description": "Displayed when the url of the forwarding service wasn't supplied.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownError": {
"message": "Unknown $SERVICENAME$ error occurred.",
"description": "Displayed when the forwarding service failed due to an unknown error.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownForwarder": {
"message": "Unknown forwarder: '$SERVICENAME$'.",
"description": "Displayed when the forwarding service is not supported.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "JustTrust.us"
}
}
}
}

View File

@ -2,12 +2,12 @@ import * as FormData from "form-data";
import { HttpsProxyAgent } from "https-proxy-agent";
import * as fe from "node-fetch";
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { ApiService } from "@bitwarden/common/services/api.service";
(global as any).fetch = fe.default;
@ -22,10 +22,10 @@ export class NodeApiService extends ApiService {
platformUtilsService: PlatformUtilsService,
environmentService: EnvironmentService,
appIdService: AppIdService,
stateService: StateService,
refreshAccessTokenErrorCallback: () => Promise<void>,
logService: LogService,
logoutCallback: () => Promise<void>,
vaultTimeoutSettingsService: VaultTimeoutSettingsService,
customUserAgent: string = null,
) {
super(
@ -33,10 +33,10 @@ export class NodeApiService extends ApiService {
platformUtilsService,
environmentService,
appIdService,
stateService,
refreshAccessTokenErrorCallback,
logService,
logoutCallback,
vaultTimeoutSettingsService,
customUserAgent,
);
}

View File

@ -1,6 +1,6 @@
import { throwError } from "rxjs";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { AbstractStorageService } from "@bitwarden/common/platform/abstractions/storage.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
@ -11,7 +11,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
constructor(
private storageService: AbstractStorageService,
private logService: LogService,
private cryptoService: () => CryptoService,
private encryptService: EncryptService,
) {}
get valuesRequireDeserialization(): boolean {
@ -59,7 +59,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
if (sessionKey == null) {
throw new Error("No session key available.");
}
const encValue = await this.cryptoService().encryptToBytes(
const encValue = await this.encryptService.encryptToBytes(
Utils.fromB64ToArray(plainValue),
sessionKey,
);
@ -78,7 +78,7 @@ export class NodeEnvSecureStorageService implements AbstractStorageService {
}
const encBuf = EncArrayBuffer.fromB64(encValue);
const decValue = await this.cryptoService().decryptFromBytes(encBuf, sessionKey);
const decValue = await this.encryptService.decryptToBytes(encBuf, sessionKey);
if (decValue == null) {
this.logService.info("Failed to decrypt.");
return null;

View File

@ -24,6 +24,11 @@ import { KeySuffixOptions, ThemeType } from "@bitwarden/common/platform/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { ThemeStateService } from "@bitwarden/common/platform/theming/theme-state.service";
import { UserId } from "@bitwarden/common/types/guid";
import {
VaultTimeout,
VaultTimeoutOption,
VaultTimeoutStringType,
} from "@bitwarden/common/types/vault-timeout.type";
import { DialogService } from "@bitwarden/components";
import { SetPinComponent } from "../../auth/components/set-pin.component";
@ -41,7 +46,7 @@ export class SettingsComponent implements OnInit {
protected readonly VaultTimeoutAction = VaultTimeoutAction;
showMinToTray = false;
vaultTimeoutOptions: any[];
vaultTimeoutOptions: VaultTimeoutOption[];
localeOptions: any[];
themeOptions: any[];
clearClipboardOptions: any[];
@ -72,14 +77,14 @@ export class SettingsComponent implements OnInit {
timeout: { hours: number; minutes: number };
action: "lock" | "logOut";
}>;
previousVaultTimeout: number = null;
previousVaultTimeout: VaultTimeout = null;
userHasMasterPassword: boolean;
userHasPinSet: boolean;
form = this.formBuilder.group({
// Security
vaultTimeout: [null as number | null],
vaultTimeout: [null as VaultTimeout | null],
vaultTimeoutAction: [VaultTimeoutAction.Lock],
pin: [null as boolean | null],
biometric: false,
@ -159,24 +164,26 @@ export class SettingsComponent implements OnInit {
this.showDuckDuckGoIntegrationOption = isMac;
this.vaultTimeoutOptions = [
// { name: i18nService.t('immediately'), value: 0 },
{ name: this.i18nService.t("oneMinute"), value: 1 },
{ name: this.i18nService.t("fiveMinutes"), value: 5 },
{ name: this.i18nService.t("fifteenMinutes"), value: 15 },
{ name: this.i18nService.t("thirtyMinutes"), value: 30 },
{ name: this.i18nService.t("oneHour"), value: 60 },
{ name: this.i18nService.t("fourHours"), value: 240 },
{ name: this.i18nService.t("onIdle"), value: -4 },
{ name: this.i18nService.t("onSleep"), value: -3 },
{ name: this.i18nService.t("onIdle"), value: VaultTimeoutStringType.OnIdle },
{ name: this.i18nService.t("onSleep"), value: VaultTimeoutStringType.OnSleep },
];
if (this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop) {
this.vaultTimeoutOptions.push({ name: this.i18nService.t("onLocked"), value: -2 });
this.vaultTimeoutOptions.push({
name: this.i18nService.t("onLocked"),
value: VaultTimeoutStringType.OnLocked,
});
}
this.vaultTimeoutOptions = this.vaultTimeoutOptions.concat([
{ name: this.i18nService.t("onRestart"), value: -1 },
{ name: this.i18nService.t("never"), value: null },
{ name: this.i18nService.t("onRestart"), value: VaultTimeoutStringType.OnRestart },
{ name: this.i18nService.t("never"), value: VaultTimeoutStringType.Never },
]);
const localeOptions: any[] = [];
@ -251,10 +258,14 @@ export class SettingsComponent implements OnInit {
// Load initial values
this.userHasPinSet = await this.pinService.isPinSet(userId);
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
const initialValues = {
vaultTimeout: await this.vaultTimeoutSettingsService.getVaultTimeout(),
vaultTimeout: await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(activeAccount.id),
),
vaultTimeoutAction: await firstValueFrom(
this.vaultTimeoutSettingsService.vaultTimeoutAction$(),
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
),
pin: this.userHasPinSet,
biometric: await this.vaultTimeoutSettingsService.isBiometricLockSet(),
@ -299,7 +310,9 @@ export class SettingsComponent implements OnInit {
this.refreshTimeoutSettings$
.pipe(
switchMap(() => this.vaultTimeoutSettingsService.vaultTimeoutAction$()),
switchMap(() =>
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(activeAccount.id),
),
takeUntil(this.destroy$),
)
.subscribe((action) => {
@ -357,8 +370,8 @@ export class SettingsComponent implements OnInit {
});
}
async saveVaultTimeout(newValue: number) {
if (newValue == null) {
async saveVaultTimeout(newValue: VaultTimeout) {
if (newValue === VaultTimeoutStringType.Never) {
const confirmed = await this.dialogService.openSimpleDialog({
title: { key: "warning" },
content: { key: "neverLockWarning" },
@ -387,7 +400,10 @@ export class SettingsComponent implements OnInit {
this.previousVaultTimeout = this.form.value.vaultTimeout;
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
activeAccount.id,
newValue,
this.form.value.vaultTimeoutAction,
);
@ -418,7 +434,10 @@ export class SettingsComponent implements OnInit {
return;
}
const activeAccount = await firstValueFrom(this.accountService.activeAccount$);
await this.vaultTimeoutSettingsService.setVaultTimeoutOptions(
activeAccount.id,
this.form.value.vaultTimeout,
newValue,
);

View File

@ -43,6 +43,7 @@ import { BiometricStateService } from "@bitwarden/common/platform/biometrics/bio
import { StateEventRunnerService } from "@bitwarden/common/platform/state";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { UserId } from "@bitwarden/common/types/guid";
import { VaultTimeout, VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { InternalFolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@ -66,12 +67,6 @@ const BroadcasterSubscriptionId = "AppComponent";
const IdleTimeout = 60000 * 10; // 10 minutes
const SyncInterval = 6 * 60 * 60 * 1000; // 6 hours
const systemTimeoutOptions = {
onLock: -2,
onSuspend: -3,
onIdle: -4,
};
@Component({
selector: "app-root",
styles: [],
@ -433,13 +428,13 @@ export class AppComponent implements OnInit, OnDestroy {
break;
}
case "systemSuspended":
await this.checkForSystemTimeout(systemTimeoutOptions.onSuspend);
await this.checkForSystemTimeout(VaultTimeoutStringType.OnSleep);
break;
case "systemLocked":
await this.checkForSystemTimeout(systemTimeoutOptions.onLock);
await this.checkForSystemTimeout(VaultTimeoutStringType.OnLocked);
break;
case "systemIdle":
await this.checkForSystemTimeout(systemTimeoutOptions.onIdle);
await this.checkForSystemTimeout(VaultTimeoutStringType.OnIdle);
break;
case "openLoginApproval":
if (message.notificationId != null) {
@ -788,7 +783,7 @@ export class AppComponent implements OnInit, OnDestroy {
}
}
private async checkForSystemTimeout(timeout: number): Promise<void> {
private async checkForSystemTimeout(timeout: VaultTimeout): Promise<void> {
const accounts = await firstValueFrom(this.accountService.accounts$);
for (const userId in accounts) {
if (userId == null) {
@ -805,9 +800,13 @@ export class AppComponent implements OnInit, OnDestroy {
}
}
private async getVaultTimeoutOptions(userId: string): Promise<[number, string]> {
const timeout = await this.stateService.getVaultTimeout({ userId: userId });
const action = await this.stateService.getVaultTimeoutAction({ userId: userId });
private async getVaultTimeoutOptions(userId: string): Promise<[VaultTimeout, string]> {
const timeout = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutByUserId$(userId),
);
const action = await firstValueFrom(
this.vaultTimeoutSettingsService.getVaultTimeoutActionByUserId$(userId),
);
return [timeout, action];
}

View File

@ -14,6 +14,7 @@ import {
SYSTEM_THEME_OBSERVABLE,
SafeInjectionToken,
STATE_FACTORY,
DEFAULT_VAULT_TIMEOUT,
INTRAPROCESS_MESSAGING_SUBJECT,
CLIENT_TYPE,
} from "@bitwarden/angular/services/injection-tokens";
@ -56,6 +57,7 @@ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/s
// eslint-disable-next-line import/no-restricted-paths -- Implementation for memory storage
import { MemoryStorageService as MemoryStorageServiceForStateProviders } from "@bitwarden/common/platform/state/storage/memory-storage.service";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/common/tools/generator/password";
import { VaultTimeoutStringType } from "@bitwarden/common/types/vault-timeout.type";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { DialogService } from "@bitwarden/components";
@ -138,6 +140,10 @@ const safeProviders: SafeProvider[] = [
provide: SUPPORTS_SECURE_STORAGE,
useValue: ELECTRON_SUPPORTS_SECURE_STORAGE,
}),
safeProvider({
provide: DEFAULT_VAULT_TIMEOUT,
useValue: VaultTimeoutStringType.OnRestart,
}),
safeProvider({
provide: I18nServiceAbstraction,
useClass: I18nRendererService,

View File

@ -2141,6 +2141,108 @@
"forwardedEmailDesc": {
"message": "Generate an email alias with an external forwarding service."
},
"forwarderError": {
"message": "$SERVICENAME$ error: $ERRORMESSAGE$",
"description": "Reports an error returned by a forwarding service to the user.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Invalid characters in domain name."
}
}
},
"forwarderGeneratedBy": {
"message": "Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen."
},
"forwarderGeneratedByWithWebsite": {
"message": "Website: $WEBSITE$. Generated by Bitwarden.",
"description": "Displayed with the address on the forwarding service's configuration screen.",
"placeholders": {
"WEBSITE": {
"content": "$1",
"example": "www.example.com"
}
}
},
"forwaderInvalidToken": {
"message": "Invalid $SERVICENAME$ API token",
"description": "Displayed when the user's API token is empty or rejected by the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwaderInvalidTokenWithMessage": {
"message": "Invalid $SERVICENAME$ API token: $ERRORMESSAGE$",
"description": "Displayed when the user's API token is rejected by the forwarding service with an error message.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
},
"errormessage": {
"content": "$2",
"example": "Please verify your email address to continue."
}
}
},
"forwarderNoAccountId": {
"message": "Unable to obtain $SERVICENAME$ masked email account ID.",
"description": "Displayed when the forwarding service fails to return an account ID.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoDomain": {
"message": "Invalid $SERVICENAME$ domain.",
"description": "Displayed when the domain is empty or domain authorization failed at the forwarding service.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderNoUrl": {
"message": "Invalid $SERVICENAME$ url.",
"description": "Displayed when the url of the forwarding service wasn't supplied.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownError": {
"message": "Unknown $SERVICENAME$ error occurred.",
"description": "Displayed when the forwarding service failed due to an unknown error.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "SimpleLogin"
}
}
},
"forwarderUnknownForwarder": {
"message": "Unknown forwarder: '$SERVICENAME$'.",
"description": "Displayed when the forwarding service is not supported.",
"placeholders": {
"servicename": {
"content": "$1",
"example": "JustTrust.us"
}
}
},
"hostname": {
"message": "Hostname",
"description": "Part of a URL."

View File

@ -479,7 +479,7 @@
"message": "El tamaño máximo de archivo es de 500MB."
},
"encryptionKeyMigrationRequired": {
"message": "Encryption key migration required. Please login through the web vault to update your encryption key."
"message": "Se requiere migración de la clave de cifrado. Por favor, inicia sesión a través de la caja fuerte web para actualizar su clave de cifrado."
},
"editedFolder": {
"message": "Carpeta editada"
@ -561,10 +561,10 @@
"message": "¡Tu nueva cuenta ha sido creada! Ahora puedes acceder."
},
"youSuccessfullyLoggedIn": {
"message": "You successfully logged in"
"message": "Has iniciado sesión correctamente"
},
"youMayCloseThisWindow": {
"message": "You may close this window"
"message": "Puedes cerrar esta ventana"
},
"masterPassSent": {
"message": "Te hemos enviado un correo electrónico con la pista de tu contraseña maestra."
@ -801,10 +801,10 @@
"message": "Cambiar contraseña maestra"
},
"continueToWebApp": {
"message": "Continue to web app?"
"message": "¿Continuar a la aplicación web?"
},
"changeMasterPasswordOnWebConfirmation": {
"message": "You can change your master password on the Bitwarden web app."
"message": "Puedes cambiar tu contraseña maestra en la aplicación web de Bitwarden."
},
"fingerprintPhrase": {
"message": "Frase de huella digital",
@ -1090,7 +1090,7 @@
"message": "1GB de espacio en disco cifrado."
},
"premiumSignUpTwoStepOptions": {
"message": "Proprietary two-step login options such as YubiKey and Duo."
"message": "Opciones de inicio de sesión con autenticación de dos pasos propietarios como YubiKey y Duo."
},
"premiumSignUpReports": {
"message": "Higiene de contraseña, salud de la cuenta e informes de violaciones de datos para mantener tu caja fuerte segura."
@ -1402,7 +1402,7 @@
"message": "Código PIN inválido."
},
"tooManyInvalidPinEntryAttemptsLoggingOut": {
"message": "Too many invalid PIN entry attempts. Logging out."
"message": "Demasiados intentos de entrada de PIN no válidos. Cerrando sesión."
},
"unlockWithWindowsHello": {
"message": "Desbloquear con Windows Hello"
@ -1553,11 +1553,11 @@
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"orgRequiresYouToSetPassword": {
"message": "Your organization requires you to set a master password.",
"message": "Tu organización requiere que establezcas una contraseña maestra.",
"description": "Used as a card title description on the set password page to explain why the user is there"
},
"verificationRequired": {
"message": "Verification required",
"message": "Verificación requerida",
"description": "Default title for the user verification dialog."
},
"currentMasterPass": {
@ -1633,10 +1633,10 @@
"message": "La integración con el navegador no está soportada"
},
"browserIntegrationErrorTitle": {
"message": "Error enabling browser integration"
"message": "Error al habilitar la integración del navegador"
},
"browserIntegrationErrorDesc": {
"message": "An error has occurred while enabling browser integration."
"message": "Se ha producido un error mientras se habilitaba la integración del navegador."
},
"browserIntegrationMasOnlyDesc": {
"message": "Por desgracia la integración del navegador sólo está soportada por ahora en la versión de la Mac App Store."
@ -1654,7 +1654,7 @@
"message": "Requiere una capa adicional de seguridad mediante el solicitar la frase de validación de huella dactilar al establecer un enlace entre el escritorio y el navegador. Cuando se activa, requiere intervención del usuario y verificación cada vez que se establece una conexión."
},
"enableHardwareAcceleration": {
"message": "Use hardware acceleration"
"message": "Utilizar aceleración de hardware"
},
"enableHardwareAccelerationDesc": {
"message": "By default this setting is ON. Turn OFF only if you experience graphical issues. Restart is required."
@ -1898,16 +1898,16 @@
"message": "Su contraseña maestra no cumple con una o más de las políticas de su organización. Para acceder a la caja fuerte, debe actualizar su contraseña maestra ahora. Proceder le desconectará de su sesión actual, requiriendo que vuelva a iniciar sesión. Las sesiones activas en otros dispositivos pueden seguir estando activas durante hasta una hora."
},
"tryAgain": {
"message": "Try again"
"message": "Intentar de nuevo"
},
"verificationRequiredForActionSetPinToContinue": {
"message": "Verification required for this action. Set a PIN to continue."
},
"setPin": {
"message": "Set PIN"
"message": "Establecer PIN"
},
"verifyWithBiometrics": {
"message": "Verify with biometrics"
"message": "Verificar biométricamente"
},
"awaitingConfirmation": {
"message": "Awaiting confirmation"

View File

@ -2698,7 +2698,7 @@
"description": "Label indicating the most common import formats"
},
"success": {
"message": "Success"
"message": "Успех"
},
"troubleshooting": {
"message": "Решавање проблема"

View File

@ -4,7 +4,6 @@ import {
} from "@bitwarden/common/platform/models/domain/account";
export class AccountSettings extends BaseAccountSettings {
vaultTimeout = -1; // On Restart
dismissedBiometricRequirePasswordOnStartCallout?: boolean;
}

View File

@ -5,8 +5,8 @@ import { concatMap, firstValueFrom, lastValueFrom, Observable, Subject, takeUnti
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
import { OrganizationApiKeyType, ProviderType } from "@bitwarden/common/admin-console/enums";
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
import { OrganizationApiKeyType, ProviderStatusType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { PlanType } from "@bitwarden/common/billing/enums";
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
@ -70,7 +70,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
private route: ActivatedRoute,
private dialogService: DialogService,
private configService: ConfigService,
private providerService: ProviderApiServiceAbstraction,
private providerService: ProviderService,
) {}
async ngOnInit() {
@ -108,15 +108,18 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
this.loading = true;
this.locale = await firstValueFrom(this.i18nService.locale$);
this.userOrg = await this.organizationService.get(this.organizationId);
if (this.userOrg.hasProvider) {
const provider = await this.providerService.getProvider(this.userOrg.providerId);
const enableConsolidatedBilling = await firstValueFrom(this.enableConsolidatedBilling$);
this.isProviderManaged = provider.type == ProviderType.Msp && enableConsolidatedBilling;
}
if (this.userOrg.canViewSubscription) {
const enableConsolidatedBilling = await firstValueFrom(this.enableConsolidatedBilling$);
const provider = await this.providerService.get(this.userOrg.providerId);
this.isProviderManaged =
enableConsolidatedBilling &&
this.userOrg.hasProvider &&
provider.providerStatus == ProviderStatusType.Billable;
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
this.lineItems = this.sub?.subscription?.items;
if (this.lineItems && this.lineItems.length) {
this.lineItems = this.lineItems
.map((item) => {

Some files were not shown because too many files have changed in this diff Show More