mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-24 08:28:12 +00:00
06927e003e
This also moves DebugLinkMixin to debuglink.py and converts the mixin to a subclass of TrezorClient (which is finally becoming a reasonable-looking class). This takes advantage of the new UI protocol and is ready for further improvements, namely, queuing input for tests that require swipes. The ui.py module contains a Click-based implementation of the UI protocol. Use of callback_* methods has been limited and will probably be cleaned up further (The contract has changed so we'll try to make third party code fail noisily. It is unclear whether a backwards compatible approach will be possible). Furthermore, device.recovery() now takes a callback as an argument. This way we can get rid of WordRequest callbacks, which are only used in the recovery flow.
142 lines
3.8 KiB
Python
142 lines
3.8 KiB
Python
import os
|
|
|
|
import click
|
|
from mnemonic import Mnemonic
|
|
|
|
from .messages import WordRequestType, PinMatrixRequestType
|
|
from . import device
|
|
from .exceptions import Cancelled
|
|
|
|
PIN_MATRIX_DESCRIPTION = """
|
|
Use the numeric keypad to describe number positions. The layout is:
|
|
7 8 9
|
|
4 5 6
|
|
1 2 3
|
|
""".strip()
|
|
|
|
RECOVERY_MATRIX_DESCRIPTION = """
|
|
Use the numeric keypad to describe positions.
|
|
For the word list use only left and right keys.
|
|
Use backspace to correct an entry.
|
|
|
|
The keypad layout is:
|
|
7 8 9 7 | 9
|
|
4 5 6 4 | 6
|
|
1 2 3 1 | 3
|
|
""".strip()
|
|
|
|
PIN_GENERIC = None
|
|
PIN_CURRENT = PinMatrixRequestType.Current
|
|
PIN_NEW = PinMatrixRequestType.NewFirst
|
|
PIN_CONFIRM = PinMatrixRequestType.NewSecond
|
|
|
|
|
|
class ClickUI:
|
|
@staticmethod
|
|
def button_request(code):
|
|
click.echo("Please confirm action on your Trezor device")
|
|
|
|
@staticmethod
|
|
def get_pin(code=None):
|
|
if code == PIN_CURRENT:
|
|
desc = "current PIN"
|
|
elif code == PIN_NEW:
|
|
desc = "new PIN"
|
|
elif code == PIN_CONFIRM:
|
|
desc = "new PIN again"
|
|
else:
|
|
desc = "PIN"
|
|
click.echo(PIN_MATRIX_DESCRIPTION)
|
|
|
|
while True:
|
|
pin = click.prompt("Please enter {}".format(desc), hide_input=True)
|
|
if not pin.isdigit():
|
|
click.echo("Non-numerical PIN provided, please try again")
|
|
else:
|
|
return pin
|
|
|
|
@staticmethod
|
|
def get_passphrase():
|
|
if os.getenv("PASSPHRASE") is not None:
|
|
click.echo("Passphrase required. Using PASSPHRASE environment variable.")
|
|
return os.getenv("PASSPHRASE")
|
|
|
|
while True:
|
|
passphrase = click.prompt("Passphrase required", hide_input=True)
|
|
second = click.prompt("Confirm your passphrase", hide_input=True)
|
|
if passphrase == second:
|
|
return passphrase
|
|
else:
|
|
click.echo("Passphrase did not match. Please try again.")
|
|
|
|
|
|
def mnemonic_words(expand=False, language="english"):
|
|
if expand:
|
|
wordlist = Mnemonic(language).wordlist
|
|
else:
|
|
wordlist = set()
|
|
|
|
def expand_word(word):
|
|
if not expand:
|
|
return word
|
|
if word in wordlist:
|
|
return word
|
|
matches = [w for w in wordlist if w.startswith(word)]
|
|
if len(matches) == 1:
|
|
return word
|
|
click.echo("Choose one of: " + ", ".join(matches))
|
|
raise KeyError(word)
|
|
|
|
def get_word(type):
|
|
assert type == WordRequestType.Plain
|
|
while True:
|
|
try:
|
|
word = click.prompt("Enter one word of mnemonic")
|
|
return expand_word(word)
|
|
except KeyError:
|
|
pass
|
|
except (KeyboardInterrupt, click.Abort):
|
|
raise Cancelled from None
|
|
|
|
return get_word
|
|
|
|
|
|
try:
|
|
# workaround for Click issue https://github.com/pallets/click/pull/1108
|
|
import msvcrt
|
|
|
|
def getchar():
|
|
while True:
|
|
key = msvcrt.getwch()
|
|
if key == "\x03":
|
|
raise KeyboardInterrupt
|
|
if key in (0x00, 0xe0):
|
|
# skip special keys: read the scancode and repeat
|
|
msvcrt.getwch()
|
|
continue
|
|
return key
|
|
|
|
|
|
except ImportError:
|
|
getchar = click.getchar
|
|
|
|
|
|
def matrix_words(type):
|
|
while True:
|
|
try:
|
|
ch = getchar()
|
|
except (KeyboardInterrupt, EOFError):
|
|
raise Cancelled from None
|
|
|
|
if ch in "\x04\x1b":
|
|
# Ctrl+D, Esc
|
|
raise Cancelled
|
|
if ch in "\x08\x7f":
|
|
# Backspace, Del
|
|
return device.RECOVERY_BACK
|
|
if type == WordRequestType.Matrix6 and ch in "147369":
|
|
return ch
|
|
if type == WordRequestType.Matrix9 and ch in "123456789":
|
|
return ch
|
|
|