diff --git a/core/src/apps/debug/load_device.py b/core/src/apps/debug/load_device.py index 9a80002243..5471142d17 100644 --- a/core/src/apps/debug/load_device.py +++ b/core/src/apps/debug/load_device.py @@ -44,9 +44,8 @@ async def load_device(ctx, msg): needs_backup=msg.needs_backup is True, no_backup=msg.no_backup is True, ) - storage.device.load_settings( - use_passphrase=msg.passphrase_protection, label=msg.label - ) + storage.device.set_passphrase_enabled(msg.passphrase_protection) + storage.device.set_label(msg.label or "") if msg.pin: config.change_pin(pin_to_int(""), pin_to_int(msg.pin), None, None) diff --git a/core/src/apps/management/apply_settings.py b/core/src/apps/management/apply_settings.py index 071b8d9656..93f761ad81 100644 --- a/core/src/apps/management/apply_settings.py +++ b/core/src/apps/management/apply_settings.py @@ -30,20 +30,27 @@ async def apply_settings(ctx: wire.Context, msg: ApplySettings): if len(msg.homescreen) > storage.device.HOMESCREEN_MAXSIZE: raise wire.DataError("Homescreen is too complex") await require_confirm_change_homescreen(ctx) + try: + storage.device.set_homescreen(msg.homescreen) + except ValueError: + raise wire.DataError("Invalid homescreen") if msg.label is not None: await require_confirm_change_label(ctx, msg.label) + storage.device.set_label(msg.label) if msg.use_passphrase is not None: await require_confirm_change_passphrase(ctx, msg.use_passphrase) + storage.device.set_passphrase_enabled(msg.use_passphrase) - if msg.passphrase_always_on_device is not None: + if ( + storage.device.is_passphrase_enabled() + and msg.passphrase_always_on_device is not None + ): await require_confirm_change_passphrase_source( ctx, msg.passphrase_always_on_device ) - - if msg.display_rotation is not None: - await require_confirm_change_display_rotation(ctx, msg.display_rotation) + storage.device.set_passphrase_always_on_device(msg.passphrase_always_on_device) if msg.auto_lock_delay_ms is not None: if msg.auto_lock_delay_ms < storage.device.AUTOLOCK_DELAY_MINIMUM: @@ -51,26 +58,19 @@ async def apply_settings(ctx: wire.Context, msg: ApplySettings): if msg.auto_lock_delay_ms > storage.device.AUTOLOCK_DELAY_MAXIMUM: raise wire.ProcessError("Auto-lock delay too long") await require_confirm_change_autolock_delay(ctx, msg.auto_lock_delay_ms) - - storage.device.load_settings( - label=msg.label, - use_passphrase=msg.use_passphrase, - homescreen=msg.homescreen, - passphrase_always_on_device=msg.passphrase_always_on_device, - display_rotation=msg.display_rotation, - autolock_delay_ms=msg.auto_lock_delay_ms, - ) + storage.device.set_autolock_delay_ms(msg.auto_lock_delay_ms) + # use the value that was stored, not the one that was supplied by the user + workflow.idle_timer.set(storage.device.get_autolock_delay_ms(), lock_device) if msg.unsafe_prompts is not None: await require_confirm_unsafe_prompts(ctx, msg.unsafe_prompts) storage.device.set_unsafe_prompts_allowed(msg.unsafe_prompts) if msg.display_rotation is not None: + await require_confirm_change_display_rotation(ctx, msg.display_rotation) + storage.device.set_rotation(msg.display_rotation) ui.display.orientation(storage.device.get_rotation()) - # use the value that was stored, not the one that was supplied by the user - workflow.idle_timer.set(storage.device.get_autolock_delay_ms(), lock_device) - return Success(message="Settings applied") @@ -117,6 +117,8 @@ async def require_confirm_change_display_rotation(ctx, rotation): label = "south" elif rotation == 270: label = "west" + else: + raise wire.DataError("Unsupported display rotation") text = Text("Change rotation", ui.ICON_CONFIG, new_lines=False) text.normal("Do you really want to", "change display rotation") text.normal("to") @@ -134,7 +136,9 @@ async def require_confirm_change_autolock_delay(ctx, delay_ms): async def require_confirm_unsafe_prompts(ctx, allow: bool) -> None: if allow: text = Text("Unsafe prompts", ui.ICON_WIPE) - text.normal("Trezor will allow you to", "confirm actions which", "might be dangerous.") + text.normal( + "Trezor will allow you to", "confirm actions which", "might be dangerous." + ) text.br_half() text.bold("Allow unsafe prompts?") await require_hold_to_confirm(ctx, text, ButtonRequestType.ProtectCall) diff --git a/core/src/apps/management/recovery_device/__init__.py b/core/src/apps/management/recovery_device/__init__.py index 0757c2c1a7..5d83d532a1 100644 --- a/core/src/apps/management/recovery_device/__init__.py +++ b/core/src/apps/management/recovery_device/__init__.py @@ -58,11 +58,11 @@ async def recovery_device(ctx: wire.Context, msg: RecoveryDevice) -> Success: newpin = await request_pin_confirm(ctx, allow_cancel=False) config.change_pin(pin_to_int(""), pin_to_int(newpin), None, None) + storage.device.set_passphrase_enabled(bool(msg.passphrase_protection)) if msg.u2f_counter is not None: storage.device.set_u2f_counter(msg.u2f_counter) - storage.device.load_settings( - label=msg.label, use_passphrase=msg.passphrase_protection - ) + if msg.label is not None: + storage.device.set_label(msg.label) storage.recovery.set_in_progress(True) storage.recovery.set_dry_run(bool(msg.dry_run)) diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 8f23287522..e94b1b8580 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -75,9 +75,9 @@ async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success: await backup_seed(ctx, msg.backup_type, secret) # write settings and master secret into storage - storage.device.load_settings( - label=msg.label, use_passphrase=msg.passphrase_protection - ) + if msg.label is not None: + storage.device.set_label(msg.label) + storage.device.set_passphrase_enabled(bool(msg.passphrase_protection)) storage.device.store_mnemonic_secret( secret, # for SLIP-39, this is the EMS msg.backup_type, diff --git a/core/src/storage/device.py b/core/src/storage/device.py index b4eabd3ba5..8c7ce34743 100644 --- a/core/src/storage/device.py +++ b/core/src/storage/device.py @@ -85,6 +85,12 @@ def get_rotation() -> int: return int.from_bytes(rotation, "big") +def set_rotation(value: int) -> None: + if value not in (0, 90, 180, 270): + raise ValueError # unsupported display rotation + common.set(_NAMESPACE, _ROTATION, value.to_bytes(2, "big"), True) # public + + def get_label() -> Optional[str]: label = common.get(_NAMESPACE, _LABEL, True) # public if label is None: @@ -92,6 +98,10 @@ def get_label() -> Optional[str]: return label.decode() +def set_label(label: str) -> None: + common.set(_NAMESPACE, _LABEL, label.encode(), True) # public + + def get_mnemonic_secret() -> Optional[bytes]: return common.get(_NAMESPACE, _MNEMONIC_SECRET) @@ -115,10 +125,25 @@ def is_passphrase_enabled() -> bool: return common.get_bool(_NAMESPACE, _USE_PASSPHRASE) +def set_passphrase_enabled(enable: bool) -> None: + common.set_bool(_NAMESPACE, _USE_PASSPHRASE, enable) + if not enable: + set_passphrase_always_on_device(False) + + def get_homescreen() -> Optional[bytes]: return common.get(_NAMESPACE, _HOMESCREEN, True) # public +def set_homescreen(homescreen: bytes) -> None: + if len(homescreen) > HOMESCREEN_MAXSIZE: + raise ValueError # homescreen too large + if homescreen[:8] == b"TOIf\x90\x00\x90\x00" or homescreen == b"": + common.set(_NAMESPACE, _HOMESCREEN, homescreen, True) # public + else: + raise ValueError # invalid homescreen + + def store_mnemonic_secret( secret: bytes, backup_type: EnumTypeBackupType, @@ -164,41 +189,8 @@ def get_passphrase_always_on_device() -> bool: return common.get_bool(_NAMESPACE, _PASSPHRASE_ALWAYS_ON_DEVICE) -def load_settings( - label: str = None, - use_passphrase: bool = None, - homescreen: bytes = None, - passphrase_always_on_device: bool = None, - display_rotation: int = None, - autolock_delay_ms: int = None, -) -> None: - if use_passphrase is False: - passphrase_always_on_device = False - if label is not None: - common.set(_NAMESPACE, _LABEL, label.encode(), True) # public - if use_passphrase is not None: - common.set_bool(_NAMESPACE, _USE_PASSPHRASE, use_passphrase) - if homescreen is not None: - if homescreen[:8] == b"TOIf\x90\x00\x90\x00": - if len(homescreen) <= HOMESCREEN_MAXSIZE: - common.set(_NAMESPACE, _HOMESCREEN, homescreen, True) # public - else: - common.set(_NAMESPACE, _HOMESCREEN, b"", True) # public - if passphrase_always_on_device is not None: - common.set_bool( - _NAMESPACE, _PASSPHRASE_ALWAYS_ON_DEVICE, passphrase_always_on_device - ) - if display_rotation is not None: - if display_rotation not in (0, 90, 180, 270): - raise ValueError( - "Unsupported display rotation degrees: %d" % display_rotation - ) - else: - common.set( - _NAMESPACE, _ROTATION, display_rotation.to_bytes(2, "big"), True - ) # public - if autolock_delay_ms is not None: - set_autolock_delay_ms(autolock_delay_ms) +def set_passphrase_always_on_device(enable: bool) -> None: + common.set_bool(_NAMESPACE, _PASSPHRASE_ALWAYS_ON_DEVICE, enable) def get_flags() -> int: