|
|
|
@ -1,6 +1,5 @@
|
|
|
|
|
from micropython import const
|
|
|
|
|
from trezor import wire, ui
|
|
|
|
|
from trezor.ui.container import Container
|
|
|
|
|
from trezor import config, ui, wire
|
|
|
|
|
from trezor.utils import unimport, chunks
|
|
|
|
|
from ubinascii import hexlify
|
|
|
|
|
|
|
|
|
@ -8,11 +7,11 @@ if __debug__:
|
|
|
|
|
internal_entropy = None
|
|
|
|
|
current_word = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unimport
|
|
|
|
|
async def layout_reset_device(ctx, msg):
|
|
|
|
|
from trezor import config
|
|
|
|
|
async def reset_device(ctx, msg):
|
|
|
|
|
from trezor.ui.text import Text
|
|
|
|
|
from trezor.crypto import hashlib, random, bip39, random
|
|
|
|
|
from trezor.crypto import hashlib, random, bip39
|
|
|
|
|
from trezor.ui.keyboard import MnemonicKeyboard
|
|
|
|
|
from trezor.messages.EntropyRequest import EntropyRequest
|
|
|
|
|
from trezor.messages.Success import Success
|
|
|
|
@ -36,11 +35,13 @@ async def layout_reset_device(ctx, msg):
|
|
|
|
|
|
|
|
|
|
internal_entropy = random.bytes(32)
|
|
|
|
|
|
|
|
|
|
# display internal entropy
|
|
|
|
|
if msg.display_random:
|
|
|
|
|
entropy_lines = chunks(hexlify(internal_entropy).decode(), 16)
|
|
|
|
|
entropy_content = Text('Internal entropy', ui.ICON_RESET, ui.MONO, *entropy_lines)
|
|
|
|
|
await require_confirm(ctx, entropy_content, ButtonRequestType.ResetDevice)
|
|
|
|
|
|
|
|
|
|
# request new PIN
|
|
|
|
|
if msg.pin_protection:
|
|
|
|
|
curpin = ''
|
|
|
|
|
newpin = await request_pin_confirm(ctx)
|
|
|
|
@ -48,6 +49,7 @@ async def layout_reset_device(ctx, msg):
|
|
|
|
|
curpin = ''
|
|
|
|
|
newpin = ''
|
|
|
|
|
|
|
|
|
|
# request external entropy and compute mnemonic
|
|
|
|
|
external_entropy_ack = await ctx.call(EntropyRequest(), EntropyAck)
|
|
|
|
|
ehash = hashlib.sha256()
|
|
|
|
|
ehash.update(internal_entropy)
|
|
|
|
@ -55,79 +57,62 @@ async def layout_reset_device(ctx, msg):
|
|
|
|
|
entropy = ehash.digest()
|
|
|
|
|
mnemonic = bip39.from_data(entropy[:msg.strength // 8])
|
|
|
|
|
|
|
|
|
|
# seed-copy warning
|
|
|
|
|
warning_content = Text('Backup your seed', ui.ICON_NOCOPY, ui.NORMAL,
|
|
|
|
|
'Never make a digital',
|
|
|
|
|
'copy of your recovery',
|
|
|
|
|
'seed and never upload',
|
|
|
|
|
'it online!')
|
|
|
|
|
await require_confirm(ctx, warning_content, ButtonRequestType.ResetDevice)
|
|
|
|
|
# mnemonic safety warning
|
|
|
|
|
warning_content = Text(
|
|
|
|
|
'Backup your seed', ui.ICON_NOCOPY, ui.NORMAL,
|
|
|
|
|
'Never make a digital',
|
|
|
|
|
'copy of your recovery',
|
|
|
|
|
'seed and never upload',
|
|
|
|
|
'it online!')
|
|
|
|
|
await require_confirm(
|
|
|
|
|
ctx,
|
|
|
|
|
warning_content,
|
|
|
|
|
ButtonRequestType.ResetDevice,
|
|
|
|
|
confirm='I understand',
|
|
|
|
|
cancel=None)
|
|
|
|
|
|
|
|
|
|
# ask to write down mnemonic
|
|
|
|
|
await show_mnemonic(mnemonic)
|
|
|
|
|
|
|
|
|
|
# ask for random number to check correctness
|
|
|
|
|
words = list(enumerate(mnemonic.split()))
|
|
|
|
|
# ask for random word to check correctness
|
|
|
|
|
words = mnemonic.split()
|
|
|
|
|
index = random.uniform(len(words))
|
|
|
|
|
word = words[index][1]
|
|
|
|
|
board = MnemonicKeyboard()
|
|
|
|
|
board.prompt = ('Type %s. word' % (index + 1))
|
|
|
|
|
res = await board
|
|
|
|
|
if res != word:
|
|
|
|
|
fail_content = Text('Wrong entry!', ui.ICON_CLEAR, ui.NORMAL,
|
|
|
|
|
'You have entered',
|
|
|
|
|
'wrong seed word.',
|
|
|
|
|
'Please, reconnect',
|
|
|
|
|
'device and try again.', icon_color=ui.RED)
|
|
|
|
|
# todo redesign dialog to single cancel button with text 'Reconnect' or something else (no icon)
|
|
|
|
|
await require_confirm(ctx, fail_content, ButtonRequestType.ResetDevice)
|
|
|
|
|
res = await MnemonicKeyboard('Type %s. word' % (index + 1))
|
|
|
|
|
if res != words[index]:
|
|
|
|
|
content = Text(
|
|
|
|
|
'Wrong entry!', ui.ICON_CLEAR,
|
|
|
|
|
'You have entered',
|
|
|
|
|
'wrong seed word.',
|
|
|
|
|
'Please, reconnect',
|
|
|
|
|
'the device and try again.', icon_color=ui.RED)
|
|
|
|
|
ui.display.clear()
|
|
|
|
|
await content
|
|
|
|
|
raise wire.FailureError(FailureType.DataError, 'Wrong entry')
|
|
|
|
|
|
|
|
|
|
# write into storage
|
|
|
|
|
if curpin != newpin:
|
|
|
|
|
config.change_pin(curpin, newpin)
|
|
|
|
|
storage.load_settings(label=msg.label,
|
|
|
|
|
use_passphrase=msg.passphrase_protection)
|
|
|
|
|
storage.load_settings(
|
|
|
|
|
label=msg.label, use_passphrase=msg.passphrase_protection)
|
|
|
|
|
storage.load_mnemonic(mnemonic)
|
|
|
|
|
|
|
|
|
|
fail_content = Text('Backup is done!', ui.ICON_CONFIRM, ui.NORMAL,
|
|
|
|
|
'Never make a digital',
|
|
|
|
|
'copy of your recovery',
|
|
|
|
|
'seed and never upload',
|
|
|
|
|
'it online!', icon_color=ui.GREEN)
|
|
|
|
|
# todo redesign dialog to single cancel button with text 'Finish?' or something else (no icon)
|
|
|
|
|
await require_confirm(ctx, fail_content, ButtonRequestType.ResetDevice)
|
|
|
|
|
# show success message
|
|
|
|
|
content = Text(
|
|
|
|
|
'Backup is done!', ui.ICON_CONFIRM,
|
|
|
|
|
'Never make a digital',
|
|
|
|
|
'copy of your recovery',
|
|
|
|
|
'seed and never upload',
|
|
|
|
|
'it online!', icon_color=ui.GREEN)
|
|
|
|
|
await require_confirm(
|
|
|
|
|
ctx,
|
|
|
|
|
content,
|
|
|
|
|
ButtonRequestType.ResetDevice,
|
|
|
|
|
confirm='Finish setup',
|
|
|
|
|
cancel=None)
|
|
|
|
|
|
|
|
|
|
return Success(message='Initialized')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def show_mnemonic_by_word(ctx, mnemonic):
|
|
|
|
|
from trezor.ui.text import Text
|
|
|
|
|
from trezor.messages.ButtonRequestType import ConfirmWord
|
|
|
|
|
from apps.common.confirm import confirm
|
|
|
|
|
|
|
|
|
|
words = mnemonic.split()
|
|
|
|
|
|
|
|
|
|
if __debug__:
|
|
|
|
|
global current_word
|
|
|
|
|
|
|
|
|
|
for index, word in enumerate(words):
|
|
|
|
|
if __debug__:
|
|
|
|
|
current_word = word
|
|
|
|
|
await confirm(ctx,
|
|
|
|
|
Text('Recovery seed setup', ui.ICON_RESET,
|
|
|
|
|
ui.NORMAL, 'Write down seed word', '',
|
|
|
|
|
ui.BOLD, '%d. %s' % (index + 1, word)),
|
|
|
|
|
ConfirmWord, confirm='Next', cancel=None)
|
|
|
|
|
|
|
|
|
|
for index, word in enumerate(words):
|
|
|
|
|
if __debug__:
|
|
|
|
|
current_word = word
|
|
|
|
|
await confirm(ctx,
|
|
|
|
|
Text('Recovery seed setup', ui.ICON_RESET,
|
|
|
|
|
ui.NORMAL, 'Confirm seed word', '',
|
|
|
|
|
ui.BOLD, '%d. %s' % (index + 1, word)),
|
|
|
|
|
ConfirmWord, confirm='Next', cancel=None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def show_mnemonic(mnemonic):
|
|
|
|
|
from trezor.ui.scroll import paginate
|
|
|
|
|
|
|
|
|
@ -143,17 +128,18 @@ async def show_mnemonic_page(page, page_count, mnemonic):
|
|
|
|
|
from trezor.ui.text import Text
|
|
|
|
|
from trezor.ui.scroll import Scrollpage, animate_swipe
|
|
|
|
|
|
|
|
|
|
lines = []
|
|
|
|
|
for pi, (wi, word) in enumerate(mnemonic[page]):
|
|
|
|
|
pos = wi + 1
|
|
|
|
|
lines.append(str('%d. %s' % (pos, word)))
|
|
|
|
|
lines = ['%d. %s' % (wi + 1, word) for wi, word in mnemonic[page]]
|
|
|
|
|
scroll_page = Scrollpage(
|
|
|
|
|
Text('Recovery seed setup', ui.ICON_RESET, ui.MONO, lines),
|
|
|
|
|
page,
|
|
|
|
|
page_count)
|
|
|
|
|
ui.display.clear()
|
|
|
|
|
scroll_page = Scrollpage(Text('Recovery seed setup', ui.ICON_RESET, ui.MONO, lines), page, page_count)
|
|
|
|
|
scroll_page.render()
|
|
|
|
|
|
|
|
|
|
if page + 1 == page_count:
|
|
|
|
|
await Button(
|
|
|
|
|
(0, 240 - 48, 240, 48),
|
|
|
|
|
'Finalize',
|
|
|
|
|
ui.grid(4, n_x=1),
|
|
|
|
|
"I'm done",
|
|
|
|
|
normal_style=ui.BTN_CONFIRM,
|
|
|
|
|
active_style=ui.BTN_CONFIRM_ACTIVE)
|
|
|
|
|
ui.display.clear()
|
|
|
|
|