diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 6d755042de..a9020cd999 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -53,6 +53,14 @@ def load_mnemonic(mnemonic: str, needs_backup: bool) -> None: config.set(_APP, _NEEDS_BACKUP, b'') +def needs_backup() -> bool: + return bool(config.get(_APP, _NEEDS_BACKUP)) + + +def set_backed_up() -> None: + config.set(_APP, _NEEDS_BACKUP, b'') + + def load_settings(label: str=None, use_passphrase: bool=None, homescreen: bytes=None) -> None: if label is not None: config.set(_APP, _LABEL, label.encode(), True) # public diff --git a/src/apps/homescreen/homescreen.py b/src/apps/homescreen/homescreen.py index 2ea8beeee4..587442ad94 100644 --- a/src/apps/homescreen/homescreen.py +++ b/src/apps/homescreen/homescreen.py @@ -22,7 +22,12 @@ def display_homescreen(): if not image: image = res.load('apps/homescreen/res/bg.toif') - ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) + if storage.is_initialized() and storage.needs_backup(): + ui.display.bar(0, 0, ui.WIDTH, 30, ui.YELLOW) + ui.display.text_center(120, 22, 'NEEDS BACKUP!', ui.BOLD, ui.BLACK, ui.YELLOW) + ui.display.bar(0, 30, ui.WIDTH, ui.HEIGHT - 30, ui.BG) + else: + ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) ui.display.avatar(48, 48 - 10, image, ui.WHITE, ui.BLACK) ui.display.text_center(120, 220, label, ui.BOLD, ui.FG, ui.BG) diff --git a/src/apps/management/__init__.py b/src/apps/management/__init__.py index 7818b03eca..4c33f953a9 100644 --- a/src/apps/management/__init__.py +++ b/src/apps/management/__init__.py @@ -1,7 +1,7 @@ from trezor.wire import register, protobuf_workflow from trezor.utils import unimport from trezor.messages.wire_types import \ - LoadDevice, ResetDevice, WipeDevice, RecoveryDevice, ApplySettings, ApplyFlags, ChangePin + LoadDevice, ResetDevice, BackupDevice, WipeDevice, RecoveryDevice, ApplySettings, ApplyFlags, ChangePin @unimport @@ -16,6 +16,12 @@ def dispatch_ResetDevice(*args, **kwargs): return reset_device(*args, **kwargs) +@unimport +def dispatch_BackupDevice(*args, **kwargs): + from .backup_device import backup_device + return backup_device(*args, **kwargs) + + @unimport def dispatch_WipeDevice(*args, **kwargs): from .wipe_device import layout_wipe_device @@ -51,6 +57,7 @@ def boot(): if __debug__: register(LoadDevice, protobuf_workflow, dispatch_LoadDevice) register(ResetDevice, protobuf_workflow, dispatch_ResetDevice) + register(BackupDevice, protobuf_workflow, dispatch_BackupDevice) register(WipeDevice, protobuf_workflow, dispatch_WipeDevice) register(RecoveryDevice, protobuf_workflow, dispatch_RecoveryDevice) register(ApplySettings, protobuf_workflow, dispatch_ApplySettings) diff --git a/src/apps/management/backup_device.py b/src/apps/management/backup_device.py new file mode 100644 index 0000000000..a3c288a48a --- /dev/null +++ b/src/apps/management/backup_device.py @@ -0,0 +1,30 @@ +from trezor import ui, wire +from trezor.messages.FailureType import ProcessError +from trezor.messages.Success import Success +from apps.common import storage +from apps.management.reset_device import show_warning, show_mnemonic, check_mnemonic, show_wrong_entry + + +@ui.layout +async def backup_device(ctx, msg): + + if not storage.is_initialized(): + raise wire.FailureError(ProcessError, 'Device is not initialized') + + if not storage.needs_backup(): + raise wire.FailureError(ProcessError, 'Seed already backed up') + + mnemonic = storage.get_mnemonic() + + storage.set_backed_up() + + # warn user about mnemonic safety + await show_warning(ctx) + while True: + # show mnemonic and require confirmation of a random word + await show_mnemonic(ctx, mnemonic) + if await check_mnemonic(ctx, mnemonic): + break + await show_wrong_entry(ctx) + + return Success(message='Seed successfully backed up') diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 0dfdab996b..0a2314a393 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -80,7 +80,8 @@ async def reset_device(ctx, msg): mnemonic=mnemonic, needs_backup=msg.skip_backup) # show success message - await show_success(ctx) + if not msg.skip_backup: + await show_success(ctx) return Success(message='Initialized')