diff --git a/common/protob/messages-debug.proto b/common/protob/messages-debug.proto index ff1a458c7..b308a1f4f 100644 --- a/common/protob/messages-debug.proto +++ b/common/protob/messages-debug.proto @@ -24,6 +24,8 @@ message DebugLinkDecision { * @next DebugLinkState */ message DebugLinkGetState { + optional bool wait_word_list = 1; // Trezor T only - wait until mnemonic words are shown + optional bool wait_word_pos = 2; // Trezor T only - wait until reset word position is requested } /** diff --git a/core/src/apps/debug/__init__.py b/core/src/apps/debug/__init__.py index 7292cd51c..4e3d92486 100644 --- a/core/src/apps/debug/__init__.py +++ b/core/src/apps/debug/__init__.py @@ -4,36 +4,60 @@ if not __debug__: halt("debug mode inactive") if __debug__: - from trezor import config, loop, utils + from trezor import config, log, loop, utils from trezor.messages import MessageType from trezor.wire import register, protobuf_workflow if False: - from typing import List, Optional + from typing import Optional from trezor import wire from trezor.messages.DebugLinkDecision import DebugLinkDecision from trezor.messages.DebugLinkGetState import DebugLinkGetState from trezor.messages.DebugLinkState import DebugLinkState reset_internal_entropy = None # type: Optional[bytes] - reset_current_words = None # type: Optional[List[str]] - reset_word_index = None # type: Optional[int] + reset_current_words = loop.chan() + reset_word_index = loop.chan() - confirm_signal = loop.signal() - swipe_signal = loop.signal() - input_signal = loop.signal() + confirm_chan = loop.chan() + swipe_chan = loop.chan() + input_chan = loop.chan() + confirm_signal = confirm_chan.take + swipe_signal = swipe_chan.take + input_signal = input_chan.take async def dispatch_DebugLinkDecision( ctx: wire.Context, msg: DebugLinkDecision ) -> None: from trezor.ui import confirm, swipe + waiting_signals = [ + bool(s.putters) for s in (confirm_chan, swipe_chan, input_chan) + ] + if sum(waiting_signals) > 0: + log.warning( + __name__, + "Received new DebugLinkDecision before the previous one was handled.", + ) + log.warning( + __name__, + "received: button {}, swipe {}, input {}".format( + msg.yes_no, msg.up_down, msg.input + ), + ) + log.warning( + __name__, + "waiting: button {}, swipe {}, input {}".format(*waiting_signals), + ) + if msg.yes_no is not None: - confirm_signal.send(confirm.CONFIRMED if msg.yes_no else confirm.CANCELLED) + await confirm_chan.put( + confirm.CONFIRMED if msg.yes_no else confirm.CANCELLED + ) if msg.up_down is not None: - swipe_signal.send(swipe.SWIPE_DOWN if msg.up_down else swipe.SWIPE_UP) + await swipe_chan.put(swipe.SWIPE_DOWN if msg.up_down else swipe.SWIPE_UP) if msg.input is not None: - input_signal.send(msg.input) + await input_chan.put(msg.input) async def dispatch_DebugLinkGetState( ctx: wire.Context, msg: DebugLinkGetState @@ -45,10 +69,12 @@ if __debug__: m.mnemonic_secret = mnemonic.get_secret() m.mnemonic_type = mnemonic.get_type() m.passphrase_protection = storage.device.has_passphrase() - m.reset_word_pos = reset_word_index m.reset_entropy = reset_internal_entropy - if reset_current_words: - m.reset_word = " ".join(reset_current_words) + + if msg.wait_word_pos: + m.reset_word_pos = await reset_word_index.take() + if msg.wait_word_list: + m.reset_word = " ".join(await reset_current_words.take()) return m def boot() -> None: diff --git a/core/src/apps/management/common/layout.py b/core/src/apps/management/common/layout.py index 6bd6df1ba..e64040fb7 100644 --- a/core/src/apps/management/common/layout.py +++ b/core/src/apps/management/common/layout.py @@ -93,7 +93,7 @@ async def _confirm_word(ctx, share_index, numbered_share_words, count): # we always confirm the first (random) word index checked_index, checked_word = numbered_choices[0] if __debug__: - debug.reset_word_index = checked_index + debug.reset_word_index.publish(checked_index) # shuffle again so the confirmed word is not always the first choice random.shuffle(numbered_choices) @@ -200,7 +200,7 @@ async def _bip39_show_mnemonic(ctx, words: list): def export_displayed_words(): # export currently displayed mnemonic words into debuglink - debug.reset_current_words = [w for _, w in words[paginated.page]] + debug.reset_current_words.publish([w for _, w in words[paginated.page]]) paginated.on_change = export_displayed_words export_displayed_words() @@ -393,7 +393,8 @@ async def _slip39_show_share_words(ctx, share_index, share_words): def export_displayed_words(): # export currently displayed mnemonic words into debuglink - debug.reset_current_words = [w for _, w in word_pages[paginated.page]] + words = [w for _, w in word_pages[paginated.page]] + debug.reset_current_words.publish(words) paginated.on_change = export_displayed_words export_displayed_words() diff --git a/core/src/trezor/messages/DebugLinkGetState.py b/core/src/trezor/messages/DebugLinkGetState.py index d979eaf58..1b834fe45 100644 --- a/core/src/trezor/messages/DebugLinkGetState.py +++ b/core/src/trezor/messages/DebugLinkGetState.py @@ -12,3 +12,18 @@ if __debug__: class DebugLinkGetState(p.MessageType): MESSAGE_WIRE_TYPE = 101 + + def __init__( + self, + wait_word_list: bool = None, + wait_word_pos: bool = None, + ) -> None: + self.wait_word_list = wait_word_list + self.wait_word_pos = wait_word_pos + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('wait_word_list', p.BoolType, 0), + 2: ('wait_word_pos', p.BoolType, 0), + } diff --git a/python/trezorlib/messages/DebugLinkGetState.py b/python/trezorlib/messages/DebugLinkGetState.py index f4c24df7c..f6a1114b2 100644 --- a/python/trezorlib/messages/DebugLinkGetState.py +++ b/python/trezorlib/messages/DebugLinkGetState.py @@ -12,3 +12,18 @@ if __debug__: class DebugLinkGetState(p.MessageType): MESSAGE_WIRE_TYPE = 101 + + def __init__( + self, + wait_word_list: bool = None, + wait_word_pos: bool = None, + ) -> None: + self.wait_word_list = wait_word_list + self.wait_word_pos = wait_word_pos + + @classmethod + def get_fields(cls) -> Dict: + return { + 1: ('wait_word_list', p.BoolType, 0), + 2: ('wait_word_pos', p.BoolType, 0), + }