You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
9.4 KiB
282 lines
9.4 KiB
from typing import TYPE_CHECKING
|
|
|
|
import storage.device as storage_device
|
|
import trezorui2
|
|
from trezor import TR
|
|
from trezor import utils
|
|
from trezor.enums import ButtonRequestType
|
|
from trezor.ui import display, style
|
|
from trezor.ui.layouts import confirm_action, request_number_slider
|
|
from trezor.wire import DataError
|
|
|
|
if TYPE_CHECKING:
|
|
from trezor.enums import SafetyCheckLevel
|
|
from trezor.messages import ApplySettings, Success
|
|
|
|
|
|
BRT_PROTECT_CALL = ButtonRequestType.ProtectCall # CACHE
|
|
|
|
|
|
def _validate_homescreen(homescreen: bytes) -> None:
|
|
import storage.device as storage_device
|
|
|
|
if homescreen == b"":
|
|
return
|
|
|
|
if len(homescreen) > storage_device.HOMESCREEN_MAXSIZE:
|
|
raise DataError(
|
|
f"Homescreen is too large, maximum size is {storage_device.HOMESCREEN_MAXSIZE} bytes"
|
|
)
|
|
if not trezorui2.check_homescreen_format(homescreen):
|
|
raise DataError("Wrong homescreen format")
|
|
|
|
|
|
async def apply_settings(msg: ApplySettings) -> Success:
|
|
from trezor.messages import Success
|
|
from trezor.wire import NotInitialized, ProcessError
|
|
|
|
from apps.base import reload_settings_from_storage
|
|
from apps.common import safety_checks
|
|
|
|
if not storage_device.is_initialized():
|
|
raise NotInitialized("Device is not initialized")
|
|
|
|
homescreen = msg.homescreen # local_cache_attribute
|
|
label = msg.label # local_cache_attribute
|
|
auto_lock_delay_ms = msg.auto_lock_delay_ms # local_cache_attribute
|
|
use_passphrase = msg.use_passphrase # local_cache_attribute
|
|
passphrase_always_on_device = (
|
|
msg.passphrase_always_on_device
|
|
) # local_cache_attribute
|
|
display_rotation = msg.display_rotation # local_cache_attribute
|
|
msg_safety_checks = msg.safety_checks # local_cache_attribute
|
|
experimental_features = msg.experimental_features # local_cache_attribute
|
|
hide_passphrase_from_host = msg.hide_passphrase_from_host # local_cache_attribute
|
|
brightness = msg.brightness
|
|
|
|
if (
|
|
homescreen is None
|
|
and label is None
|
|
and use_passphrase is None
|
|
and passphrase_always_on_device is None
|
|
and display_rotation is None
|
|
and auto_lock_delay_ms is None
|
|
and msg_safety_checks is None
|
|
and experimental_features is None
|
|
and hide_passphrase_from_host is None
|
|
and (brightness is None or not utils.USE_BACKLIGHT)
|
|
):
|
|
raise ProcessError("No setting provided")
|
|
|
|
if homescreen is not None:
|
|
_validate_homescreen(homescreen)
|
|
await _require_confirm_change_homescreen(homescreen)
|
|
try:
|
|
storage_device.set_homescreen(homescreen)
|
|
except ValueError:
|
|
raise DataError("Invalid homescreen")
|
|
|
|
if label is not None:
|
|
if len(label) > storage_device.LABEL_MAXLENGTH:
|
|
raise DataError("Label too long")
|
|
await _require_confirm_change_label(label)
|
|
storage_device.set_label(label)
|
|
|
|
if use_passphrase is not None:
|
|
await _require_confirm_change_passphrase(use_passphrase)
|
|
storage_device.set_passphrase_enabled(use_passphrase)
|
|
|
|
if passphrase_always_on_device is not None:
|
|
if not storage_device.is_passphrase_enabled():
|
|
raise DataError("Passphrase is not enabled")
|
|
await _require_confirm_change_passphrase_source(passphrase_always_on_device)
|
|
storage_device.set_passphrase_always_on_device(passphrase_always_on_device)
|
|
|
|
if auto_lock_delay_ms is not None:
|
|
if auto_lock_delay_ms < storage_device.AUTOLOCK_DELAY_MINIMUM:
|
|
raise ProcessError("Auto-lock delay too short")
|
|
if auto_lock_delay_ms > storage_device.AUTOLOCK_DELAY_MAXIMUM:
|
|
raise ProcessError("Auto-lock delay too long")
|
|
await _require_confirm_change_autolock_delay(auto_lock_delay_ms)
|
|
storage_device.set_autolock_delay_ms(auto_lock_delay_ms)
|
|
|
|
if msg_safety_checks is not None:
|
|
await _require_confirm_safety_checks(msg_safety_checks)
|
|
safety_checks.apply_setting(msg_safety_checks)
|
|
|
|
if display_rotation is not None:
|
|
await _require_confirm_change_display_rotation(display_rotation)
|
|
storage_device.set_rotation(display_rotation)
|
|
|
|
if experimental_features is not None:
|
|
await _require_confirm_experimental_features(experimental_features)
|
|
storage_device.set_experimental_features(experimental_features)
|
|
|
|
if hide_passphrase_from_host is not None:
|
|
if safety_checks.is_strict():
|
|
raise ProcessError("Safety checks are strict")
|
|
await _require_confirm_hide_passphrase_from_host(hide_passphrase_from_host)
|
|
storage_device.set_hide_passphrase_from_host(hide_passphrase_from_host)
|
|
|
|
if brightness is not None and utils.USE_BACKLIGHT:
|
|
new_brightness = await _require_set_brightness()
|
|
storage_device.set_brightness(new_brightness)
|
|
|
|
reload_settings_from_storage()
|
|
|
|
return Success(message="Settings applied")
|
|
|
|
|
|
async def _require_confirm_change_homescreen(homescreen: bytes) -> None:
|
|
from trezor.ui.layouts import confirm_homescreen
|
|
|
|
await confirm_homescreen(homescreen)
|
|
|
|
|
|
async def _require_confirm_change_label(label: str) -> None:
|
|
from trezor.ui.layouts import confirm_single
|
|
|
|
await confirm_single(
|
|
"set_label",
|
|
TR.device_name__title,
|
|
description=TR.device_name__change_template,
|
|
description_param=label,
|
|
verb=TR.buttons__change,
|
|
)
|
|
|
|
|
|
async def _require_confirm_change_passphrase(use: bool) -> None:
|
|
description = TR.passphrase__turn_on if use else TR.passphrase__turn_off
|
|
verb = TR.buttons__turn_on if use else TR.buttons__turn_off
|
|
await confirm_action(
|
|
"set_passphrase",
|
|
TR.passphrase__title_settings,
|
|
description=description,
|
|
verb=verb,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
async def _require_confirm_change_passphrase_source(
|
|
passphrase_always_on_device: bool,
|
|
) -> None:
|
|
description = (
|
|
TR.passphrase__always_on_device
|
|
if passphrase_always_on_device
|
|
else TR.passphrase__revoke_on_device
|
|
)
|
|
await confirm_action(
|
|
"set_passphrase_source",
|
|
TR.passphrase__title_source,
|
|
description=description,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
async def _require_confirm_change_display_rotation(rotation: int) -> None:
|
|
if rotation == 0:
|
|
label = TR.rotation__north
|
|
elif rotation == 90:
|
|
label = TR.rotation__east
|
|
elif rotation == 180:
|
|
label = TR.rotation__south
|
|
elif rotation == 270:
|
|
label = TR.rotation__west
|
|
else:
|
|
raise DataError("Unsupported display rotation")
|
|
|
|
await confirm_action(
|
|
"set_rotation",
|
|
TR.rotation__title_change,
|
|
description=TR.rotation__change_template,
|
|
description_param=label,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
async def _require_confirm_change_autolock_delay(delay_ms: int) -> None:
|
|
from trezor.strings import format_duration_ms
|
|
|
|
unit_plurals = {
|
|
"millisecond": TR.plurals__lock_after_x_milliseconds,
|
|
"second": TR.plurals__lock_after_x_seconds,
|
|
"minute": TR.plurals__lock_after_x_minutes,
|
|
"hour": TR.plurals__lock_after_x_hours,
|
|
}
|
|
|
|
await confirm_action(
|
|
"set_autolock_delay",
|
|
TR.auto_lock__title,
|
|
description=TR.auto_lock__change_template,
|
|
description_param=format_duration_ms(delay_ms, unit_plurals),
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
async def _require_confirm_safety_checks(level: SafetyCheckLevel) -> None:
|
|
from trezor.enums import SafetyCheckLevel
|
|
|
|
if level == SafetyCheckLevel.Strict:
|
|
await confirm_action(
|
|
"set_safety_checks",
|
|
TR.safety_checks__title,
|
|
description=TR.safety_checks__enforce_strict,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
elif level in (SafetyCheckLevel.PromptAlways, SafetyCheckLevel.PromptTemporarily):
|
|
description = (
|
|
TR.safety_checks__approve_unsafe_temporary
|
|
if level == SafetyCheckLevel.PromptTemporarily
|
|
else TR.safety_checks__approve_unsafe_always
|
|
)
|
|
await confirm_action(
|
|
"set_safety_checks",
|
|
TR.safety_checks__title_safety_override,
|
|
TR.words__are_you_sure,
|
|
description,
|
|
hold=True,
|
|
verb=TR.buttons__hold_to_confirm,
|
|
reverse=True,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
else:
|
|
raise ValueError # enum value out of range
|
|
|
|
|
|
async def _require_confirm_experimental_features(enable: bool) -> None:
|
|
if enable:
|
|
await confirm_action(
|
|
"set_experimental_features",
|
|
TR.experimental_mode__title,
|
|
TR.experimental_mode__only_for_dev,
|
|
TR.experimental_mode__enable,
|
|
reverse=True,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
async def _require_confirm_hide_passphrase_from_host(enable: bool) -> None:
|
|
if enable:
|
|
await confirm_action(
|
|
"set_hide_passphrase_from_host",
|
|
TR.passphrase__title_hide,
|
|
description=TR.passphrase__hide,
|
|
br_code=BRT_PROTECT_CALL,
|
|
)
|
|
|
|
|
|
if utils.USE_BACKLIGHT:
|
|
|
|
async def _require_set_brightness() -> int:
|
|
def callback(val: int) -> None:
|
|
display.backlight(val)
|
|
|
|
return await request_number_slider(
|
|
"Set brightness",
|
|
callback,
|
|
min_count=style.BACKLIGHT_MIN,
|
|
max_count=style.BACKLIGHT_MAX,
|
|
count=style.get_backlight_normal(),
|
|
br_name="set_brightness",
|
|
)
|