diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 760010263..67ef8afd9 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -2,9 +2,12 @@ from trezor import ui from trezor import wire from trezor.utils import unimport +# TODO: publish only when debuglink is on +matrix = None + @unimport -async def request_pin(session_id, *args, **kwargs): +async def request_pin_on_display(session_id: int, code: int=None) -> str: from trezor.messages.ButtonRequest import ButtonRequest from trezor.messages.ButtonRequestType import ProtectCall from trezor.messages.FailureType import PinCancelled @@ -12,26 +15,79 @@ async def request_pin(session_id, *args, **kwargs): from trezor.ui.confirm import ConfirmDialog, CONFIRMED from trezor.ui.pin import PinMatrix + global matrix + + _, label = _get_code_and_label(code) + await wire.reply_message(session_id, ButtonRequest(code=ProtectCall), ButtonAck) ui.display.clear() - matrix = PinMatrix(*args, **kwargs) + matrix = PinMatrix(label) dialog = ConfirmDialog(matrix) + pin = matrix.pin + matrix = None + if await dialog != CONFIRMED: raise wire.FailureError(PinCancelled, 'PIN cancelled') + return pin - return matrix.pin + +@unimport +async def request_pin_on_client(session_id: int, code: int=None) -> str: + from trezor.messages.FailureType import PinCancelled + from trezor.messages.PinMatrixRequest import PinMatrixRequest + from trezor.messages.wire_types import PinMatrixAck, Cancel + from trezor.ui.pin import PinMatrix + + global matrix + + code, label = _get_code_and_label(code) + + ui.display.clear() + matrix = PinMatrix(label) + matrix.render() + + ack = await wire.reply_message(session_id, + PinMatrixRequest(code=code), + PinMatrixAck, Cancel) + digits = matrix.digits + matrix = None + + if ack.WIRE_TYPE == Cancel: + raise wire.FailureError(PinCancelled, 'PIN cancelled') + return _decode_pin(ack.pin, digits) + + +request_pin = request_pin_on_client @unimport -async def request_pin_twice(session_id): +async def request_pin_twice(session_id: int) -> str: from trezor.messages.FailureType import PinInvalid + from trezor.messages import PinMatrixRequestType - pin_first = await request_pin(session_id) - pin_again = await request_pin(session_id, 'Enter PIN again') + pin_first = await request_pin(session_id, PinMatrixRequestType.NewFirst) + pin_again = await request_pin(session_id, PinMatrixRequestType.NewSecond) if pin_first != pin_again: raise wire.FailureError(PinInvalid, 'PIN invalid') return pin_first + + +def _get_code_and_label(code: int) -> str: + from trezor.messages import PinMatrixRequestType + if code is None: + code = PinMatrixRequestType.Current + if code == PinMatrixRequestType.NewFirst: + label = 'Enter new PIN' + elif code == PinMatrixRequestType.NewSecond: + label = 'Enter new PIN again' + else: # PinMatrixRequestType.Current + label = 'Enter PIN' + return code, label + + +def _decode_pin(pin: str, secret: list) -> str: + return ''.join([str(secret[int(d) - 1]) for d in pin]) diff --git a/src/trezor/ui/pin.py b/src/trezor/ui/pin.py index 2151de441..028606a13 100644 --- a/src/trezor/ui/pin.py +++ b/src/trezor/ui/pin.py @@ -10,7 +10,9 @@ def digit_area(i): height = const(48) x = (i % 3) * width y = (i // 3) * height - return (x, y + 48, width - 1, height - 1) # 48px is offset of input line / -1px is due to corner bug of overlaying elements + # 48px is offset of input line / -1px is due to corner bug of overlaying + # elements + return (x, y + 48, width - 1, height - 1) def generate_digits(): @@ -21,15 +23,21 @@ def generate_digits(): class PinMatrix(): - def __init__(self, label='Enter PIN', pin=''): + def __init__(self, label, pin=''): self.label = label self.pin = pin + self.digits = generate_digits() + + # we lay out the buttons top-left to bottom-right, but the order of the + # digits is defined as bottom-left to top-right (on numpad) + reordered_digits = self.digits[6:] + self.digits[3:6] + self.digits[:3] + self.pin_buttons = [Button(digit_area(i), str(d)) + for i, d in enumerate(reordered_digits)] + self.clear_button = Button((240 - 35, 5, 30, 30), res.load('trezor/res/pin_close.toig'), normal_style=CLEAR_BUTTON, active_style=CLEAR_BUTTON_ACTIVE) - self.pin_buttons = [Button(digit_area(i), str(d)) - for i, d in enumerate(generate_digits())] def render(self):