mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-05 13:01:12 +00:00
ui/passphrase: ask for source of passphrase
This commit is contained in:
parent
bd44eceeef
commit
7b89e4b14c
@ -1,4 +1,4 @@
|
|||||||
from trezor import ui, wire
|
from trezor import ui, wire, res
|
||||||
|
|
||||||
|
|
||||||
async def request_passphrase(ctx):
|
async def request_passphrase(ctx):
|
||||||
@ -6,17 +6,52 @@ async def request_passphrase(ctx):
|
|||||||
from trezor.messages.PassphraseRequest import PassphraseRequest
|
from trezor.messages.PassphraseRequest import PassphraseRequest
|
||||||
from trezor.messages.wire_types import PassphraseAck, Cancel
|
from trezor.messages.wire_types import PassphraseAck, Cancel
|
||||||
from trezor.ui.text import Text
|
from trezor.ui.text import Text
|
||||||
|
from trezor.ui.confirm import ConfirmDialog, CONFIRMED
|
||||||
|
from trezor.ui.entry_select import EntrySelector
|
||||||
|
from trezor.ui.keyboard import PassphraseKeyboard
|
||||||
|
|
||||||
ui.display.clear()
|
ui.display.clear()
|
||||||
text = Text('Enter passphrase', ui.ICON_RESET,
|
text = Text('Enter passphrase', ui.ICON_RESET,
|
||||||
'Please enter passphrase', 'on your computer.')
|
'Where to enter your', 'passphrase?')
|
||||||
text.render()
|
entry = EntrySelector(text)
|
||||||
|
entry_type = await entry
|
||||||
|
|
||||||
ack = await ctx.call(PassphraseRequest(), PassphraseAck, Cancel)
|
if entry_type == 1:
|
||||||
if ack.MESSAGE_WIRE_TYPE == Cancel:
|
ui.display.clear()
|
||||||
raise wire.FailureError(ActionCancelled, 'Passphrase cancelled')
|
text = Text('Passphrase entry', ui.ICON_RESET,
|
||||||
|
'Please, type passphrase', 'on connected host.')
|
||||||
|
text.render()
|
||||||
|
ack = await ctx.call(PassphraseRequest(), PassphraseAck, Cancel)
|
||||||
|
if ack.MESSAGE_WIRE_TYPE == Cancel:
|
||||||
|
raise wire.FailureError(ActionCancelled, 'Passphrase cancelled')
|
||||||
|
return ack.passphrase
|
||||||
|
else:
|
||||||
|
def onchange():
|
||||||
|
c = dialog.cancel
|
||||||
|
if keyboard.passphrase:
|
||||||
|
c.content = res.load(ui.ICON_CLEAR)
|
||||||
|
else:
|
||||||
|
c.content = res.load(ui.ICON_LOCK)
|
||||||
|
c.taint()
|
||||||
|
c.render()
|
||||||
|
|
||||||
return ack.passphrase
|
ui.display.clear()
|
||||||
|
keyboard = PassphraseKeyboard('Enter passphrase')
|
||||||
|
keyboard.onchange = onchange
|
||||||
|
dialog = ConfirmDialog(keyboard)
|
||||||
|
dialog.cancel.area = ui.grid(12)
|
||||||
|
dialog.confirm.area = ui.grid(14)
|
||||||
|
keyboard.onchange()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
result = await dialog
|
||||||
|
if result == CONFIRMED:
|
||||||
|
return keyboard.passphrase
|
||||||
|
elif result != CONFIRMED and keyboard.passphrase:
|
||||||
|
keyboard.change('')
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise wire.FailureError(ActionCancelled, 'Passphrase cancelled')
|
||||||
|
|
||||||
|
|
||||||
async def protect_by_passphrase(ctx):
|
async def protect_by_passphrase(ctx):
|
||||||
|
33
src/trezor/ui/entry_select.py
Normal file
33
src/trezor/ui/entry_select.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from micropython import const
|
||||||
|
from trezor import loop
|
||||||
|
from trezor import ui
|
||||||
|
from trezor.ui import Widget
|
||||||
|
from trezor.ui.button import Button, BTN_CLICKED
|
||||||
|
|
||||||
|
_DEVICE = const(0)
|
||||||
|
_HOST = const(1)
|
||||||
|
|
||||||
|
|
||||||
|
class EntrySelector(Widget):
|
||||||
|
|
||||||
|
def __init__(self, content):
|
||||||
|
self.content = content
|
||||||
|
self.device = Button(ui.grid(8, n_y=4, n_x=4, cells_x=4), 'Device',
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
self.host = Button(ui.grid(12, n_y=4, n_x=4, cells_x=4), 'Host',
|
||||||
|
normal_style=ui.BTN_KEY,
|
||||||
|
active_style=ui.BTN_KEY_ACTIVE)
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
self.device.render()
|
||||||
|
self.host.render()
|
||||||
|
|
||||||
|
def touch(self, event, pos):
|
||||||
|
if self.device.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return _DEVICE
|
||||||
|
if self.host.touch(event, pos) == BTN_CLICKED:
|
||||||
|
return _HOST
|
||||||
|
|
||||||
|
async def __iter__(self):
|
||||||
|
return await loop.wait(super().__iter__(), self.content)
|
@ -2,7 +2,14 @@ from trezor import ui, res, loop, io
|
|||||||
from trezor.crypto import bip39
|
from trezor.crypto import bip39
|
||||||
from trezor.ui import display
|
from trezor.ui import display
|
||||||
from trezor.ui.button import Button, BTN_CLICKED, ICON
|
from trezor.ui.button import Button, BTN_CLICKED, ICON
|
||||||
|
from .swipe import Swipe, SWIPE_LEFT, SWIPE_RIGHT, SWIPE_HORIZONTAL
|
||||||
|
|
||||||
|
KEYBOARD = {
|
||||||
|
'0': ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
|
||||||
|
'1': ['_', 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqrs', 'tuv', 'wxyz', '*#'],
|
||||||
|
'2': ['_', 'ABC', 'DEF', 'GHI', 'JKL', 'MNO', 'PQRS', 'TUV', 'WXYZ', '*#'],
|
||||||
|
'3': ['_', '.', '/', '!', '+', '-', '?', ',', ';', '$']
|
||||||
|
}
|
||||||
|
|
||||||
def key_buttons():
|
def key_buttons():
|
||||||
keys = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz']
|
keys = ['abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz']
|
||||||
@ -11,6 +18,24 @@ def key_buttons():
|
|||||||
for i, k in enumerate(keys)
|
for i, k in enumerate(keys)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def render_scrollbar(page):
|
||||||
|
bbox = const(240)
|
||||||
|
size = const(8)
|
||||||
|
padding = 12
|
||||||
|
page_count = len(KEYBOARD)
|
||||||
|
|
||||||
|
if page_count * padding > bbox:
|
||||||
|
padding = bbox // page_count
|
||||||
|
|
||||||
|
x = (bbox // 2) - (page_count // 2) * padding
|
||||||
|
y = 44
|
||||||
|
|
||||||
|
for i in range(0, page_count):
|
||||||
|
if i != page:
|
||||||
|
ui.display.bar_radius(x + i * padding, y, size,
|
||||||
|
size, ui.DARK_GREY, ui.BG, size // 2)
|
||||||
|
ui.display.bar_radius(x + page * padding, y, size,
|
||||||
|
size, ui.FG, ui.BG, size // 2)
|
||||||
|
|
||||||
def compute_mask(text: str) -> int:
|
def compute_mask(text: str) -> int:
|
||||||
mask = 0
|
mask = 0
|
||||||
@ -21,6 +46,14 @@ def compute_mask(text: str) -> int:
|
|||||||
mask |= 1 << shift
|
mask |= 1 << shift
|
||||||
return mask
|
return mask
|
||||||
|
|
||||||
|
def digit_area(i):
|
||||||
|
if i == 9: # 0-position
|
||||||
|
i = 10 # display it in the middle
|
||||||
|
return ui.grid(i + 3) # skip the first line
|
||||||
|
|
||||||
|
def generate_keyboard(index):
|
||||||
|
digits = list(range(0, 10)) # 0-9
|
||||||
|
return digits
|
||||||
|
|
||||||
class Input(Button):
|
class Input(Button):
|
||||||
def __init__(self, area: tuple, content: str='', word: str=''):
|
def __init__(self, area: tuple, content: str='', word: str=''):
|
||||||
@ -76,6 +109,41 @@ class Input(Button):
|
|||||||
iy = ty - ICON
|
iy = ty - ICON
|
||||||
display.icon(ix, iy, res.load(i), fg_color, bg_color)
|
display.icon(ix, iy, res.load(i), fg_color, bg_color)
|
||||||
|
|
||||||
|
class PassphraseKeyboard(ui.Widget):
|
||||||
|
def __init__(self, label):
|
||||||
|
self.label = label
|
||||||
|
self.passphrase = ''
|
||||||
|
self.index = 1
|
||||||
|
self.keyboard_type = 1
|
||||||
|
self.keys = KEYBOARD[str(self.keyboard_type)]
|
||||||
|
|
||||||
|
self.key_buttons = [Button(digit_area(i), d)
|
||||||
|
for i, d in enumerate(self.keys)]
|
||||||
|
self.onchange = None
|
||||||
|
|
||||||
|
def render(self):
|
||||||
|
# clear canvas under input line
|
||||||
|
display.bar(0, 0, 240, 45, ui.BG)
|
||||||
|
|
||||||
|
# input line with a header
|
||||||
|
header = self.passphrase if self.passphrase else self.label
|
||||||
|
display.text_center(120, 32, header, ui.BOLD, ui.GREY, ui.BG)
|
||||||
|
render_scrollbar(self.keyboard_type)
|
||||||
|
# pin matrix buttons
|
||||||
|
for btn in self.key_buttons:
|
||||||
|
btn.render()
|
||||||
|
|
||||||
|
def touch(self, event, pos):
|
||||||
|
for btn in self.key_buttons:
|
||||||
|
if btn.touch(event, pos) == BTN_CLICKED:
|
||||||
|
self.change(self.passphrase + btn.content)
|
||||||
|
break
|
||||||
|
|
||||||
|
def change(self, passphrase):
|
||||||
|
self.passphrase = passphrase
|
||||||
|
if self.onchange:
|
||||||
|
self.onchange()
|
||||||
|
|
||||||
|
|
||||||
class MnemonicKeyboard(ui.Widget):
|
class MnemonicKeyboard(ui.Widget):
|
||||||
def __init__(self, prompt: str=''):
|
def __init__(self, prompt: str=''):
|
||||||
|
Loading…
Reference in New Issue
Block a user