2019-07-01 07:45:30 +00:00
|
|
|
from micropython import const
|
2021-12-08 09:10:58 +00:00
|
|
|
from typing import TYPE_CHECKING
|
2019-07-01 07:45:30 +00:00
|
|
|
|
2022-09-21 10:50:01 +00:00
|
|
|
import storage.cache as storage_cache
|
2019-10-25 15:43:55 +00:00
|
|
|
from storage import common
|
2024-05-24 15:29:55 +00:00
|
|
|
from trezor import utils
|
2019-07-01 07:45:30 +00:00
|
|
|
|
2021-12-08 09:10:58 +00:00
|
|
|
if TYPE_CHECKING:
|
2021-03-23 12:35:27 +00:00
|
|
|
from trezor.enums import BackupType
|
2020-09-17 12:27:04 +00:00
|
|
|
from typing_extensions import Literal
|
2019-07-09 12:05:35 +00:00
|
|
|
|
2019-07-01 07:45:30 +00:00
|
|
|
# Namespace:
|
2019-09-12 12:18:00 +00:00
|
|
|
_NAMESPACE = common.APP_DEVICE
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
# fmt: off
|
|
|
|
# Keys:
|
2020-06-16 07:20:06 +00:00
|
|
|
DEVICE_ID = const(0x00) # bytes
|
2019-07-11 14:52:25 +00:00
|
|
|
_VERSION = const(0x01) # int
|
|
|
|
_MNEMONIC_SECRET = const(0x02) # bytes
|
|
|
|
_LABEL = const(0x04) # str
|
|
|
|
_USE_PASSPHRASE = const(0x05) # bool (0x01 or empty)
|
|
|
|
_HOMESCREEN = const(0x06) # bytes
|
|
|
|
_NEEDS_BACKUP = const(0x07) # bool (0x01 or empty)
|
|
|
|
_FLAGS = const(0x08) # int
|
2019-09-11 07:51:51 +00:00
|
|
|
U2F_COUNTER = const(0x09) # int
|
2019-11-21 09:53:42 +00:00
|
|
|
_PASSPHRASE_ALWAYS_ON_DEVICE = const(0x0A) # bool (0x01 or empty)
|
2019-07-11 14:52:25 +00:00
|
|
|
_UNFINISHED_BACKUP = const(0x0B) # bool (0x01 or empty)
|
|
|
|
_AUTOLOCK_DELAY_MS = const(0x0C) # int
|
|
|
|
_NO_BACKUP = const(0x0D) # bool (0x01 or empty)
|
2019-09-19 07:37:23 +00:00
|
|
|
_BACKUP_TYPE = const(0x0E) # int
|
2019-07-11 14:52:25 +00:00
|
|
|
_ROTATION = const(0x0F) # int
|
|
|
|
_SLIP39_IDENTIFIER = const(0x10) # bool
|
|
|
|
_SLIP39_ITERATION_EXPONENT = const(0x11) # int
|
2019-08-13 15:50:06 +00:00
|
|
|
_SD_SALT_AUTH_KEY = const(0x12) # bytes
|
2020-06-16 07:20:06 +00:00
|
|
|
INITIALIZED = const(0x13) # bool (0x01 or empty)
|
2020-09-17 12:27:04 +00:00
|
|
|
_SAFETY_CHECK_LEVEL = const(0x14) # int
|
2020-10-04 21:46:54 +00:00
|
|
|
_EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty)
|
2023-02-15 14:43:04 +00:00
|
|
|
_HIDE_PASSPHRASE_FROM_HOST = const(0x16) # bool (0x01 or empty)
|
2024-05-24 15:29:55 +00:00
|
|
|
if utils.USE_THP:
|
|
|
|
_DEVICE_SECRET = const(0x17) # bytes
|
|
|
|
_CRED_AUTH_KEY_COUNTER = const(0x18) # bytes
|
2024-05-07 13:46:15 +00:00
|
|
|
# unused from python:
|
|
|
|
# _BRIGHTNESS = const(0x19) # int
|
|
|
|
_DISABLE_HAPTIC_FEEDBACK = const(0x20) # bool (0x01 or empty)
|
|
|
|
|
2024-05-24 15:29:55 +00:00
|
|
|
|
2020-10-16 17:39:32 +00:00
|
|
|
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
|
|
|
|
SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1)
|
2020-09-17 12:27:04 +00:00
|
|
|
_DEFAULT_SAFETY_CHECK_LEVEL = SAFETY_CHECK_LEVEL_STRICT
|
2021-12-08 09:10:58 +00:00
|
|
|
if TYPE_CHECKING:
|
2020-09-17 12:27:04 +00:00
|
|
|
StorageSafetyCheckLevel = Literal[0, 1]
|
2019-07-01 07:45:30 +00:00
|
|
|
# fmt: on
|
|
|
|
|
2022-09-15 10:45:30 +00:00
|
|
|
HOMESCREEN_MAXSIZE = const(16384)
|
|
|
|
LABEL_MAXLENGTH = const(32)
|
2020-11-18 17:59:24 +00:00
|
|
|
|
|
|
|
if __debug__:
|
|
|
|
AUTOLOCK_DELAY_MINIMUM = 10 * 1000 # 10 seconds
|
|
|
|
else:
|
|
|
|
AUTOLOCK_DELAY_MINIMUM = 60 * 1000 # 1 minute
|
2022-09-15 10:45:30 +00:00
|
|
|
AUTOLOCK_DELAY_DEFAULT = const(10 * 60 * 1000) # 10 minutes
|
2020-06-02 09:10:35 +00:00
|
|
|
# autolock intervals larger than AUTOLOCK_DELAY_MAXIMUM cause issues in the scheduler
|
2022-09-15 10:45:30 +00:00
|
|
|
AUTOLOCK_DELAY_MAXIMUM = const(0x2000_0000) # ~6 days
|
2019-07-01 07:45:30 +00:00
|
|
|
|
2019-10-25 15:43:55 +00:00
|
|
|
# Length of SD salt auth tag.
|
|
|
|
# Other SD-salt-related constants are in sd_salt.py
|
|
|
|
SD_SALT_AUTH_KEY_LEN_BYTES = const(16)
|
|
|
|
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
def is_version_stored() -> bool:
|
2019-09-12 12:18:00 +00:00
|
|
|
return bool(common.get(_NAMESPACE, _VERSION))
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_version() -> bytes | None:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get(_NAMESPACE, _VERSION)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2019-07-09 12:05:35 +00:00
|
|
|
def set_version(version: bytes) -> None:
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set(_NAMESPACE, _VERSION, version)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2020-06-16 07:20:06 +00:00
|
|
|
def is_initialized() -> bool:
|
|
|
|
return common.get_bool(_NAMESPACE, INITIALIZED, public=True)
|
|
|
|
|
|
|
|
|
2022-09-21 10:50:01 +00:00
|
|
|
def get_device_id() -> str:
|
2021-03-22 15:14:24 +00:00
|
|
|
from trezorcrypto import random # avoid pulling in trezor.crypto
|
2023-08-15 15:56:09 +00:00
|
|
|
from ubinascii import hexlify
|
2021-03-22 15:14:24 +00:00
|
|
|
|
2020-06-16 07:20:06 +00:00
|
|
|
dev_id = common.get(_NAMESPACE, DEVICE_ID, public=True)
|
2019-07-01 07:45:30 +00:00
|
|
|
if not dev_id:
|
2022-09-21 10:50:01 +00:00
|
|
|
# _new_device_id
|
|
|
|
new_dev_id_str = hexlify(random.bytes(12)).decode().upper()
|
|
|
|
dev_id = new_dev_id_str.encode()
|
2020-06-16 07:20:06 +00:00
|
|
|
common.set(_NAMESPACE, DEVICE_ID, dev_id, public=True)
|
2019-07-01 07:45:30 +00:00
|
|
|
return dev_id.decode()
|
|
|
|
|
|
|
|
|
|
|
|
def get_rotation() -> int:
|
2020-07-23 14:51:32 +00:00
|
|
|
rotation = common.get(_NAMESPACE, _ROTATION, public=True)
|
2019-07-01 07:45:30 +00:00
|
|
|
if not rotation:
|
|
|
|
return 0
|
|
|
|
return int.from_bytes(rotation, "big")
|
|
|
|
|
|
|
|
|
2020-07-14 11:46:44 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_label() -> str | None:
|
2019-09-12 12:18:00 +00:00
|
|
|
label = common.get(_NAMESPACE, _LABEL, True) # public
|
2019-07-01 07:45:30 +00:00
|
|
|
if label is None:
|
|
|
|
return None
|
|
|
|
return label.decode()
|
|
|
|
|
|
|
|
|
2020-07-14 11:46:44 +00:00
|
|
|
def set_label(label: str) -> None:
|
2021-01-04 11:46:45 +00:00
|
|
|
if len(label) > LABEL_MAXLENGTH:
|
|
|
|
raise ValueError # label too long
|
2020-07-14 11:46:44 +00:00
|
|
|
common.set(_NAMESPACE, _LABEL, label.encode(), True) # public
|
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_mnemonic_secret() -> bytes | None:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get(_NAMESPACE, _MNEMONIC_SECRET)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2021-03-23 12:35:27 +00:00
|
|
|
def get_backup_type() -> BackupType:
|
|
|
|
from trezor.enums import BackupType
|
2021-03-22 15:14:24 +00:00
|
|
|
|
2019-09-19 07:37:23 +00:00
|
|
|
backup_type = common.get_uint8(_NAMESPACE, _BACKUP_TYPE)
|
|
|
|
if backup_type is None:
|
2021-03-22 15:14:24 +00:00
|
|
|
backup_type = BackupType.Bip39
|
2019-09-19 07:37:23 +00:00
|
|
|
|
|
|
|
if backup_type not in (
|
|
|
|
BackupType.Bip39,
|
|
|
|
BackupType.Slip39_Basic,
|
|
|
|
BackupType.Slip39_Advanced,
|
2024-05-17 19:26:21 +00:00
|
|
|
BackupType.Slip39_Single_Extendable,
|
|
|
|
BackupType.Slip39_Basic_Extendable,
|
|
|
|
BackupType.Slip39_Advanced_Extendable,
|
2019-09-19 07:37:23 +00:00
|
|
|
):
|
|
|
|
# Invalid backup type
|
|
|
|
raise RuntimeError
|
2024-04-29 11:02:40 +00:00
|
|
|
return backup_type
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2019-11-08 08:43:32 +00:00
|
|
|
def is_passphrase_enabled() -> bool:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_bool(_NAMESPACE, _USE_PASSPHRASE)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2020-07-14 11:46:44 +00:00
|
|
|
def set_passphrase_enabled(enable: bool) -> None:
|
|
|
|
common.set_bool(_NAMESPACE, _USE_PASSPHRASE, enable)
|
|
|
|
if not enable:
|
|
|
|
set_passphrase_always_on_device(False)
|
|
|
|
|
|
|
|
|
|
|
|
def set_homescreen(homescreen: bytes) -> None:
|
|
|
|
if len(homescreen) > HOMESCREEN_MAXSIZE:
|
|
|
|
raise ValueError # homescreen too large
|
2020-08-21 10:00:42 +00:00
|
|
|
common.set(_NAMESPACE, _HOMESCREEN, homescreen, public=True)
|
2020-07-14 11:46:44 +00:00
|
|
|
|
|
|
|
|
2019-07-01 07:45:30 +00:00
|
|
|
def store_mnemonic_secret(
|
|
|
|
secret: bytes,
|
2021-03-23 12:35:27 +00:00
|
|
|
backup_type: BackupType,
|
2019-07-01 07:45:30 +00:00
|
|
|
needs_backup: bool = False,
|
|
|
|
no_backup: bool = False,
|
|
|
|
) -> None:
|
2019-09-12 12:18:00 +00:00
|
|
|
set_version(common.STORAGE_VERSION_CURRENT)
|
|
|
|
common.set(_NAMESPACE, _MNEMONIC_SECRET, secret)
|
2019-09-19 07:37:23 +00:00
|
|
|
common.set_uint8(_NAMESPACE, _BACKUP_TYPE, backup_type)
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set_true_or_delete(_NAMESPACE, _NO_BACKUP, no_backup)
|
2020-06-16 07:20:06 +00:00
|
|
|
common.set_bool(_NAMESPACE, INITIALIZED, True, public=True)
|
2019-07-01 07:45:30 +00:00
|
|
|
if not no_backup:
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set_true_or_delete(_NAMESPACE, _NEEDS_BACKUP, needs_backup)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def needs_backup() -> bool:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_bool(_NAMESPACE, _NEEDS_BACKUP)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_backed_up() -> None:
|
2019-09-12 12:18:00 +00:00
|
|
|
common.delete(_NAMESPACE, _NEEDS_BACKUP)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def unfinished_backup() -> bool:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_bool(_NAMESPACE, _UNFINISHED_BACKUP)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_unfinished_backup(state: bool) -> None:
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set_bool(_NAMESPACE, _UNFINISHED_BACKUP, state)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def no_backup() -> bool:
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_bool(_NAMESPACE, _NO_BACKUP)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2019-11-21 09:53:42 +00:00
|
|
|
def get_passphrase_always_on_device() -> bool:
|
2020-01-24 13:45:10 +00:00
|
|
|
"""
|
|
|
|
This is backwards compatible with _PASSPHRASE_SOURCE:
|
|
|
|
- If ASK(0) => returns False, the check against b"\x01" in get_bool fails.
|
|
|
|
- If DEVICE(1) => returns True, the check against b"\x01" in get_bool succeeds.
|
|
|
|
- If HOST(2) => returns False, the check against b"\x01" in get_bool fails.
|
|
|
|
"""
|
|
|
|
return common.get_bool(_NAMESPACE, _PASSPHRASE_ALWAYS_ON_DEVICE)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2020-07-14 11:46:44 +00:00
|
|
|
def set_passphrase_always_on_device(enable: bool) -> None:
|
|
|
|
common.set_bool(_NAMESPACE, _PASSPHRASE_ALWAYS_ON_DEVICE, enable)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_flags() -> int:
|
2019-09-12 12:18:00 +00:00
|
|
|
b = common.get(_NAMESPACE, _FLAGS)
|
2019-07-01 07:45:30 +00:00
|
|
|
if b is None:
|
|
|
|
return 0
|
|
|
|
else:
|
|
|
|
return int.from_bytes(b, "big")
|
|
|
|
|
|
|
|
|
|
|
|
def set_flags(flags: int) -> None:
|
2019-09-12 12:18:00 +00:00
|
|
|
b = common.get(_NAMESPACE, _FLAGS)
|
2019-07-01 07:45:30 +00:00
|
|
|
if b is None:
|
2019-07-09 12:05:35 +00:00
|
|
|
i = 0
|
2019-07-01 07:45:30 +00:00
|
|
|
else:
|
2019-07-09 12:05:35 +00:00
|
|
|
i = int.from_bytes(b, "big")
|
2020-11-23 13:24:13 +00:00
|
|
|
flags = (flags | i) & 0xFFFF_FFFF
|
2019-07-09 12:05:35 +00:00
|
|
|
if flags != i:
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set(_NAMESPACE, _FLAGS, flags.to_bytes(4, "big"))
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2020-11-18 17:59:24 +00:00
|
|
|
def _normalize_autolock_delay(delay_ms: int) -> int:
|
|
|
|
delay_ms = max(delay_ms, AUTOLOCK_DELAY_MINIMUM)
|
|
|
|
delay_ms = min(delay_ms, AUTOLOCK_DELAY_MAXIMUM)
|
|
|
|
return delay_ms
|
|
|
|
|
|
|
|
|
2019-07-01 07:45:30 +00:00
|
|
|
def get_autolock_delay_ms() -> int:
|
2019-09-12 12:18:00 +00:00
|
|
|
b = common.get(_NAMESPACE, _AUTOLOCK_DELAY_MS)
|
2019-07-01 07:45:30 +00:00
|
|
|
if b is None:
|
2020-05-18 12:59:58 +00:00
|
|
|
return AUTOLOCK_DELAY_DEFAULT
|
2019-07-01 07:45:30 +00:00
|
|
|
else:
|
2020-11-18 17:59:24 +00:00
|
|
|
return _normalize_autolock_delay(int.from_bytes(b, "big"))
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_autolock_delay_ms(delay_ms: int) -> None:
|
2020-11-18 17:59:24 +00:00
|
|
|
delay_ms = _normalize_autolock_delay(delay_ms)
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set(_NAMESPACE, _AUTOLOCK_DELAY_MS, delay_ms.to_bytes(4, "big"))
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
2021-03-10 13:43:21 +00:00
|
|
|
def next_u2f_counter() -> int:
|
|
|
|
return common.next_counter(_NAMESPACE, U2F_COUNTER, writable_locked=True)
|
2019-07-01 07:45:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_u2f_counter(count: int) -> None:
|
2021-03-10 13:43:21 +00:00
|
|
|
common.set_counter(_NAMESPACE, U2F_COUNTER, count, writable_locked=True)
|
2019-07-11 14:52:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_slip39_identifier(identifier: int) -> None:
|
|
|
|
"""
|
|
|
|
The device's actual SLIP-39 identifier used in passphrase derivation.
|
|
|
|
Not to be confused with recovery.identifier, which is stored only during
|
|
|
|
the recovery process and it is copied here upon success.
|
|
|
|
"""
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set_uint16(_NAMESPACE, _SLIP39_IDENTIFIER, identifier)
|
2019-07-11 14:52:25 +00:00
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_slip39_identifier() -> int | None:
|
2024-04-30 18:26:46 +00:00
|
|
|
"""The device's actual SLIP-39 identifier used in legacy passphrase derivation."""
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_uint16(_NAMESPACE, _SLIP39_IDENTIFIER)
|
2019-07-11 14:52:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_slip39_iteration_exponent(exponent: int) -> None:
|
|
|
|
"""
|
|
|
|
The device's actual SLIP-39 iteration exponent used in passphrase derivation.
|
|
|
|
Not to be confused with recovery.iteration_exponent, which is stored only during
|
|
|
|
the recovery process and it is copied here upon success.
|
|
|
|
"""
|
2019-09-12 12:18:00 +00:00
|
|
|
common.set_uint8(_NAMESPACE, _SLIP39_ITERATION_EXPONENT, exponent)
|
2019-07-11 14:52:25 +00:00
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_slip39_iteration_exponent() -> int | None:
|
2019-07-11 14:52:25 +00:00
|
|
|
"""
|
|
|
|
The device's actual SLIP-39 iteration exponent used in passphrase derivation.
|
|
|
|
"""
|
2019-09-12 12:18:00 +00:00
|
|
|
return common.get_uint8(_NAMESPACE, _SLIP39_ITERATION_EXPONENT)
|
2019-08-13 15:50:06 +00:00
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def get_sd_salt_auth_key() -> bytes | None:
|
2019-08-13 15:50:06 +00:00
|
|
|
"""
|
|
|
|
The key used to check the authenticity of the SD card salt.
|
|
|
|
"""
|
|
|
|
auth_key = common.get(_NAMESPACE, _SD_SALT_AUTH_KEY, public=True)
|
|
|
|
if auth_key is not None and len(auth_key) != SD_SALT_AUTH_KEY_LEN_BYTES:
|
|
|
|
raise ValueError
|
|
|
|
return auth_key
|
|
|
|
|
|
|
|
|
2021-03-18 09:48:50 +00:00
|
|
|
def set_sd_salt_auth_key(auth_key: bytes | None) -> None:
|
2019-08-13 15:50:06 +00:00
|
|
|
"""
|
|
|
|
The key used to check the authenticity of the SD card salt.
|
|
|
|
"""
|
|
|
|
if auth_key is not None:
|
|
|
|
if len(auth_key) != SD_SALT_AUTH_KEY_LEN_BYTES:
|
|
|
|
raise ValueError
|
|
|
|
return common.set(_NAMESPACE, _SD_SALT_AUTH_KEY, auth_key, public=True)
|
|
|
|
else:
|
|
|
|
return common.delete(_NAMESPACE, _SD_SALT_AUTH_KEY, public=True)
|
2020-07-13 13:58:41 +00:00
|
|
|
|
|
|
|
|
2020-09-17 12:27:04 +00:00
|
|
|
# do not use this function directly, see apps.common.safety_checks instead
|
|
|
|
def safety_check_level() -> StorageSafetyCheckLevel:
|
|
|
|
level = common.get_uint8(_NAMESPACE, _SAFETY_CHECK_LEVEL)
|
|
|
|
if level not in (SAFETY_CHECK_LEVEL_STRICT, SAFETY_CHECK_LEVEL_PROMPT):
|
|
|
|
return _DEFAULT_SAFETY_CHECK_LEVEL
|
|
|
|
else:
|
2024-04-29 11:02:40 +00:00
|
|
|
return level
|
2020-07-13 13:58:41 +00:00
|
|
|
|
|
|
|
|
2020-09-17 12:27:04 +00:00
|
|
|
# do not use this function directly, see apps.common.safety_checks instead
|
|
|
|
def set_safety_check_level(level: StorageSafetyCheckLevel) -> None:
|
|
|
|
if level not in (SAFETY_CHECK_LEVEL_STRICT, SAFETY_CHECK_LEVEL_PROMPT):
|
|
|
|
raise ValueError
|
|
|
|
common.set_uint8(_NAMESPACE, _SAFETY_CHECK_LEVEL, level)
|
2020-10-04 21:46:54 +00:00
|
|
|
|
|
|
|
|
2022-09-21 10:50:01 +00:00
|
|
|
@storage_cache.stored(storage_cache.STORAGE_DEVICE_EXPERIMENTAL_FEATURES)
|
2021-03-30 09:52:33 +00:00
|
|
|
def _get_experimental_features() -> bytes:
|
|
|
|
if common.get_bool(_NAMESPACE, _EXPERIMENTAL_FEATURES):
|
|
|
|
return b"\x01"
|
|
|
|
else:
|
|
|
|
return b""
|
|
|
|
|
|
|
|
|
2020-10-04 21:46:54 +00:00
|
|
|
def get_experimental_features() -> bool:
|
2021-03-30 09:52:33 +00:00
|
|
|
return bool(_get_experimental_features())
|
2020-10-04 21:46:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_experimental_features(enabled: bool) -> None:
|
2021-03-30 09:52:33 +00:00
|
|
|
cached_bytes = b"\x01" if enabled else b""
|
2022-09-21 10:50:01 +00:00
|
|
|
storage_cache.set(storage_cache.STORAGE_DEVICE_EXPERIMENTAL_FEATURES, cached_bytes)
|
2020-10-04 21:46:54 +00:00
|
|
|
common.set_true_or_delete(_NAMESPACE, _EXPERIMENTAL_FEATURES, enabled)
|
2023-02-15 14:43:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_hide_passphrase_from_host(hide: bool) -> None:
|
|
|
|
"""
|
|
|
|
Whether we should hide the passphrase from the host.
|
|
|
|
"""
|
|
|
|
common.set_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST, hide)
|
|
|
|
|
|
|
|
|
|
|
|
def get_hide_passphrase_from_host() -> bool:
|
|
|
|
"""
|
|
|
|
Whether we should hide the passphrase from the host.
|
|
|
|
"""
|
|
|
|
return common.get_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST)
|
2024-05-24 15:29:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
if utils.USE_THP:
|
|
|
|
|
|
|
|
def get_device_secret() -> bytes:
|
|
|
|
"""
|
|
|
|
Device secret is used to derive keys that are independent of the seed.
|
|
|
|
"""
|
|
|
|
device_secret = common.get(_NAMESPACE, _DEVICE_SECRET)
|
|
|
|
if not device_secret:
|
|
|
|
from trezor.crypto import random
|
|
|
|
|
|
|
|
device_secret = random.bytes(16, True)
|
|
|
|
common.set(_NAMESPACE, _DEVICE_SECRET, device_secret)
|
|
|
|
return device_secret
|
|
|
|
|
|
|
|
def get_cred_auth_key_counter() -> bytes:
|
|
|
|
return common.get(_NAMESPACE, _CRED_AUTH_KEY_COUNTER) or bytes(4)
|
|
|
|
|
|
|
|
def increment_cred_auth_key_counter() -> None:
|
|
|
|
counter = int.from_bytes(get_cred_auth_key_counter(), "big")
|
|
|
|
utils.ensure(counter < 0xFFFFFFFF, "Overflow of cred_auth_key_counter")
|
|
|
|
common.set(_NAMESPACE, _CRED_AUTH_KEY_COUNTER, (counter + 1).to_bytes(4, "big"))
|
2024-05-07 13:46:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
def set_haptic_feedback(enable: bool) -> None:
|
|
|
|
"""
|
|
|
|
Enable or disable haptic feedback.
|
|
|
|
"""
|
|
|
|
common.set_bool(_NAMESPACE, _DISABLE_HAPTIC_FEEDBACK, not enable, True)
|
|
|
|
|
|
|
|
|
|
|
|
def get_haptic_feedback() -> bool:
|
|
|
|
"""
|
|
|
|
Get haptic feedback enable, default to true if not set.
|
|
|
|
"""
|
|
|
|
return not common.get_bool(_NAMESPACE, _DISABLE_HAPTIC_FEEDBACK, True)
|