mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-07 15:18:08 +00:00
rework high-level storage
We don't use Storage protobuf message anymore, and instead all keys are as granular as possible. trezor.storage provides high-level function interface.
This commit is contained in:
parent
53f6347838
commit
a44e16a9ca
@ -12,11 +12,6 @@ _cached_root_node = None
|
|||||||
|
|
||||||
|
|
||||||
async def get_node(session_id: int, path: list):
|
async def get_node(session_id: int, path: list):
|
||||||
from trezor import ui
|
|
||||||
ui.display.clear()
|
|
||||||
ui.display.text_center(120, 120, 'Deriving key...',
|
|
||||||
ui.NORMAL, ui.GREY, ui.BLACK)
|
|
||||||
ui.display.refresh()
|
|
||||||
node = await get_root_node(session_id)
|
node = await get_root_node(session_id)
|
||||||
node.derive_path(path)
|
node.derive_path(path)
|
||||||
return node
|
return node
|
||||||
@ -48,17 +43,15 @@ async def compute_seed(session_id):
|
|||||||
from .request_pin import request_pin
|
from .request_pin import request_pin
|
||||||
from . import storage
|
from . import storage
|
||||||
|
|
||||||
try:
|
if not storage.is_initialized():
|
||||||
st = storage.get(session_id)
|
|
||||||
except KeyError:
|
|
||||||
raise wire.FailureError(Other, 'Device is not initialized')
|
raise wire.FailureError(Other, 'Device is not initialized')
|
||||||
|
|
||||||
st_pin = getattr(st, 'pin', '')
|
if storage.is_protected_by_pin():
|
||||||
if st_pin and st_pin != await request_pin(session_id):
|
pin = await request_pin(session_id)
|
||||||
|
if not storage.check_pin(pin):
|
||||||
raise wire.FailureError(PinInvalid, 'PIN is incorrect')
|
raise wire.FailureError(PinInvalid, 'PIN is incorrect')
|
||||||
|
|
||||||
st_passphrase_protection = getattr(st, 'passphrase_protection', False)
|
if storage.is_protected_by_passphrase():
|
||||||
if st_passphrase_protection:
|
|
||||||
from trezor.messages.PassphraseRequest import PassphraseRequest
|
from trezor.messages.PassphraseRequest import PassphraseRequest
|
||||||
from trezor.messages.wire_types import PassphraseAck
|
from trezor.messages.wire_types import PassphraseAck
|
||||||
ack = await wire.reply_message(session_id, PassphraseRequest(), PassphraseAck)
|
ack = await wire.reply_message(session_id, PassphraseRequest(), PassphraseAck)
|
||||||
@ -66,4 +59,4 @@ async def compute_seed(session_id):
|
|||||||
else:
|
else:
|
||||||
passphrase = ''
|
passphrase = ''
|
||||||
|
|
||||||
return bip39.seed(st.mnemonic, passphrase)
|
return bip39.seed(storage.get_mnemonic(), passphrase)
|
||||||
|
@ -1,27 +1,111 @@
|
|||||||
|
import protobuf as p
|
||||||
from micropython import const
|
from micropython import const
|
||||||
from trezor import config
|
from trezor import config
|
||||||
from trezor.messages.Storage import Storage
|
|
||||||
|
_APP_COMMON = const(1)
|
||||||
|
|
||||||
|
_CFG_ID = const(0)
|
||||||
|
_CFG_VERSION = const(1)
|
||||||
|
_CFG_MNEMONIC = const(2)
|
||||||
|
_CFG_LANGUAGE = const(3)
|
||||||
|
_CFG_LABEL = const(4)
|
||||||
|
_CFG_PIN = const(5)
|
||||||
|
_CFG_PIN_ATTEMPTS = const(6)
|
||||||
|
_CFG_PASSPHRASE_PROTECTION = const(7)
|
||||||
|
|
||||||
|
_types = {
|
||||||
|
_CFG_ID: p.UnicodeType,
|
||||||
|
_CFG_VERSION: p.UVarintType,
|
||||||
|
_CFG_MNEMONIC: p.UnicodeType,
|
||||||
|
_CFG_LANGUAGE: p.UnicodeType,
|
||||||
|
_CFG_LABEL: p.UnicodeType,
|
||||||
|
_CFG_PIN: p.UnicodeType,
|
||||||
|
_CFG_PIN_ATTEMPTS: p.UVarintType,
|
||||||
|
_CFG_PASSPHRASE_PROTECTION: p.BoolType,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
APP_COMMON = const(1)
|
def get_device_id() -> str:
|
||||||
CFG_STORAGE = const(1)
|
devid = _get(_CFG_ID)
|
||||||
|
if devid is None:
|
||||||
|
devid = _new_device_id()
|
||||||
|
_set(_CFG_ID, devid)
|
||||||
|
return devid
|
||||||
|
|
||||||
|
|
||||||
def has(session_id):
|
def is_initialized() -> bool:
|
||||||
buf = config.get(session_id, APP_COMMON, CFG_STORAGE)
|
return _get(_CFG_VERSION) is not None
|
||||||
return bool(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def get(session_id):
|
def is_protected_by_pin() -> bool:
|
||||||
buf = config.get(session_id, APP_COMMON, CFG_STORAGE)
|
return _get(_CFG_PIN) is not None
|
||||||
if not buf:
|
|
||||||
raise KeyError('Storage is not initialized')
|
|
||||||
return Storage.loads(buf)
|
|
||||||
|
|
||||||
|
|
||||||
def set(session_id, st):
|
def is_protected_by_passphrase() -> bool:
|
||||||
config.set(session_id, APP_COMMON, CFG_STORAGE, st.dumps())
|
return _get(_CFG_PASSPHRASE_PROTECTION) is True
|
||||||
|
|
||||||
|
|
||||||
def clear(session_id):
|
def check_pin(pin: str) -> bool:
|
||||||
config.set(session_id, APP_COMMON, CFG_STORAGE, b'')
|
return _get(_CFG_PIN) == pin
|
||||||
|
|
||||||
|
|
||||||
|
def get_label() -> str:
|
||||||
|
return _get(_CFG_LABEL)
|
||||||
|
|
||||||
|
|
||||||
|
def get_mnemonic() -> str:
|
||||||
|
return _get(_CFG_MNEMONIC)
|
||||||
|
|
||||||
|
|
||||||
|
def load_mnemonic(mnemonic: str):
|
||||||
|
if is_initialized():
|
||||||
|
raise Exception('Device is already initialized')
|
||||||
|
_set(_CFG_VERSION, 1)
|
||||||
|
_set(_CFG_MNEMONIC, mnemonic)
|
||||||
|
|
||||||
|
|
||||||
|
def load_settings(language: str,
|
||||||
|
label: str,
|
||||||
|
pin: str,
|
||||||
|
passphrase_protection: bool):
|
||||||
|
if not is_initialized():
|
||||||
|
raise Exception('Device is not initialized')
|
||||||
|
_set(_CFG_LANGUAGE, language or None)
|
||||||
|
_set(_CFG_LABEL, label or None)
|
||||||
|
_set(_CFG_PIN, pin or None)
|
||||||
|
_set(_CFG_PIN_ATTEMPTS, None)
|
||||||
|
_set(_CFG_PASSPHRASE_PROTECTION, passphrase_protection)
|
||||||
|
|
||||||
|
|
||||||
|
def wipe():
|
||||||
|
_set(_CFG_ID, _new_device_id())
|
||||||
|
_set(_CFG_VERSION, None)
|
||||||
|
_set(_CFG_MNEMONIC, None)
|
||||||
|
_set(_CFG_LANGUAGE, None)
|
||||||
|
_set(_CFG_LABEL, None)
|
||||||
|
_set(_CFG_PIN, None)
|
||||||
|
_set(_CFG_PIN_ATTEMPTS, None)
|
||||||
|
_set(_CFG_PASSPHRASE_PROTECTION, None)
|
||||||
|
|
||||||
|
|
||||||
|
def _get(key: int):
|
||||||
|
buf = config.get(_APP_COMMON, key)
|
||||||
|
if buf:
|
||||||
|
val = _types[key].loads(buf)
|
||||||
|
else:
|
||||||
|
val = None
|
||||||
|
return val
|
||||||
|
|
||||||
|
|
||||||
|
def _set(key: int, val):
|
||||||
|
if val is not None:
|
||||||
|
buf = _types[key].dumps(val)
|
||||||
|
else:
|
||||||
|
buf = b''
|
||||||
|
config.set(_APP_COMMON, key, buf)
|
||||||
|
|
||||||
|
|
||||||
|
def _new_device_id() -> str:
|
||||||
|
from ubinascii import hexlify
|
||||||
|
from trezor.crypto import random
|
||||||
|
return str(hexlify(random.bytes(16)))
|
||||||
|
@ -5,29 +5,15 @@ from trezor.utils import unimport
|
|||||||
@unimport
|
@unimport
|
||||||
async def layout_load_device(message, session_id):
|
async def layout_load_device(message, session_id):
|
||||||
from trezor.crypto import bip39
|
from trezor.crypto import bip39
|
||||||
from trezor.messages.Storage import Storage
|
|
||||||
from trezor.messages.Success import Success
|
from trezor.messages.Success import Success
|
||||||
from trezor.messages.FailureType import UnexpectedMessage, Other
|
from trezor.messages.FailureType import UnexpectedMessage, Other
|
||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
from ..common.confirm import require_confirm
|
from ..common.confirm import require_confirm
|
||||||
from ..common import storage
|
from ..common import storage
|
||||||
|
|
||||||
if storage.has(session_id):
|
if storage.is_initialized():
|
||||||
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
||||||
|
|
||||||
st = Storage()
|
|
||||||
st.imported = True
|
|
||||||
st.version = 1
|
|
||||||
st.pin = message.pin
|
|
||||||
st.passphrase_protection = message.passphrase_protection,
|
|
||||||
st.language = message.language
|
|
||||||
st.label = message.label
|
|
||||||
|
|
||||||
if hasattr(message, 'node'):
|
|
||||||
st.node = message.node
|
|
||||||
|
|
||||||
elif hasattr(message, 'mnemonic'):
|
|
||||||
st.mnemonic = message.mnemonic
|
|
||||||
if not message.skip_checksum and not bip39.check(message.mnemonic):
|
if not message.skip_checksum and not bip39.check(message.mnemonic):
|
||||||
raise wire.FailureError(Other, 'Mnemonic is not valid')
|
raise wire.FailureError(Other, 'Mnemonic is not valid')
|
||||||
|
|
||||||
@ -36,6 +22,10 @@ async def layout_load_device(message, session_id):
|
|||||||
ui.BOLD, 'Loading private seed', 'is not recommended.',
|
ui.BOLD, 'Loading private seed', 'is not recommended.',
|
||||||
ui.NORMAL, 'Continue only if you', 'know what you are doing!'))
|
ui.NORMAL, 'Continue only if you', 'know what you are doing!'))
|
||||||
|
|
||||||
storage.set(session_id, st)
|
storage.load_mnemonic(message.mnemonic)
|
||||||
|
storage.load_settings(pin=message.pin,
|
||||||
|
passphrase_protection=message.passphrase_protection,
|
||||||
|
language=message.language,
|
||||||
|
label=message.label)
|
||||||
|
|
||||||
return Success(message='Device loaded')
|
return Success(message='Device loaded')
|
||||||
|
@ -6,27 +6,28 @@ from trezor.utils import unimport, chunks
|
|||||||
@unimport
|
@unimport
|
||||||
async def layout_reset_device(message, session_id):
|
async def layout_reset_device(message, session_id):
|
||||||
from trezor.messages.Success import Success
|
from trezor.messages.Success import Success
|
||||||
from trezor.messages.Storage import Storage
|
|
||||||
from trezor.messages.FailureType import UnexpectedMessage
|
from trezor.messages.FailureType import UnexpectedMessage
|
||||||
from ..common.request_pin import request_pin_twice
|
from ..common.request_pin import request_pin_twice
|
||||||
from ..common import storage
|
from ..common import storage
|
||||||
|
|
||||||
if storage.has(session_id):
|
if storage.is_initialized():
|
||||||
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
raise wire.FailureError(UnexpectedMessage, 'Already initialized')
|
||||||
|
|
||||||
mnemonic = await generate_mnemonic(
|
mnemonic = await generate_mnemonic(
|
||||||
message.strength, message.display_random, session_id)
|
message.strength, message.display_random, session_id)
|
||||||
|
|
||||||
await show_mnemonic(mnemonic)
|
await show_mnemonic(mnemonic)
|
||||||
|
|
||||||
if message.pin_protection:
|
if message.pin_protection:
|
||||||
pin = await request_pin_twice(session_id)
|
pin = await request_pin_twice(session_id)
|
||||||
else:
|
else:
|
||||||
pin = ''
|
pin = None
|
||||||
|
|
||||||
storage.set(session_id, Storage(
|
storage.load_mnemonic(mnemonic)
|
||||||
version=1, pin=pin, mnemonic=mnemonic,
|
storage.load_settings(pin=pin,
|
||||||
passphrase_protection=message.passphrase_protection,
|
passphrase_protection=message.passphrase_protection,
|
||||||
language=message.language, label=message.label))
|
language=message.language,
|
||||||
|
label=message.label)
|
||||||
|
|
||||||
return Success(message='Initialized')
|
return Success(message='Initialized')
|
||||||
|
|
||||||
|
@ -3,20 +3,18 @@ from trezor.utils import unimport
|
|||||||
|
|
||||||
|
|
||||||
@unimport
|
@unimport
|
||||||
async def layout_wipe_device(message, session_id):
|
async def layout_wipe_device(_, session_id):
|
||||||
from trezor.messages.Success import Success
|
from trezor.messages.Success import Success
|
||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
from ..common.confirm import hold_to_confirm
|
from ..common.confirm import hold_to_confirm
|
||||||
from ..common import storage
|
from ..common import storage
|
||||||
|
|
||||||
ui.display.clear()
|
await hold_to_confirm(session_id, Text(
|
||||||
content = Text(
|
|
||||||
'Wiping device',
|
'Wiping device',
|
||||||
ui.ICON_WIPE,
|
ui.ICON_WIPE,
|
||||||
ui.BOLD, 'Do you really want to', 'wipe the device?',
|
ui.BOLD, 'Do you really want to', 'wipe the device?',
|
||||||
ui.NORMAL, '', 'All data will be lost.')
|
ui.NORMAL, '', 'All data will be lost.'))
|
||||||
await hold_to_confirm(session_id, content)
|
|
||||||
|
|
||||||
storage.clear(session_id)
|
storage.wipe()
|
||||||
|
|
||||||
return Success(message='Device wiped')
|
return Success(message='Device wiped')
|
||||||
|
@ -34,17 +34,11 @@ def _save():
|
|||||||
_load()
|
_load()
|
||||||
|
|
||||||
|
|
||||||
def get(session_id, app_id, key, default=None):
|
def get(app_id, key, default=None):
|
||||||
# TODO: session_id
|
|
||||||
return _mock.get((app_id << 8) | key, default)
|
return _mock.get((app_id << 8) | key, default)
|
||||||
|
|
||||||
|
|
||||||
def set(session_id, app_id, key, value):
|
def set(app_id, key, value):
|
||||||
# TODO: session_id
|
|
||||||
_mock[(app_id << 8) | key] = value
|
_mock[(app_id << 8) | key] = value
|
||||||
_save()
|
_save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def commit(session_id):
|
|
||||||
pass
|
|
||||||
|
Loading…
Reference in New Issue
Block a user