diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 5fb85b08..39c9276a 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1,518 +1,522 @@ { - "extName": { - "message": "Authenticator", - "description": "Extension Name." - }, - "extShortName": { - "message": "Authenticator", - "description": "Extension Short Name." - }, - "extDesc": { - "message": "Authenticator generates two-factor authentication codes in your browser.", - "description": "Extension Description." - }, - "added": { - "message": " has been added.", - "description": "Added Account." - }, - "errorqr": { - "message": "Unrecognized QR code.", - "description": "QR Error." - }, - "errorsecret": { - "message": "Invalid account secret", - "description": "Secret Error." - }, - "add_code": { - "message": "Add account", - "description": "Add account." - }, - "add_qr": { - "message": "Scan QR Code", - "description": "Scan QR Code." - }, - "add_secret": { - "message": "Manual Entry", - "description": "Manual Entry." - }, - "migration_fail": { - "message": "Import failed. If you are migrating data from Google Authenticator, please re-export your data from Google Authenticator and try again.", - "description": "Import migration data failed." - }, - "migration_partly_fail": { - "message": "Some account data was not imported successfully.", - "description": "Some migration data is broken." - }, - "close": { - "message": "Close", - "description": "Close." - }, - "ok": { - "message": "Ok", - "description": "OK." - }, - "yes": { - "message": "Yes", - "description": "Yes." - }, - "no": { - "message": "No", - "description": "No." - }, - "account": { - "message": "Account", - "description": "Account." - }, - "accountName": { - "message": "Username", - "description": "Account Name." - }, - "issuer": { - "message": "Issuer", - "description": "Issuer." - }, - "secret": { - "message": "Secret", - "description": "Secret." - }, - "updateSuccess": { - "message": "Success.", - "description": "Update Success." - }, - "updateFailure": { - "message": "Failure.", - "description": "Update Failure." - }, - "about": { - "message": "About", - "description": "About." - }, - "settings": { - "message": "Settings", - "description": "Settings." - }, - "security": { - "message": "Security", - "description": "Security." - }, - "current_phrase": { - "message": "Current Password", - "description": "Current Passphrase." - }, - "new_phrase": { - "message": "New Password", - "description": "New Passphrase." - }, - "phrase": { - "message": "Password", - "description": "Passphrase." - }, - "confirm_phrase": { - "message": "Confirm Password", - "description": "Confirm Passphrase." - }, - "confirm_delete": { - "message": "Are you sure you want to delete this account? This action cannot be undone.", - "description": "Remove entry confirmation" - }, - "confirm_delete_all": { - "message": "I understand that all of my data will be irrecoverably deleted.", - "description": "Message that user is required to acknowledge before clearing all data." - }, - "delete_all": { - "message": "Reset Authenticator" - }, - "delete_all_warning": { - "message": "This will delete all of your data and completely reset Authenticator. You will not be able to recover any deleted data! You should consider saving a backup before resetting Authenticator." - }, - "security_warning": { - "message": "This password will be used to encrypt your accounts. No one can help you if you forget the password.", - "description": "Passphrase Warning." - }, - "update": { - "message": "Update", - "description": "Update." - }, - "phrase_incorrect": { - "message": "You cannot add a new account until all accounts are decrypted. Please enter the correct password before continuing.", - "description": "Passphrase Incorrect." - }, - "phrase_incorrect_export": { - "message": "Accounts that were not able to be decrypted will not be included in this backup.", - "description": "Skip Unable-decripted Data." - }, - "phrase_not_match": { - "message": "Password does not match.", - "description": "Passphrase Not Match." - }, - "encrypted": { - "message": "Encrypted", - "description": "Encrypted." - }, - "copied": { - "message": "Copied", - "description": "Copied." - }, - "feedback": { - "message": "Feedback", - "description": "Feedback." - }, - "translate": { - "message": "Translate", - "description": "Translate." - }, - "source": { - "message": "Source Code", - "description": "Source Code." - }, - "passphrase_info": { - "message": "Enter password to decrypt account data.", - "description": "Passphrase Info" - }, - "sync_clock": { - "message": "Sync Clock with Google", - "description": "Sync Clock" - }, - "remember_phrase": { - "message": "Remember Password", - "description": "Remember Passphrase" - }, - "clock_too_far_off": { - "message": "Caution! Your local clock is too far off, please fix it before continuing.", - "description": "Local Time is Too Far Off" - }, - "remind_backup": { - "message": "Do you have a backup for your accounts? Don't wait until it's too late!", - "description": "Remind Backup" - }, - "capture_failed": { - "message": "Capture failed, please reload the page and try again.", - "description": "Capture Failed" - }, - "capture_local_file_failed": { - "message": "Are you trying to scan QR code from a local file? Use Import QR Image Backup instead.", - "description": "Import QR image backup instead of scan local image" - }, - "based_on_time": { - "message": "Time Based", - "description": "Time Based" - }, - "based_on_counter": { - "message": "Counter Based", - "description": "Counter Based" - }, - "resize_popup_page": { - "message": "Preferences", - "description": "Popup Page Settings" - }, - "scale": { - "message": "Scale", - "description": "Scale" - }, - "export_info": { - "message": "Warning: all backups are unencrypted. Want to add an account to another app? Hover over the top right part of any account and hit the hidden button.", - "description": "Export menu info text" - }, - "download_backup": { - "message": "Download Backup File", - "description": "Download backup file." - }, - "import_backup": { - "message": "Import Backup", - "description": "Import backup." - }, - "import_backup_file": { - "message": "Import Backup File", - "description": "Import backup file." - }, - "import_backup_qr": { - "message": "Import QR Image Backup", - "description": "Import qr image backup." - }, - "import_qr_images": { - "message": "Import QR Images", - "description": "Import qr images. Shown as add account method." - }, - "import_backup_code": { - "message": "Import Text Backup", - "description": "Import backup code." - }, - "import_otp_urls": { - "message": "Import OTP URLs", - "description": "Import OTP URLs. Shown as add account method." - }, - "import_backup_qr_partly_failed": { - "message": "Import successful, but some QR codes could not be recognized.", - "description": "Import successful, but some QR image cannot be recognized." - }, - "import_backup_qr_in_batches": { - "message": "You can select multiple files to import backup in batches.", - "description": "You can select multiple image files to import backup in batches." - }, - "show_all_entries": { - "message": "Show all entries", - "description": "Show all entries." - }, - "dropbox_risk": { - "message": "Warning: backups are unencrypted. Use at your own risk.", - "description": "Backup risk warning." - }, - "import_error_password": { - "message": "You must provide correct password to import backups.", - "description": "Error password warning when import backups." - }, - "local_passphrase_warning": { - "message": "Your password is stored locally, please change it in the security menu immediately.", - "description": "localStorage password warning." - }, - "remove": { - "message": "Remove", - "description": "Remove password." - }, - "download_enc_backup": { - "message": "Download Password-Protected Backup", - "description": "Download Encrypted Backup" - }, - "search": { - "message": "Search", - "description": "Search" - }, - "popout": { - "message": "Popup mode", - "description": "Make window turn into persistent popup" - }, - "lock": { - "message": "Lock", - "description": "Lock accounts" - }, - "edit": { - "message": "Edit", - "description": "Edit" - }, - "manual_dropbox": { - "message": "Manual Backup", - "description": "Manual backup" - }, - "use_autofill": { - "message": "Use Autofill", - "description": "Use Autofill" - }, - "use_high_contrast": { - "message": "Use High Contrast", - "description": "Use High Contrast" - }, - "theme": { - "message": "Theme", - "description": "Theme" - }, - "theme_light": { - "message": "Light", - "description": "Light theme" - }, - "theme_dark": { - "message": "Dark", - "description": "Dark theme" - }, - "theme_simple": { - "message": "Simple", - "description": "Simple theme" - }, - "theme_compact": { - "message": "Compact", - "description": "Compact theme" - }, - "theme_high_contrast": { - "message": "High Contrast", - "description": "High Contrast theme" - }, - "theme_flat": { - "message": "Flat", - "description": "Flat theme" - }, - "storage_sync_info": { - "message": "Automatically backup your data to 3rd party storage services.", - "description": "3rd party backup info" - }, - "browser_sync": { - "message": "Browser Sync", - "description": "Storage location" - }, - "sign_in": { - "message": "Sign in", - "description": "Sign in to 3rd party storage services" - }, - "sign_in_business": { - "message": "Sign in (Business)", - "description": "Sign in to 3rd party storage services" - }, - "onedrive_business_perms": { - "message": "Why do business accounts require more permissions?" - }, - "log_out": { - "message": "Logout", - "description": "Sign out of 3rd party storage services" - }, - "token_revoked": { - "message": "There was an issue connecting to your $SERVICE$ account, please sign in again.", - "description": "Error authenticating to backup service. $SERVICE$ will be replaced with a proper noun (E.g.: 'Google Drive' or 'Dropbox')", - "placeholders": { - "service": { - "content": "$1", - "example": "Google Drive" - } - } - }, - "otp_unsupported_warn": { - "message": "You have one or more Steam or Blizzard accounts. Unencrypted backups will not use standardized backup format.", - "description": "Warning if using account that is not supported by standard backup format." - }, - "otp_backup_inform": { - "message": "You can import backups from some other applications.", - "description": "Info text on import page" - }, - "otp_backup_learn": { - "message": "Learn more", - "description": "learn more link on import page. Placed after otp_backup_inform" - }, - "loading": { - "message": "Loading..." - }, - "autolock": { - "message": "Lock after" - }, - "minutes": { - "message": "minutes" - }, - "advanced": { - "message": "Advanced" - }, - "period": { - "message": "Period" - }, - "type": { - "message": "Type" - }, - "invalid": { - "message": "Invalid" - }, - "digits": { - "message": "Digits" - }, - "algorithm": { - "message": "Algorithm" - }, - "smart_filter": { - "message": "Smart Filter" - }, - "backup": { - "message": "Backup" - }, - "backup_file_info": { - "message": "Backup your data to a file." - }, - "password_policy_default_hint": { - "message": "Your password does not meet your organization's security requirements. Contact your administrator for more information." - }, - "advisor": { - "message": "Advisor" - }, - "advisor_insight_password_not_set": { - "message": "Set a password to protect your data." - }, - "advisor_insight_auto_lock_not_set": { - "message": "Enable auto-lock to protect your data." - }, - "advisor_insight_browser_sync_not_enabled": { - "message": "Browser sync is disabled. Enabling it allows accounts to be synced across browsers." - }, - "advisor_insight_auto_fill_not_enabled": { - "message": "Autofill can be enabled to automatically fill codes into websites." - }, - "advisor_insight_smart_filter_not_enabled": { - "message": "Enabling smart filter allows for quick access to accounts." - }, - "show_all_insights": { - "message": "Show all insights." - }, - "no_insight_available": { - "message": "No insights found, everything looks good!" - }, - "danger": { - "message": "Danger" - }, - "warning": { - "message": "Warning" - }, - "info": { - "message": "Info" - }, - "dismiss": { - "message": "Dismiss" - }, - "learn_more": { - "message": "Learn more" - }, - "enable_context_menu": { - "message": "Add to context menu" - }, - "no_entires": { - "message": "No accounts to display. Add your first account now." - }, - "permissions": { - "message": "Permissions" - }, - "permission_revoke": { - "message": "Revoke" - }, - "permission_show_required_permissions": { - "message": "Show non-revocable permissions" - }, - "permission_required": { - "message": "This is a required permission and cannot be revoked." - }, - "permission_active_tab": { - "message": "Access to the current tab to scan QR codes." - }, - "permission_storage": { - "message": "Access to browser storage to store account data." - }, - "permission_identity": { - "message": "Allows sign in to 3rd party storage services." - }, - "permission_alarms": { - "message": "Allows auto-lock to work." - }, - "permission_scripting": { - "message": "Inject scripts into he current tab to scan QR codes and allow auto-fill to work." - }, - "permission_clipboard_write": { - "message": "Grants write-only access to the clipboard to copy codes to clipboard when you click on the account." - }, - "permission_context_menus": { - "message": "Adds Authenticator to context menu." - }, - "permission_sync_clock": { - "message": "Allows clock sync with Google." - }, - "permission_dropbox": { - "message": "Allows backup to Dropbox." - }, - "permission_dropbox_cannot_revoke": { - "message": "You must disable Dropbox backup first." - }, - "permission_drive": { - "message": "Allows backup to Google Drive." - }, - "permission_drive_cannot_revoke": { - "message": "You must disable Google Drive backup first." - }, - "permission_onedrive": { - "message": "Allows backup to OneDrive." - }, - "permission_onedrive_cannot_revoke": { - "message": "You must disable OneDrive backup first." - }, - "permission_unknown_permission": { - "message": "Unknown permission. If see this message, please send a bug report." + "extName": { + "message": "Authenticator", + "description": "Extension Name." + }, + "extShortName": { + "message": "Authenticator", + "description": "Extension Short Name." + }, + "extDesc": { + "message": "Authenticator generates two-factor authentication codes in your browser.", + "description": "Extension Description." + }, + "added": { + "message": " has been added.", + "description": "Added Account." + }, + "errorqr": { + "message": "Unrecognized QR code.", + "description": "QR Error." + }, + "errorsecret": { + "message": "Invalid account secret", + "description": "Secret Error." + }, + "add_code": { + "message": "Add account", + "description": "Add account." + }, + "add_qr": { + "message": "Scan QR Code", + "description": "Scan QR Code." + }, + "add_secret": { + "message": "Manual Entry", + "description": "Manual Entry." + }, + "migration_fail": { + "message": "Import failed. If you are migrating data from Google Authenticator, please re-export your data from Google Authenticator and try again.", + "description": "Import migration data failed." + }, + "migration_partly_fail": { + "message": "Some account data was not imported successfully.", + "description": "Some migration data is broken." + }, + "close": { + "message": "Close", + "description": "Close." + }, + "ok": { + "message": "Ok", + "description": "OK." + }, + "yes": { + "message": "Yes", + "description": "Yes." + }, + "no": { + "message": "No", + "description": "No." + }, + "account": { + "message": "Account", + "description": "Account." + }, + "accountName": { + "message": "Username", + "description": "Account Name." + }, + "issuer": { + "message": "Issuer", + "description": "Issuer." + }, + "secret": { + "message": "Secret", + "description": "Secret." + }, + "updateSuccess": { + "message": "Success.", + "description": "Update Success." + }, + "updateFailure": { + "message": "Failure.", + "description": "Update Failure." + }, + "about": { + "message": "About", + "description": "About." + }, + "settings": { + "message": "Settings", + "description": "Settings." + }, + "security": { + "message": "Security", + "description": "Security." + }, + "current_phrase": { + "message": "Current Password", + "description": "Current Passphrase." + }, + "new_phrase": { + "message": "New Password", + "description": "New Passphrase." + }, + "phrase": { + "message": "Password", + "description": "Passphrase." + }, + "confirm_phrase": { + "message": "Confirm Password", + "description": "Confirm Passphrase." + }, + "confirm_delete": { + "message": "Are you sure you want to delete this account? This action cannot be undone.", + "description": "Remove entry confirmation" + }, + "confirm_delete_all": { + "message": "I understand that all of my data will be irrecoverably deleted.", + "description": "Message that user is required to acknowledge before clearing all data." + }, + "delete_all": { + "message": "Reset Authenticator" + }, + "delete_all_warning": { + "message": "This will delete all of your data and completely reset Authenticator. You will not be able to recover any deleted data! You should consider saving a backup before resetting Authenticator." + }, + "security_warning": { + "message": "This password will be used to encrypt your accounts. No one can help you if you forget the password.", + "description": "Passphrase Warning." + }, + "update": { + "message": "Update", + "description": "Update." + }, + "phrase_incorrect": { + "message": "You cannot add a new account until all accounts are decrypted. Please enter the correct password before continuing.", + "description": "Passphrase Incorrect." + }, + "phrase_incorrect_export": { + "message": "Accounts that were not able to be decrypted will not be included in this backup.", + "description": "Skip Unable-decripted Data." + }, + "phrase_not_match": { + "message": "Password does not match.", + "description": "Passphrase Not Match." + }, + "encrypted": { + "message": "Encrypted", + "description": "Encrypted." + }, + "copied": { + "message": "Copied", + "description": "Copied." + }, + "feedback": { + "message": "Feedback", + "description": "Feedback." + }, + "translate": { + "message": "Translate", + "description": "Translate." + }, + "source": { + "message": "Source Code", + "description": "Source Code." + }, + "passphrase_info": { + "message": "Enter password to decrypt account data.", + "description": "Passphrase Info" + }, + "sync_clock": { + "message": "Sync Clock with Google", + "description": "Sync Clock" + }, + "remember_phrase": { + "message": "Remember Password", + "description": "Remember Passphrase" + }, + "clock_too_far_off": { + "message": "Caution! Your local clock is too far off, please fix it before continuing.", + "description": "Local Time is Too Far Off" + }, + "remind_backup": { + "message": "Do you have a backup for your accounts? Don't wait until it's too late!", + "description": "Remind Backup" + }, + "capture_failed": { + "message": "Capture failed, please reload the page and try again.", + "description": "Capture Failed" + }, + "capture_local_file_failed": { + "message": "Are you trying to scan QR code from a local file? Use Import QR Image Backup instead.", + "description": "Import QR image backup instead of scan local image" + }, + "based_on_time": { + "message": "Time Based", + "description": "Time Based" + }, + "based_on_counter": { + "message": "Counter Based", + "description": "Counter Based" + }, + "resize_popup_page": { + "message": "Preferences", + "description": "Popup Page Settings" + }, + "scale": { + "message": "Scale", + "description": "Scale" + }, + "export_info": { + "message": "Warning: all backups are unencrypted. Want to add an account to another app? Hover over the top right part of any account and hit the hidden button.", + "description": "Export menu info text" + }, + "download_backup": { + "message": "Download Backup File", + "description": "Download backup file." + }, + "import_backup": { + "message": "Import Backup", + "description": "Import backup." + }, + "import_backup_file": { + "message": "Import Backup File", + "description": "Import backup file." + }, + "import_backup_qr": { + "message": "Import QR Image Backup", + "description": "Import qr image backup." + }, + "import_qr_images": { + "message": "Import QR Images", + "description": "Import qr images. Shown as add account method." + }, + "import_backup_code": { + "message": "Import Text Backup", + "description": "Import backup code." + }, + "import_otp_urls": { + "message": "Import OTP URLs", + "description": "Import OTP URLs. Shown as add account method." + }, + "import_backup_qr_partly_failed": { + "message": "Import successful, but some QR codes could not be recognized.", + "description": "Import successful, but some QR image cannot be recognized." + }, + "import_backup_qr_in_batches": { + "message": "You can select multiple files to import backup in batches.", + "description": "You can select multiple image files to import backup in batches." + }, + "show_all_entries": { + "message": "Show all entries", + "description": "Show all entries." + }, + "import_error_password": { + "message": "You must provide correct password to import backups.", + "description": "Error password warning when import backups." + }, + "local_passphrase_warning": { + "message": "Your password is stored locally, please change it in the security menu immediately.", + "description": "localStorage password warning." + }, + "remove": { + "message": "Remove", + "description": "Remove password." + }, + "download_enc_backup": { + "message": "Download Password-Protected Backup", + "description": "Download Encrypted Backup" + }, + "search": { + "message": "Search", + "description": "Search" + }, + "popout": { + "message": "Popup mode", + "description": "Make window turn into persistent popup" + }, + "lock": { + "message": "Lock", + "description": "Lock accounts" + }, + "edit": { + "message": "Edit", + "description": "Edit" + }, + "manual_dropbox": { + "message": "Manual Backup", + "description": "Manual backup" + }, + "use_autofill": { + "message": "Use Autofill", + "description": "Use Autofill" + }, + "use_high_contrast": { + "message": "Use High Contrast", + "description": "Use High Contrast" + }, + "theme": { + "message": "Theme", + "description": "Theme" + }, + "theme_light": { + "message": "Light", + "description": "Light theme" + }, + "theme_dark": { + "message": "Dark", + "description": "Dark theme" + }, + "theme_simple": { + "message": "Simple", + "description": "Simple theme" + }, + "theme_compact": { + "message": "Compact", + "description": "Compact theme" + }, + "theme_high_contrast": { + "message": "High Contrast", + "description": "High Contrast theme" + }, + "theme_flat": { + "message": "Flat", + "description": "Flat theme" + }, + "storage_sync_info": { + "message": "Automatically backup your data to 3rd party storage services.", + "description": "3rd party backup info" + }, + "browser_sync": { + "message": "Browser Sync", + "description": "Storage location" + }, + "sign_in": { + "message": "Sign in", + "description": "Sign in to 3rd party storage services" + }, + "sign_in_business": { + "message": "Sign in (Business)", + "description": "Sign in to 3rd party storage services" + }, + "onedrive_business_perms": { + "message": "Why do business accounts require more permissions?" + }, + "log_out": { + "message": "Logout", + "description": "Sign out of 3rd party storage services" + }, + "token_revoked": { + "message": "There was an issue connecting to your $SERVICE$ account, please sign in again.", + "description": "Error authenticating to backup service. $SERVICE$ will be replaced with a proper noun (E.g.: 'Google Drive' or 'Dropbox')", + "placeholders": { + "service": { + "content": "$1", + "example": "Google Drive" + } } + }, + "otp_unsupported_warn": { + "message": "You have one or more Steam or Blizzard accounts. Unencrypted backups will not use standardized backup format.", + "description": "Warning if using account that is not supported by standard backup format." + }, + "otp_backup_inform": { + "message": "You can import backups from some other applications.", + "description": "Info text on import page" + }, + "otp_backup_learn": { + "message": "Learn more", + "description": "learn more link on import page. Placed after otp_backup_inform" + }, + "loading": { + "message": "Loading..." + }, + "autolock": { + "message": "Lock after" + }, + "minutes": { + "message": "minutes" + }, + "advanced": { + "message": "Advanced" + }, + "period": { + "message": "Period" + }, + "type": { + "message": "Type" + }, + "invalid": { + "message": "Invalid" + }, + "digits": { + "message": "Digits" + }, + "algorithm": { + "message": "Algorithm" + }, + "smart_filter": { + "message": "Smart Filter" + }, + "backup": { + "message": "Backup" + }, + "backup_file_info": { + "message": "Backup your data to a file." + }, + "password_policy_default_hint": { + "message": "Your password does not meet your organization's security requirements. Contact your administrator for more information." + }, + "advisor": { + "message": "Advisor" + }, + "advisor_insight_password_not_set": { + "message": "Set a password to protect your data." + }, + "advisor_insight_auto_lock_not_set": { + "message": "Enable auto-lock to protect your data." + }, + "advisor_insight_browser_sync_not_enabled": { + "message": "Browser sync is disabled. Enabling it allows accounts to be synced across browsers." + }, + "advisor_insight_auto_fill_not_enabled": { + "message": "Autofill can be enabled to automatically fill codes into websites." + }, + "advisor_insight_smart_filter_not_enabled": { + "message": "Enabling smart filter allows for quick access to accounts." + }, + "show_all_insights": { + "message": "Show all insights." + }, + "no_insight_available": { + "message": "No insights found, everything looks good!" + }, + "danger": { + "message": "Danger" + }, + "warning": { + "message": "Warning" + }, + "info": { + "message": "Info" + }, + "dismiss": { + "message": "Dismiss" + }, + "learn_more": { + "message": "Learn more" + }, + "enable_context_menu": { + "message": "Add to context menu" + }, + "no_entires": { + "message": "No accounts to display. Add your first account now." + }, + "permissions": { + "message": "Permissions" + }, + "permission_revoke": { + "message": "Revoke" + }, + "permission_show_required_permissions": { + "message": "Show non-revocable permissions" + }, + "permission_required": { + "message": "This is a required permission and cannot be revoked." + }, + "permission_active_tab": { + "message": "Access to the current tab to scan QR codes." + }, + "permission_storage": { + "message": "Access to browser storage to store account data." + }, + "permission_identity": { + "message": "Allows sign in to 3rd party storage services." + }, + "permission_alarms": { + "message": "Allows auto-lock to work." + }, + "permission_scripting": { + "message": "Inject scripts into he current tab to scan QR codes and allow auto-fill to work." + }, + "permission_clipboard_write": { + "message": "Grants write-only access to the clipboard to copy codes to clipboard when you click on the account." + }, + "permission_context_menus": { + "message": "Adds Authenticator to context menu." + }, + "permission_sync_clock": { + "message": "Allows clock sync with Google." + }, + "permission_dropbox": { + "message": "Allows backup to Dropbox." + }, + "permission_dropbox_cannot_revoke": { + "message": "You must disable Dropbox backup first." + }, + "permission_drive": { + "message": "Allows backup to Google Drive." + }, + "permission_drive_cannot_revoke": { + "message": "You must disable Google Drive backup first." + }, + "permission_onedrive": { + "message": "Allows backup to OneDrive." + }, + "permission_onedrive_cannot_revoke": { + "message": "You must disable OneDrive backup first." + }, + "permission_unknown_permission": { + "message": "Unknown permission. If see this message, please send a bug report." + }, + "encryption_required": { + "message": "Set a password in the security menu to use this feature.", + "description": "Backup risk warning." + }, + "warn_backup_paused": { + "message": "Warning: Cloud backups are paused until a password is set via the security menu.", + "description": "Backup paused warning." + } } diff --git a/src/components/Popup/DrivePage.vue b/src/components/Popup/DrivePage.vue index 351a61bb..22653316 100644 --- a/src/components/Popup/DrivePage.vue +++ b/src/components/Popup/DrivePage.vue @@ -1,29 +1,24 @@ <template> <div> <div> - <div class="text warning" v-show="!isEncrypted || !defaultEncryption"> - {{ i18n.dropbox_risk }} + <div class="text warning" v-show="needEncryption"> + {{ i18n.encryption_required }} </div> <div v-show="backupToken"> <div style="margin: 10px 0px 0px 20px; overflow-wrap: break-word"> {{ i18n.account }} - {{ email }} </div> </div> - <a-select-input - v-show="!!defaultEncryption && backupToken" - :label="i18n.encrypted" - v-model="isEncrypted" - > - <option value="true">{{ i18n.yes }}</option> - <option value="false">{{ i18n.no }}</option> - </a-select-input> <a-button v-show="backupToken" @click="backupLogout()"> {{ i18n.log_out }} </a-button> - <a-button v-show="!backupToken" @click="getBackupToken()"> + <a-button + v-show="!backupToken && !needEncryption" + @click="getBackupToken()" + > {{ i18n.sign_in }} </a-button> - <a-button v-show="backupToken" @click="backupUpload()"> + <a-button v-show="backupToken && !needEncryption" @click="backupUpload()"> {{ i18n.manual_dropbox }} </a-button> </div> @@ -50,25 +45,15 @@ export default Vue.extend({ defaultEncryption: function () { return this.$store.state.accounts.defaultEncryption; }, - isEncrypted: { - get(): boolean { - if (UserSettings.items[`${service}Encrypted`] === null) { - this.$store.commit("backup/setEnc", { service, value: true }); - UserSettings.items[`${service}Encrypted`] = true; - UserSettings.commitItems(); - return true; - } - return this.$store.state.backup.driveEncrypted; - }, - set(newValue: string) { - UserSettings.items.driveEncrypted = newValue === "true"; - UserSettings.commitItems(); - this.$store.commit("backup/setEnc", { service, value: newValue }); - }, + allEntriesEncrypted: function (): boolean { + return this.$store.getters["accounts/allEntriesEncrypted"]; }, - backupToken: function () { + backupToken: function (): string | undefined { return this.$store.state.backup.driveToken; }, + needEncryption: function (): boolean { + return !this.defaultEncryption || !this.allEntriesEncrypted; + }, }, methods: { getBackupToken() { diff --git a/src/components/Popup/DropboxPage.vue b/src/components/Popup/DropboxPage.vue index 030d2d6c..1dd56eeb 100644 --- a/src/components/Popup/DropboxPage.vue +++ b/src/components/Popup/DropboxPage.vue @@ -1,29 +1,24 @@ <template> <div> <div> - <div class="text warning" v-show="!isEncrypted || !defaultEncryption"> - {{ i18n.dropbox_risk }} + <div class="text warning" v-show="needEncryption"> + {{ i18n.encryption_required }} </div> <div v-show="backupToken"> <div style="margin: 10px 0px 0px 20px; overflow-wrap: break-word"> {{ i18n.account }} - {{ email }} </div> </div> - <a-select-input - v-show="!!defaultEncryption && backupToken" - :label="i18n.encrypted" - v-model="isEncrypted" - > - <option value="true">{{ i18n.yes }}</option> - <option value="false">{{ i18n.no }}</option> - </a-select-input> <a-button v-show="backupToken" @click="backupLogout()"> {{ i18n.log_out }} </a-button> - <a-button v-show="!backupToken" @click="getBackupToken()"> + <a-button + v-show="!backupToken && !needEncryption" + @click="getBackupToken()" + > {{ i18n.sign_in }} </a-button> - <a-button v-show="backupToken" @click="backupUpload()"> + <a-button v-show="backupToken && !needEncryption" @click="backupUpload()"> {{ i18n.manual_dropbox }} </a-button> </div> @@ -49,25 +44,15 @@ export default Vue.extend({ defaultEncryption: function () { return this.$store.state.accounts.defaultEncryption; }, - isEncrypted: { - get(): boolean { - if (UserSettings.items[`${service}Encrypted`] === null) { - this.$store.commit("backup/setEnc", { service, value: true }); - UserSettings.items[`${service}Encrypted`] = true; - UserSettings.commitItems(); - return true; - } - return this.$store.state.backup.dropboxEncrypted; - }, - set(newValue: string) { - UserSettings.items.dropboxEncrypted = newValue === "true"; - UserSettings.commitItems(); - this.$store.commit("backup/setEnc", { service, value: newValue }); - }, + allEntriesEncrypted: function (): boolean { + return this.$store.getters["accounts/allEntriesEncrypted"]; }, - backupToken: function () { + backupToken: function (): string | undefined { return this.$store.state.backup.dropboxToken; }, + needEncryption: function (): boolean { + return !this.defaultEncryption || !this.allEntriesEncrypted; + }, }, methods: { getBackupToken() { diff --git a/src/components/Popup/OneDrivePage.vue b/src/components/Popup/OneDrivePage.vue index 8c93fc78..eb679591 100644 --- a/src/components/Popup/OneDrivePage.vue +++ b/src/components/Popup/OneDrivePage.vue @@ -1,39 +1,37 @@ <template> <div> <div> - <div class="text warning" v-show="!isEncrypted || !defaultEncryption"> - {{ i18n.dropbox_risk }} + <div class="text warning" v-show="needEncryption"> + {{ i18n.encryption_required }} </div> <div v-show="backupToken"> <div style="margin: 10px 0px 0px 20px; overflow-wrap: break-word"> {{ i18n.account }} - {{ email }} </div> </div> - <a-select-input - v-show="!!defaultEncryption && backupToken" - :label="i18n.encrypted" - v-model="isEncrypted" - > - <option value="true">{{ i18n.yes }}</option> - <option value="false">{{ i18n.no }}</option> - </a-select-input> <a-button v-show="backupToken" @click="backupLogout()"> {{ i18n.log_out }} </a-button> - <a-button v-show="!backupToken" @click="getBackupToken()"> + <a-button + v-show="!backupToken && !needEncryption" + @click="getBackupToken()" + > {{ i18n.sign_in }} </a-button> - <a-button v-show="!backupToken" @click="getBackupToken(true)"> + <a-button + v-show="!backupToken && !needEncryption" + @click="getBackupToken(true)" + > {{ i18n.sign_in_business }} </a-button> - <div class="text" v-show="!backupToken"> + <div class="text" v-show="!backupToken && !needEncryption"> <a v-on:click="openLink('https://otp.ee/onedriveperms')" href="https://otp.ee/onedriveperms" >{{ i18n.onedrive_business_perms }}</a > </div> - <a-button v-show="backupToken" @click="backupUpload()"> + <a-button v-show="backupToken && !needEncryption" @click="backupUpload()"> {{ i18n.manual_dropbox }} </a-button> </div> @@ -59,23 +57,13 @@ export default Vue.extend({ defaultEncryption: function () { return this.$store.state.accounts.defaultEncryption; }, - isEncrypted: { - get(): boolean { - if (UserSettings.items.oneDriveEncrypted === null) { - this.$store.commit("backup/setEnc", { service, value: true }); - UserSettings.items.oneDriveEncrypted = true; - UserSettings.commitItems(); - return true; - } - return this.$store.state.backup.driveEncrypted; - }, - set(newValue: string) { - UserSettings.items.driveEncrypted = newValue === "true"; - UserSettings.commitItems(); - this.$store.commit("backup/setEnc", { service, value: newValue }); - }, + allEntriesEncrypted: function (): boolean { + return this.$store.getters["accounts/allEntriesEncrypted"]; + }, + needEncryption: function (): boolean { + return !this.defaultEncryption || !this.allEntriesEncrypted; }, - backupToken: function () { + backupToken: function (): string | undefined { return this.$store.state.backup.oneDriveToken; }, }, diff --git a/src/definitions/module-interface.d.ts b/src/definitions/module-interface.d.ts index 49426631..6d224777 100644 --- a/src/definitions/module-interface.d.ts +++ b/src/definitions/module-interface.d.ts @@ -76,6 +76,7 @@ interface AccountsState { keys: OldKey | Key[]; wrongPassword: boolean; initComplete: boolean; + allEntriesEncrypted: boolean; } interface NotificationState { @@ -86,9 +87,6 @@ interface NotificationState { } interface BackupState { - dropboxEncrypted: boolean; - driveEncrypted: boolean; - oneDriveEncrypted: boolean; dropboxToken: boolean; driveToken: boolean; oneDriveToken: boolean; diff --git a/src/models/backup.ts b/src/models/backup.ts index 5484c572..223db3ee 100644 --- a/src/models/backup.ts +++ b/src/models/backup.ts @@ -12,15 +12,7 @@ export class Dropbox implements BackupProvider { async upload(encryption: Encryption) { await UserSettings.updateItems(); - if (UserSettings.items.dropboxEncrypted === undefined) { - // Encrypt by default if user hasn't set yet - UserSettings.items.dropboxEncrypted = true; - UserSettings.commitItems(); - } - const exportData = await EntryStorage.backupGetExport( - encryption, - UserSettings.items.dropboxEncrypted === true - ); + const exportData = await EntryStorage.backupGetExport(encryption, true); const backup = JSON.stringify(exportData, null, 2); const url = "https://content.dropboxapi.com/2/files/upload"; @@ -352,14 +344,8 @@ export class Drive implements BackupProvider { async upload(encryption: Encryption) { await UserSettings.updateItems(); - if (UserSettings.items.driveEncrypted === undefined) { - UserSettings.items.driveEncrypted = true; - UserSettings.commitItems(); - } - const exportData = await EntryStorage.backupGetExport( - encryption, - UserSettings.items.driveEncrypted === true - ); + + const exportData = await EntryStorage.backupGetExport(encryption, true); const backup = JSON.stringify(exportData, null, 2); const token = await this.getToken(); @@ -581,13 +567,8 @@ export class OneDrive implements BackupProvider { async upload(encryption: Encryption) { await UserSettings.updateItems(); - if (UserSettings.items.oneDriveEncrypted === undefined) { - UserSettings.items.oneDriveEncrypted = true; - } - const exportData = await EntryStorage.backupGetExport( - encryption, - UserSettings.items.oneDriveEncrypted === true - ); + + const exportData = await EntryStorage.backupGetExport(encryption, true); const backup = JSON.stringify(exportData, null, 2); const token = await this.getToken(); diff --git a/src/models/settings.ts b/src/models/settings.ts index f40cb2e1..fbf9656a 100644 --- a/src/models/settings.ts +++ b/src/models/settings.ts @@ -5,18 +5,15 @@ export enum StorageLocation { interface UserSettingsData { // local settings - driveEncrypted?: boolean; driveFolder?: string; driveRefreshToken?: string; driveRevoked?: boolean; driveToken?: string; - dropboxEncrypted?: boolean; dropboxRevoked?: boolean; dropboxToken?: string; lastRemindingBackupTime?: number; offset?: number; oneDriveBusiness?: boolean; - oneDriveEncrypted?: boolean; oneDriveRevoked?: boolean; oneDriveRefreshToken?: string; oneDriveToken?: string; @@ -35,18 +32,15 @@ interface UserSettingsData { // Maybe we can have a better way to define this const LocalUserSettingsDataKeys = [ - "driveEncrypted", "driveFolder", "driveRefreshToken", "driveRevoked", "driveToken", - "dropboxEncrypted", "dropboxRevoked", "dropboxToken", "lastRemindingBackupTime", "offset", "oneDriveBusiness", - "oneDriveEncrypted", "oneDriveRevoked", "oneDriveRefreshToken", "oneDriveToken", @@ -70,13 +64,10 @@ export class UserSettings { if ( [ "autofill", - "driveEncrypted", "driveRevoked", - "dropboxEncrypted", "dropboxRevoked", "enableContextMenu", "oneDriveBusiness", - "oneDriveEncrypted", "oneDriveRevoked", "smartFilter", "enableContextMenu", @@ -85,13 +76,10 @@ export class UserSettings { settings[ key as | "autofill" - | "driveEncrypted" | "driveRevoked" - | "dropboxEncrypted" | "dropboxRevoked" | "enableContextMenu" | "oneDriveBusiness" - | "oneDriveEncrypted" | "oneDriveRevoked" | "smartFilter" | "enableContextMenu" diff --git a/src/popup.ts b/src/popup.ts index 173bc033..9f9c4f44 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -201,6 +201,21 @@ async function init() { init(); async function runScheduledBackup(clientTime: number, instance: Vue) { + if (!instance.$store.getters["accounts/allEntriesEncrypted"]) { + // Don't ever upload an unencrypted secret + if ( + instance.$store.state.backup.dropboxToken || + instance.$store.state.backup.driveToken || + instance.$store.state.backup.oneDriveToken + ) { + instance.$store.commit( + "notification/alert", + instance.i18n.warn_backup_paused + ); + } + return; + } + if (instance.$store.state.backup.dropboxToken) { chrome.permissions.contains( { origins: ["https://*.dropboxapi.com/*"] }, diff --git a/src/store/Accounts.ts b/src/store/Accounts.ts index c6e29304..fae87a25 100644 --- a/src/store/Accounts.ts +++ b/src/store/Accounts.ts @@ -75,6 +75,11 @@ export class Accounts implements Module { ); return [...pinnedEntries, ...unpinnedEntries]; }, + allEntriesEncrypted(state: AccountsState) { + return state.entries.every((entry) => { + return Boolean(entry.encryption?.getEncryptionStatus()); + }); + }, }, mutations: { stopFilter(state: AccountsState) { diff --git a/src/store/Backup.ts b/src/store/Backup.ts index 790ed719..5c68a0ec 100644 --- a/src/store/Backup.ts +++ b/src/store/Backup.ts @@ -6,9 +6,6 @@ export class Backup implements Module { return { state: { - dropboxEncrypted: UserSettings.items.dropboxEncrypted === true, - driveEncrypted: UserSettings.items.driveEncrypted === true, - oneDriveEncrypted: UserSettings.items.oneDriveEncrypted === true, dropboxToken: Boolean(UserSettings.items.dropboxToken), driveToken: Boolean(UserSettings.items.driveToken), oneDriveToken: Boolean(UserSettings.items.oneDriveToken), @@ -35,24 +32,6 @@ export class Backup implements Module { break; } }, - setEnc(state: BackupState, args: { service: string; value: boolean }) { - switch (args.service) { - case "dropbox": - state.dropboxEncrypted = args.value; - break; - - case "drive": - state.driveEncrypted = args.value; - break; - - case "onedrive": - state.oneDriveEncrypted = args.value; - break; - - default: - break; - } - }, }, namespaced: true, };