mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-30 01:58:11 +00:00
50dc265162
This commit replaces request_passphrase with flow_request_passphrase. The added benefit is that the user is prompted for confirmation if they want to proceed with an empty passphrase.
160 lines
4.4 KiB
Python
160 lines
4.4 KiB
Python
import time
|
|
from typing import Iterator, Tuple
|
|
|
|
Coords = Tuple[int, int]
|
|
|
|
DISPLAY_WIDTH = 240
|
|
DISPLAY_HEIGHT = 240
|
|
|
|
|
|
def grid(dim: int, grid_cells: int, cell: int) -> int:
|
|
step = dim // grid_cells
|
|
ofs = step // 2
|
|
return cell * step + ofs
|
|
|
|
|
|
def grid35(x: int, y: int) -> Coords:
|
|
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 5, y)
|
|
|
|
|
|
def grid34(x: int, y: int) -> Coords:
|
|
return grid(DISPLAY_WIDTH, 3, x), grid(DISPLAY_HEIGHT, 4, y)
|
|
|
|
|
|
def _grid34_from_index(idx: int) -> Coords:
|
|
grid_x = idx % 3
|
|
grid_y = idx // 3 + 1 # first line is empty
|
|
return grid34(grid_x, grid_y)
|
|
|
|
|
|
LEFT = grid(DISPLAY_WIDTH, 3, 0)
|
|
MID = grid(DISPLAY_WIDTH, 3, 1)
|
|
RIGHT = grid(DISPLAY_WIDTH, 3, 2)
|
|
|
|
TOP = grid(DISPLAY_HEIGHT, 6, 0)
|
|
BOTTOM = grid(DISPLAY_HEIGHT, 6, 5)
|
|
|
|
OK = (RIGHT, BOTTOM)
|
|
CANCEL = (LEFT, BOTTOM)
|
|
INFO = (MID, BOTTOM)
|
|
|
|
RECOVERY_DELETE = (LEFT, TOP)
|
|
|
|
CORNER_BUTTON = (215, 25)
|
|
|
|
CONFIRM_WORD = (MID, TOP)
|
|
TOP_ROW = (MID, TOP)
|
|
|
|
MERCURY_YES = grid34(2, 2)
|
|
MERCURY_NO = grid34(0, 2)
|
|
|
|
|
|
def reset_minus(model_internal_name: str) -> Coords:
|
|
RESET_MINUS_T3T1 = (LEFT, grid(DISPLAY_HEIGHT, 5, 3))
|
|
RESET_MINUS = (LEFT, grid(DISPLAY_HEIGHT, 5, 1))
|
|
if model_internal_name == "T3T1":
|
|
return RESET_MINUS_T3T1
|
|
else:
|
|
return RESET_MINUS
|
|
|
|
|
|
def reset_plus(model_internal_name: str) -> Coords:
|
|
RESET_PLUS_T3T1 = (RIGHT, grid(DISPLAY_HEIGHT, 5, 3))
|
|
RESET_PLUS = (RIGHT, grid(DISPLAY_HEIGHT, 5, 1))
|
|
if model_internal_name == "T3T1":
|
|
return RESET_PLUS_T3T1
|
|
else:
|
|
return RESET_PLUS
|
|
|
|
|
|
RESET_WORD_CHECK = [
|
|
(MID, grid(DISPLAY_HEIGHT, 5, 2)),
|
|
(MID, grid(DISPLAY_HEIGHT, 5, 3)),
|
|
(MID, grid(DISPLAY_HEIGHT, 5, 4)),
|
|
]
|
|
|
|
VERTICAL_MENU = [
|
|
(MID, grid(DISPLAY_HEIGHT, 4, 1)),
|
|
(MID, grid(DISPLAY_HEIGHT, 4, 2)),
|
|
(MID, grid(DISPLAY_HEIGHT, 4, 3)),
|
|
]
|
|
|
|
TAP_TO_CONFIRM = VERTICAL_MENU[1]
|
|
|
|
|
|
BUTTON_LETTERS_BIP39 = ("abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz")
|
|
BUTTON_LETTERS_SLIP39 = ("ab", "cd", "ef", "ghij", "klm", "nopq", "rs", "tuv", "wxyz")
|
|
|
|
# fmt: off
|
|
PASSPHRASE_LOWERCASE = (" ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz", "*#")
|
|
PASSPHRASE_UPPERCASE = (" ", "ABC", "DEF", "GHI", "JKL", "MNO", "PQRS", "TUV", "WXYZ", "*#")
|
|
PASSPHRASE_DIGITS = ("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
|
|
PASSPHRASE_SPECIAL = ("_<>", ".:@", "/|\\", "!()", "+%&", "-[]", "?{}", ",'`", ";\"~", "$^=")
|
|
# fmt: on
|
|
|
|
|
|
def get_passphrase_choices(char: str) -> tuple[str, ...]:
|
|
if char in " *#":
|
|
return PASSPHRASE_LOWERCASE
|
|
|
|
if char.islower():
|
|
return PASSPHRASE_LOWERCASE
|
|
elif char.isupper():
|
|
return PASSPHRASE_UPPERCASE
|
|
elif char.isdigit():
|
|
return PASSPHRASE_DIGITS
|
|
else:
|
|
return PASSPHRASE_SPECIAL
|
|
|
|
|
|
def passphrase(char: str) -> Tuple[Coords, int]:
|
|
choices = get_passphrase_choices(char)
|
|
idx = next(i for i, letters in enumerate(choices) if char in letters)
|
|
click_amount = choices[idx].index(char) + 1
|
|
return pin_passphrase_index(idx), click_amount
|
|
|
|
|
|
def pin_passphrase_index(idx: int) -> Coords:
|
|
if idx == 9:
|
|
idx = 10 # last digit is in the middle
|
|
return pin_passphrase_grid(idx)
|
|
|
|
|
|
def pin_passphrase_grid(idx: int) -> Coords:
|
|
grid_x = idx % 3
|
|
grid_y = idx // 3 + 1 # first line is empty
|
|
return grid35(grid_x, grid_y)
|
|
|
|
|
|
def type_word(word: str, is_slip39: bool = False) -> Iterator[Coords]:
|
|
if is_slip39:
|
|
yield from _type_word_slip39(word)
|
|
else:
|
|
yield from _type_word_bip39(word)
|
|
|
|
|
|
def _type_word_slip39(word: str) -> Iterator[Coords]:
|
|
for l in word:
|
|
idx = next(i for i, letters in enumerate(BUTTON_LETTERS_SLIP39) if l in letters)
|
|
yield _grid34_from_index(idx)
|
|
|
|
|
|
def _type_word_bip39(word: str) -> Iterator[Coords]:
|
|
coords_prev: Coords | None = None
|
|
for letter in word:
|
|
time.sleep(0.1) # not being so quick to miss something
|
|
coords, amount = _letter_coords_and_amount(letter)
|
|
# If the button is the same as for the previous letter,
|
|
# waiting a second before pressing it again.
|
|
if coords == coords_prev:
|
|
time.sleep(1.1)
|
|
coords_prev = coords
|
|
for _ in range(amount):
|
|
yield coords
|
|
|
|
|
|
def _letter_coords_and_amount(letter: str) -> Tuple[Coords, int]:
|
|
idx = next(i for i, letters in enumerate(BUTTON_LETTERS_BIP39) if letter in letters)
|
|
click_amount = BUTTON_LETTERS_BIP39[idx].index(letter) + 1
|
|
return _grid34_from_index(idx), click_amount
|