mirror of
https://github.com/bitwarden/browser.git
synced 2024-09-27 04:03:00 +02:00
Merge branch 'main' of https://github.com/bitwarden/clients into PM-4954-migrate-sso-component
This commit is contained in:
commit
854ba52fc1
@ -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",
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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ı."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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": "Грешка при задаването на целева колекция."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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ó."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -2177,6 +2177,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."
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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": "ターゲットコレクションの割り当てに失敗しました。"
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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ą."
|
||||
},
|
||||
|
@ -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ā."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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": "Ошибка при назначении целевой коллекции."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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": "Грешка при додељивању циљне колекције."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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ı."
|
||||
}
|
||||
}
|
||||
|
@ -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": "Помилка призначення цільової збірки."
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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": "分配目标集合时出错。"
|
||||
},
|
||||
|
@ -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."
|
||||
},
|
||||
|
@ -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),
|
||||
),
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Location } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject, firstValueFrom, map, switchMap, takeUntil } from "rxjs";
|
||||
import { Subject, firstValueFrom, map, of, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout-settings.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
@ -49,7 +49,7 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
||||
readonly currentAccount$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((a) =>
|
||||
a == null
|
||||
? null
|
||||
? of(null)
|
||||
: this.authService.activeAccountStatus$.pipe(map((s) => ({ ...a, status: s }))),
|
||||
),
|
||||
);
|
||||
@ -106,12 +106,14 @@ export class AccountSwitcherComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
if (confirmed) {
|
||||
this.messagingService.send("logout", { userId });
|
||||
const result = await this.accountSwitcherService.logoutAccount(userId);
|
||||
// unlocked logout responses need to be navigated out of the account switcher.
|
||||
// other responses will be handled by background and app.component
|
||||
if (result?.status === AuthenticationStatus.Unlocked) {
|
||||
this.location.back();
|
||||
}
|
||||
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["home"]);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { CommonModule, Location } from "@angular/common";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { AvatarModule } from "@bitwarden/components";
|
||||
|
||||
import { AccountSwitcherService, AvailableAccount } from "./services/account-switcher.service";
|
||||
@ -21,9 +21,9 @@ export class AccountComponent {
|
||||
|
||||
constructor(
|
||||
private accountSwitcherService: AccountSwitcherService,
|
||||
private router: Router,
|
||||
private location: Location,
|
||||
private i18nService: I18nService,
|
||||
private logService: LogService,
|
||||
) {}
|
||||
|
||||
get specialAccountAddId() {
|
||||
@ -32,15 +32,19 @@ export class AccountComponent {
|
||||
|
||||
async selectAccount(id: string) {
|
||||
this.loading.emit(true);
|
||||
await this.accountSwitcherService.selectAccount(id);
|
||||
let result;
|
||||
try {
|
||||
result = await this.accountSwitcherService.selectAccount(id);
|
||||
} catch (e) {
|
||||
this.logService.error("Error selecting account", e);
|
||||
}
|
||||
|
||||
if (id === this.specialAccountAddId) {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["home"]);
|
||||
} else {
|
||||
// Navigate out of account switching for unlocked accounts
|
||||
// locked or logged out account statuses are handled by background and app.component
|
||||
if (result?.status === AuthenticationStatus.Unlocked) {
|
||||
this.location.back();
|
||||
}
|
||||
this.loading.emit(false);
|
||||
}
|
||||
|
||||
get status() {
|
||||
|
@ -186,4 +186,35 @@ describe("AccountSwitcherService", () => {
|
||||
expect(removeListenerSpy).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("logout", () => {
|
||||
const userId1 = "1" as UserId;
|
||||
const userId2 = "2" as UserId;
|
||||
it("initiates logout", async () => {
|
||||
let listener: (
|
||||
message: { command: string; userId: UserId; status: AuthenticationStatus },
|
||||
sender: unknown,
|
||||
sendResponse: unknown,
|
||||
) => void;
|
||||
jest.spyOn(chrome.runtime.onMessage, "addListener").mockImplementation((addedListener) => {
|
||||
listener = addedListener;
|
||||
});
|
||||
|
||||
const removeListenerSpy = jest.spyOn(chrome.runtime.onMessage, "removeListener");
|
||||
|
||||
const logoutPromise = accountSwitcherService.logoutAccount(userId1);
|
||||
|
||||
listener(
|
||||
{ command: "switchAccountFinish", userId: userId2, status: AuthenticationStatus.Unlocked },
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
|
||||
const result = await logoutPromise;
|
||||
|
||||
expect(messagingService.send).toHaveBeenCalledWith("logout", { userId: userId1 });
|
||||
expect(result).toEqual({ newUserId: userId2, status: AuthenticationStatus.Unlocked });
|
||||
expect(removeListenerSpy).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -41,7 +41,7 @@ export class AccountSwitcherService {
|
||||
SPECIAL_ADD_ACCOUNT_ID = "addAccount";
|
||||
availableAccounts$: Observable<AvailableAccount[]>;
|
||||
|
||||
switchAccountFinished$: Observable<string>;
|
||||
switchAccountFinished$: Observable<{ userId: UserId; status: AuthenticationStatus }>;
|
||||
|
||||
constructor(
|
||||
private accountService: AccountService,
|
||||
@ -111,11 +111,11 @@ export class AccountSwitcherService {
|
||||
);
|
||||
|
||||
// Create a reusable observable that listens to the switchAccountFinish message and returns the userId from the message
|
||||
this.switchAccountFinished$ = fromChromeEvent<[message: { command: string; userId: string }]>(
|
||||
chrome.runtime.onMessage,
|
||||
).pipe(
|
||||
this.switchAccountFinished$ = fromChromeEvent<
|
||||
[message: { command: string; userId: UserId; status: AuthenticationStatus }]
|
||||
>(chrome.runtime.onMessage).pipe(
|
||||
filter(([message]) => message.command === "switchAccountFinish"),
|
||||
map(([message]) => message.userId),
|
||||
map(([message]) => ({ userId: message.userId, status: message.status })),
|
||||
);
|
||||
}
|
||||
|
||||
@ -127,12 +127,46 @@ export class AccountSwitcherService {
|
||||
if (id === this.SPECIAL_ADD_ACCOUNT_ID) {
|
||||
id = null;
|
||||
}
|
||||
const userId = id as UserId;
|
||||
|
||||
// Creates a subscription to the switchAccountFinished observable but further
|
||||
// filters it to only care about the current userId.
|
||||
const switchAccountFinishedPromise = firstValueFrom(
|
||||
const switchAccountFinishedPromise = this.listenForSwitchAccountFinish(userId);
|
||||
|
||||
// Initiate the actions required to make account switching happen
|
||||
await this.accountService.switchAccount(userId);
|
||||
this.messagingService.send("switchAccount", { userId }); // This message should cause switchAccountFinish to be sent
|
||||
|
||||
// Wait until we receive the switchAccountFinished message
|
||||
return await switchAccountFinishedPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param userId the user id to logout
|
||||
* @returns the userId and status of the that has been switch to due to the logout. null on errors.
|
||||
*/
|
||||
async logoutAccount(
|
||||
userId: UserId,
|
||||
): Promise<{ newUserId: UserId; status: AuthenticationStatus } | null> {
|
||||
// logout creates an account switch to the next up user, which may be null
|
||||
const switchPromise = this.listenForSwitchAccountFinish(null);
|
||||
|
||||
await this.messagingService.send("logout", { userId });
|
||||
|
||||
// wait for account switch to happen, the result will be the new user id and status
|
||||
const result = await switchPromise;
|
||||
return { newUserId: result.userId, status: result.status };
|
||||
}
|
||||
|
||||
// Listens for the switchAccountFinish message and returns the userId from the message
|
||||
// Optionally filters switchAccountFinish to an expected userId
|
||||
private listenForSwitchAccountFinish(
|
||||
expectedUserId: UserId | null,
|
||||
): Promise<{ userId: UserId; status: AuthenticationStatus } | null> {
|
||||
return firstValueFrom(
|
||||
this.switchAccountFinished$.pipe(
|
||||
filter((userId) => userId === id),
|
||||
filter(({ userId }) => (expectedUserId ? userId === expectedUserId : true)),
|
||||
timeout({
|
||||
// Much longer than account switching is expected to take for normal accounts
|
||||
// but the account switching process includes a possible full sync so we need to account
|
||||
@ -143,20 +177,13 @@ export class AccountSwitcherService {
|
||||
throwError(() => new Error(AccountSwitcherService.incompleteAccountSwitchError)),
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
// Initiate the actions required to make account switching happen
|
||||
await this.accountService.switchAccount(id as UserId);
|
||||
this.messagingService.send("switchAccount", { userId: id }); // This message should cause switchAccountFinish to be sent
|
||||
|
||||
// Wait until we recieve the switchAccountFinished message
|
||||
await switchAccountFinishedPromise.catch((err) => {
|
||||
).catch((err) => {
|
||||
if (
|
||||
err instanceof Error &&
|
||||
err.message === AccountSwitcherService.incompleteAccountSwitchError
|
||||
) {
|
||||
this.logService.warning("message 'switchAccount' never responded.");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -3,7 +3,7 @@ import { mock } from "jest-mock-extended";
|
||||
import {
|
||||
AssertCredentialResult,
|
||||
CreateCredentialResult,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
export function createCredentialCreationOptionsMock(
|
||||
customFields: Partial<CredentialCreationOptions> = {},
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -78,6 +78,9 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
||||
import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto-function.service";
|
||||
import { CryptoService as CryptoServiceAbstraction } from "@bitwarden/common/platform/abstractions/crypto.service";
|
||||
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
|
||||
import { Fido2AuthenticatorService as Fido2AuthenticatorServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-authenticator.service.abstraction";
|
||||
import { Fido2ClientService as Fido2ClientServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/platform/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||
import { FileUploadService as FileUploadServiceAbstraction } from "@bitwarden/common/platform/abstractions/file-upload/file-upload.service";
|
||||
import { I18nService as I18nServiceAbstraction } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { KeyGenerationService as KeyGenerationServiceAbstraction } from "@bitwarden/common/platform/abstractions/key-generation.service";
|
||||
@ -97,6 +100,7 @@ import { Message, MessageListener, MessageSender } from "@bitwarden/common/platf
|
||||
// eslint-disable-next-line no-restricted-imports -- Used for dependency creation
|
||||
import { SubjectMessageSender } from "@bitwarden/common/platform/messaging/internal";
|
||||
import { Lazy } from "@bitwarden/common/platform/misc/lazy";
|
||||
import { clearCaches } from "@bitwarden/common/platform/misc/sequentialize";
|
||||
import { GlobalState } from "@bitwarden/common/platform/models/domain/global-state";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import { AppIdService } from "@bitwarden/common/platform/services/app-id.service";
|
||||
@ -105,6 +109,8 @@ import { DefaultConfigService } from "@bitwarden/common/platform/services/config
|
||||
import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service";
|
||||
import { ContainerService } from "@bitwarden/common/platform/services/container.service";
|
||||
import { EncryptServiceImplementation } from "@bitwarden/common/platform/services/cryptography/encrypt.service.implementation";
|
||||
import { Fido2AuthenticatorService } from "@bitwarden/common/platform/services/fido2/fido2-authenticator.service";
|
||||
import { Fido2ClientService } from "@bitwarden/common/platform/services/fido2/fido2-client.service";
|
||||
import { FileUploadService } from "@bitwarden/common/platform/services/file-upload/file-upload.service";
|
||||
import { KeyGenerationService } from "@bitwarden/common/platform/services/key-generation.service";
|
||||
import { MigrationBuilderService } from "@bitwarden/common/platform/services/migration-builder.service";
|
||||
@ -125,6 +131,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";
|
||||
@ -153,11 +160,9 @@ 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";
|
||||
import { Fido2ClientService as Fido2ClientServiceAbstraction } from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction } from "@bitwarden/common/vault/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||
import { CipherFileUploadService as CipherFileUploadServiceAbstraction } from "@bitwarden/common/vault/abstractions/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { InternalFolderService as InternalFolderServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
@ -168,8 +173,6 @@ import { VaultSettingsService as VaultSettingsServiceAbstraction } from "@bitwar
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { CipherService } from "@bitwarden/common/vault/services/cipher.service";
|
||||
import { CollectionService } from "@bitwarden/common/vault/services/collection.service";
|
||||
import { Fido2AuthenticatorService } from "@bitwarden/common/vault/services/fido2/fido2-authenticator.service";
|
||||
import { Fido2ClientService } from "@bitwarden/common/vault/services/fido2/fido2-client.service";
|
||||
import { CipherFileUploadService } from "@bitwarden/common/vault/services/file-upload/cipher-file-upload.service";
|
||||
import { FolderApiService } from "@bitwarden/common/vault/services/folder/folder-api.service";
|
||||
import { FolderService } from "@bitwarden/common/vault/services/folder/folder.service";
|
||||
@ -224,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";
|
||||
@ -495,7 +497,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,
|
||||
@ -581,12 +583,30 @@ 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,
|
||||
this.vaultTimeoutSettingsService,
|
||||
(expired: boolean) => this.logout(expired),
|
||||
);
|
||||
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
|
||||
@ -603,8 +623,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,
|
||||
@ -710,17 +729,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,
|
||||
@ -808,6 +816,7 @@ export default class MainBackground {
|
||||
logoutCallback,
|
||||
this.billingAccountProfileStateService,
|
||||
this.tokenService,
|
||||
this.authService,
|
||||
);
|
||||
this.eventUploadService = new EventUploadService(
|
||||
this.apiService,
|
||||
@ -1056,6 +1065,7 @@ export default class MainBackground {
|
||||
this.stateService,
|
||||
this.notificationsService,
|
||||
this.accountService,
|
||||
this.vaultTimeoutSettingsService,
|
||||
);
|
||||
|
||||
this.usernameGenerationService = new UsernameGenerationService(
|
||||
@ -1172,6 +1182,7 @@ export default class MainBackground {
|
||||
* Switch accounts to indicated userId -- null is no active user
|
||||
*/
|
||||
async switchAccount(userId: UserId) {
|
||||
let nextAccountStatus: AuthenticationStatus;
|
||||
try {
|
||||
const currentlyActiveAccount = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((account) => account?.id)),
|
||||
@ -1179,6 +1190,8 @@ export default class MainBackground {
|
||||
// can be removed once password generation history is migrated to state providers
|
||||
await this.stateService.clearDecryptedData(currentlyActiveAccount);
|
||||
await this.accountService.switchAccount(userId);
|
||||
// Clear sequentialized caches
|
||||
clearCaches();
|
||||
|
||||
if (userId == null) {
|
||||
this.loginEmailService.setRememberEmail(false);
|
||||
@ -1186,11 +1199,12 @@ export default class MainBackground {
|
||||
|
||||
await this.refreshBadge();
|
||||
await this.refreshMenu();
|
||||
await this.overlayBackground.updateOverlayCiphers();
|
||||
await this.overlayBackground?.updateOverlayCiphers(); // null in popup only contexts
|
||||
this.messagingService.send("goHome");
|
||||
return;
|
||||
}
|
||||
|
||||
const status = await this.authService.getAuthStatus(userId);
|
||||
nextAccountStatus = await this.authService.getAuthStatus(userId);
|
||||
const forcePasswordReset =
|
||||
(await firstValueFrom(this.masterPasswordService.forceSetPasswordReason$(userId))) !=
|
||||
ForceSetPasswordReason.None;
|
||||
@ -1198,7 +1212,9 @@ export default class MainBackground {
|
||||
await this.systemService.clearPendingClipboard();
|
||||
await this.notificationsService.updateConnection(false);
|
||||
|
||||
if (status === AuthenticationStatus.Locked) {
|
||||
if (nextAccountStatus === AuthenticationStatus.LoggedOut) {
|
||||
this.messagingService.send("goHome");
|
||||
} else if (nextAccountStatus === AuthenticationStatus.Locked) {
|
||||
this.messagingService.send("locked", { userId: userId });
|
||||
} else if (forcePasswordReset) {
|
||||
this.messagingService.send("update-temp-password", { userId: userId });
|
||||
@ -1206,11 +1222,14 @@ export default class MainBackground {
|
||||
this.messagingService.send("unlocked", { userId: userId });
|
||||
await this.refreshBadge();
|
||||
await this.refreshMenu();
|
||||
await this.overlayBackground.updateOverlayCiphers();
|
||||
await this.overlayBackground?.updateOverlayCiphers(); // null in popup only contexts
|
||||
await this.syncService.fullSync(false);
|
||||
}
|
||||
} finally {
|
||||
this.messagingService.send("switchAccountFinish", { userId: userId });
|
||||
this.messagingService.send("switchAccountFinish", {
|
||||
userId: userId,
|
||||
status: nextAccountStatus,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1231,6 +1250,13 @@ export default class MainBackground {
|
||||
|
||||
await this.eventUploadService.uploadEvents(userBeingLoggedOut);
|
||||
|
||||
const newActiveUser =
|
||||
userBeingLoggedOut === activeUserId
|
||||
? await firstValueFrom(this.accountService.nextUpAccount$.pipe(map((a) => a?.id)))
|
||||
: null;
|
||||
|
||||
await this.switchAccount(newActiveUser);
|
||||
|
||||
// HACK: We shouldn't wait for the authentication status to change but instead subscribe to the
|
||||
// authentication status to do various actions.
|
||||
const logoutPromise = firstValueFrom(
|
||||
@ -1263,12 +1289,7 @@ export default class MainBackground {
|
||||
]);
|
||||
|
||||
//Needs to be checked before state is cleaned
|
||||
const needStorageReseed = await this.needsStorageReseed();
|
||||
|
||||
const newActiveUser =
|
||||
userBeingLoggedOut === activeUserId
|
||||
? await firstValueFrom(this.accountService.nextUpAccount$.pipe(map((a) => a?.id)))
|
||||
: null;
|
||||
const needStorageReseed = await this.needsStorageReseed(userId);
|
||||
|
||||
await this.stateService.clean({ userId: userBeingLoggedOut });
|
||||
await this.accountService.clean(userBeingLoggedOut);
|
||||
@ -1278,16 +1299,10 @@ export default class MainBackground {
|
||||
// HACK: Wait for the user logging outs authentication status to transition to LoggedOut
|
||||
await logoutPromise;
|
||||
|
||||
await this.switchAccount(newActiveUser);
|
||||
if (newActiveUser != null) {
|
||||
// we have a new active user, do not continue tearing down application
|
||||
this.messagingService.send("switchAccountFinish");
|
||||
} else {
|
||||
this.messagingService.send("doneLoggingOut", {
|
||||
expired: expired,
|
||||
userId: userBeingLoggedOut,
|
||||
});
|
||||
}
|
||||
|
||||
if (needStorageReseed) {
|
||||
await this.reseedStorage();
|
||||
@ -1300,16 +1315,16 @@ export default class MainBackground {
|
||||
}
|
||||
await this.refreshBadge();
|
||||
await this.mainContextMenuHandler?.noAccess();
|
||||
// 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.notificationsService.updateConnection(false);
|
||||
await this.notificationsService.updateConnection(false);
|
||||
await this.systemService.clearPendingClipboard();
|
||||
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) {
|
||||
|
@ -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
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -5,6 +5,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,
|
||||
@ -20,7 +24,6 @@ import {
|
||||
PlatformUtilsServiceInitOptions,
|
||||
platformUtilsServiceFactory,
|
||||
} from "./platform-utils-service.factory";
|
||||
import { stateServiceFactory, StateServiceInitOptions } from "./state-service.factory";
|
||||
|
||||
type ApiServiceFactoryOptions = FactoryOptions & {
|
||||
apiServiceOptions: {
|
||||
@ -34,7 +37,7 @@ export type ApiServiceInitOptions = ApiServiceFactoryOptions &
|
||||
PlatformUtilsServiceInitOptions &
|
||||
EnvironmentServiceInitOptions &
|
||||
AppIdServiceInitOptions &
|
||||
StateServiceInitOptions;
|
||||
VaultTimeoutSettingsServiceInitOptions;
|
||||
|
||||
export function apiServiceFactory(
|
||||
cache: { apiService?: AbstractApiService } & CachedServices,
|
||||
@ -50,7 +53,7 @@ export function apiServiceFactory(
|
||||
await platformUtilsServiceFactory(cache, opts),
|
||||
await environmentServiceFactory(cache, opts),
|
||||
await appIdServiceFactory(cache, opts),
|
||||
await stateServiceFactory(cache, opts),
|
||||
await vaultTimeoutSettingsServiceFactory(cache, opts),
|
||||
opts.apiServiceOptions.logoutCallback,
|
||||
opts.apiServiceOptions.customUserAgent,
|
||||
),
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { mergeMap } from "rxjs";
|
||||
import { filter, mergeMap } from "rxjs";
|
||||
|
||||
import {
|
||||
AbstractStorageService,
|
||||
@ -34,6 +34,11 @@ export default abstract class AbstractChromeStorageService
|
||||
|
||||
constructor(protected chromeStorageApi: chrome.storage.StorageArea) {
|
||||
this.updates$ = fromChromeEvent(this.chromeStorageApi.onChanged).pipe(
|
||||
filter(([changes]) => {
|
||||
// Our storage services support changing only one key at a time. If more are changed, it's due to
|
||||
// reseeding storage and we should ignore the changes.
|
||||
return Object.keys(changes).length === 1;
|
||||
}),
|
||||
mergeMap(([changes]) => {
|
||||
return Object.entries(changes).map(([key, change]) => {
|
||||
// The `newValue` property isn't on the StorageChange object
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
@ -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",
|
||||
});
|
||||
}
|
||||
}
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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;
|
||||
}
|
||||
}
|
@ -91,13 +91,9 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
message: this.i18nService.t("loginExpired"),
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["home"]);
|
||||
});
|
||||
this.changeDetectorRef.detectChanges();
|
||||
} else if (msg.command === "authBlocked") {
|
||||
} else if (msg.command === "authBlocked" || msg.command === "goHome") {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["home"]);
|
||||
@ -137,9 +133,6 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
this.router.navigate(["/remove-password"]);
|
||||
} else if (msg.command === "switchAccountFinish") {
|
||||
// TODO: unset loading?
|
||||
// this.loading = false;
|
||||
} else if (msg.command == "update-temp-password") {
|
||||
// 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
|
||||
|
@ -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,
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
AssertCredentialResult,
|
||||
CreateCredentialParams,
|
||||
CreateCredentialResult,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
type SharedFido2ScriptInjectionDetails = {
|
||||
runAt: browser.contentScripts.RegisteredContentScriptOptions["runAt"];
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
CreateCredentialParams,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Fido2ClientService } from "@bitwarden/common/platform/services/fido2/fido2-client.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
import { Fido2ClientService } from "@bitwarden/common/vault/services/fido2/fido2-client.service";
|
||||
|
||||
import { createPortSpyMock } from "../../../autofill/spec/autofill-mocks";
|
||||
import {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { firstValueFrom, startWith } from "rxjs";
|
||||
import { pairwise } from "rxjs/operators";
|
||||
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
AssertCredentialResult,
|
||||
CreateCredentialParams,
|
||||
CreateCredentialResult,
|
||||
Fido2ClientService,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
|
||||
|
||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||
|
@ -16,14 +16,14 @@ import {
|
||||
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { UserRequestedFallbackAbortReason } from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { UserRequestedFallbackAbortReason } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import {
|
||||
Fido2UserInterfaceService as Fido2UserInterfaceServiceAbstraction,
|
||||
Fido2UserInterfaceSession,
|
||||
NewCredentialParams,
|
||||
PickCredentialParams,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-user-interface.service.abstraction";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
|
||||
import { BrowserApi } from "../../platform/browser/browser-api";
|
||||
import { closeFido2Popout, openFido2Popout } from "../popup/utils/vault-popout-window";
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
|
||||
import { CreateCredentialResult } from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { CreateCredentialResult } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
import { createPortSpyMock } from "../../../autofill/spec/autofill-mocks";
|
||||
import { triggerPortOnDisconnectEvent } from "../../../autofill/spec/testing-utils";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {
|
||||
AssertCredentialParams,
|
||||
CreateCredentialParams,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
import { sendExtensionMessage } from "../../../autofill/utils";
|
||||
import { Fido2PortName } from "../enums/fido2-port-name.enum";
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
CreateCredentialResult,
|
||||
AssertCredentialParams,
|
||||
AssertCredentialResult,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
export enum MessageType {
|
||||
CredentialCreationRequest,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FallbackRequestedError } from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { FallbackRequestedError } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
import { Message, MessageType } from "./message";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { FallbackRequestedError } from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { FallbackRequestedError } from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
|
||||
import { WebauthnUtils } from "../webauthn-utils";
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import {
|
||||
CreateCredentialResult,
|
||||
AssertCredentialResult,
|
||||
} from "@bitwarden/common/vault/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { Fido2Utils } from "@bitwarden/common/vault/services/fido2/fido2-utils";
|
||||
} from "@bitwarden/common/platform/abstractions/fido2/fido2-client.service.abstraction";
|
||||
import { Fido2Utils } from "@bitwarden/common/platform/services/fido2/fido2-utils";
|
||||
|
||||
import {
|
||||
InsecureAssertCredentialParams,
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user