From b5220e8675d3b570e7190036977f01ec00c37f72 Mon Sep 17 00:00:00 2001 From: Peter Jensen Date: Tue, 16 Jan 2018 17:48:06 +0100 Subject: [PATCH 1/6] apps/management/reset_device: add icons and warning --- assets/dontcopy.png | Bin 0 -> 1293 bytes src/apps/management/reset_device.py | 9 ++++++--- src/trezor/res/nocopy.toig | Bin 0 -> 147 bytes src/trezor/ui/style.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 assets/dontcopy.png create mode 100644 src/trezor/res/nocopy.toig diff --git a/assets/dontcopy.png b/assets/dontcopy.png new file mode 100644 index 0000000000000000000000000000000000000000..4a1480f22b14dc1262269216aff65e81838020f4 GIT binary patch literal 1293 zcmXX_4>;3l9Diq~XwqnG{X>Qoq75OX8L>o*Y3Iq9EkrVZVz!w5d8|{q%0=2vs!OM- zkknnvtYaOX&Yz=`x?)9Fxr%c~WPbPC-F=_u`}us{&-3}d@AJIR^DU)Eg;`pxvH$>B z(!xWcVYW8*QWy}Xm-TC5HqQ!=%LQPWjj<6x@eK|DBrc6grPB}cj_`61^0FLgRH{Q( z4lgAwBN>2#r(8Ds!swfqW8DO;mQH6xkF6WS;W7AHt>}W}q~yHBSdN>2_+Go&L3_-o zJ%c$)l=-daUGo$(`Vh$WH-MCTSicv`;SPA z$wecPvhe8qe>K9W^TSV*VIR)e?4hNH!WpD2S42tPn6uN^)Px+-UW#Zhhn8*uhX8d^}eF6r1ruDM^a$<)|>FUzNGj*rWejVsi;pyQ~6nu5}KGsZS ze9iq63-%>9j+g8b?&4JpsaDo0>J}MW>t57iRM)P|Q6|JQglY!MZ5ySPIUk0$#r?WU zhkK^zRFae$Z#7#pz$qO!tq+)pSNc8Mv6XrB&=PLgT34S`XFC*Aum#0Ww#wVX^0eWt zw&#zq+f1Pa@w~Q_5+UQ4#G{MwJu4mU(y&+z3qvO7@A*w;dMD)hmBumoS)XfL2K-6x zBy#iXl*C8Lz0JK1#3zhTH@{F5>W{<@D=iG&SxZ7*%!Iw~JDxn%@B z-S9kiu;?DMrJ)J>5Tc|tyF%5gg5FP}Po6h4YkFx_M}?X>Y3+#++q;|Q?zrd9wN^OR zM>S-}sd=sA^25sAzP#b|TZca{udn{hSAXzVduBi~ng21-y0jn{QK61D5%YTwp~jFW z`X%&zL|6kM!N4!-iB#_Ae;gc%(GVr_C>iL2B-YKXUSOP2W`N}C4yf_Zr@aRYYgw6nnWdO`UFuw&L&kKNeYybkP0I=hg zC+c>>yT+r1P#6VIIexnK_DKjTHhZXo;{ZSqXH=iWKESTKY4+c7a;|q0vTHAvLlFM| zMBkYHb<(E>t)YejwFM$&Gq<2W(ay1t;m3_P03sNI0kVfR+vsc}LK}??AWt(G++a0* zx9Y3n{M(QRq0_^92OTHx{|=wqc5v;1F0+iCE8@vB7l*|+o`~1aUn_IKb-VdZH7dxt zDVSF@qNFMP7_A#KVA&D;m%
    5|X3?GXB+TUh;!du6w$G&AFQg^W%|D@691pY*-D zXAl$nAiG4(k!BvR%L;AmBE9#$zvQDh@^6#A3>P6no}>4b5DKw68~dDbtax95Js3@@ zK9z|{xE1(@{Ku?`(}2LR&(=hr($-3(swm9v2*7Z@60jK26?KZ#_X%s0cCY*bVv$p} z5^*~j+0uUi{BAV7 literal 0 HcmV?d00001 diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 689b76dfcf..05c39c7971 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -56,7 +56,10 @@ async def layout_reset_device(ctx, msg): entropy = ehash.digest() mnemonic = bip39.from_data(entropy[:msg.strength // 8]) - await show_mnemonic_by_word(ctx, mnemonic) + 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) + + await show_mnemonic(ctx, mnemonic) if curpin != newpin: config.change_pin(curpin, newpin) @@ -96,7 +99,7 @@ async def show_mnemonic_by_word(ctx, mnemonic): ConfirmWord, confirm='Next', cancel=None) -async def show_mnemonic(mnemonic): +async def show_mnemonic(ctx, mnemonic): from trezor.ui.scroll import paginate first_page = const(0) @@ -111,7 +114,7 @@ async def show_mnemonic_page(page, page_count, mnemonic): from trezor.ui.scroll import render_scrollbar, animate_swipe ui.display.clear() - ui.header('Write down your seed', ui.ICON_RESET, ui.BG, ui.LIGHT_GREEN) + ui.header('Write down seed', ui.ICON_RESET, ui.FG, ui.BG) render_scrollbar(page, page_count) for pi, (wi, word) in enumerate(mnemonic[page]): diff --git a/src/trezor/res/nocopy.toig b/src/trezor/res/nocopy.toig new file mode 100644 index 0000000000000000000000000000000000000000..eeb3029ebf3fa26c4ef2f5f5b6dc8d7a22f097e8 GIT binary patch literal 147 zcmV;E0BrwMPf2GI01^O)0000xr@#OPjPD;YFu1n@S-SrO825;u-hclUbpHc2GX4Lr!1Dhggu(S6s1d~A|GNJX12d4p_nGIv z0!W1Yf7Snw3~fLy>;HpP0U0dqhUXtK{NFjVy}W$?e}(-25b%k)91Qw_s=$Eh4FC{p BO~wEK literal 0 HcmV?d00001 diff --git a/src/trezor/ui/style.py b/src/trezor/ui/style.py index 59ae73aae4..42cef048d1 100644 --- a/src/trezor/ui/style.py +++ b/src/trezor/ui/style.py @@ -55,6 +55,7 @@ ICON_LOCK = 'trezor/res/lock.toig' ICON_SEND = 'trezor/res/send.toig' ICON_CLICK = 'trezor/res/click.toig' ICON_BACK = 'trezor/res/left.toig' +ICON_NOCOPY = 'trezor/res/nocopy.toig' # buttons BTN_DEFAULT = { @@ -153,5 +154,5 @@ LDR_DEFAULT_ACTIVE = { 'bg-color': BG, 'fg-color': GREEN, 'icon': ICON_SEND, - 'icon-fg-color': GREEN, + 'icon-fg-color': WHITE, } From 44ca1ea70330a7703e46571d298ba6038891b975 Mon Sep 17 00:00:00 2001 From: Peter Jensen Date: Wed, 17 Jan 2018 17:42:55 +0100 Subject: [PATCH 2/6] apps/management/reset_device: update styles --- assets/swipedown.png | Bin 0 -> 1303 bytes src/apps/management/reset_device.py | 32 +++++++++++++++------------- src/trezor/res/swipedown.toig | Bin 0 -> 137 bytes src/trezor/ui/scroll.py | 19 ++++++++++------- src/trezor/ui/style.py | 1 + src/trezor/ui/text.py | 21 ++++++++++++------ 6 files changed, 44 insertions(+), 29 deletions(-) create mode 100644 assets/swipedown.png create mode 100644 src/trezor/res/swipedown.toig diff --git a/assets/swipedown.png b/assets/swipedown.png new file mode 100644 index 0000000000000000000000000000000000000000..00af05f40cf59e67ed64cfc339b1a807dec5f4a9 GIT binary patch literal 1303 zcmV+y1?c*TP)U8P*7-ZbZ>KLZ*U+lnSp_Ufq@}0xwybFAi#%#fq@|}KQEO56)-X|e7nZL z$iTqBa9P*U#mSX{G{Bl%P*lRez;J+pfx##xwK$o9f#C}S14DXwNkIt%17i#W1A|CX zc0maP17iUL1A|C*NRTrF17iyV0~1e4YDEbH0|SF|enDkXW_m`6f}y3QrGjHhep0GJ zaAk2xYHqQDXI^rCQ9*uDVo7QW0|Nup4h9AW240u^5(W3f%sd4n162kpgNVo|1qcff zJ_s=cNG>fZg9jx8g8+j9g8_pBLjXe}Lp{R+hNBE`7{wV~7)u#fFy3PlV+vxLz;uCG zm^qSpA@ds+OO_6nTdaDlt*rOhEZL^9ePa)2-_4=K(Z%tFGm-NGmm}8}ZcXk5JW@PU zd4+f<@d@)yL(o<5icqT158+-B6_LH7;i6x}CW#w~Uy-Pgl#@Irl`kzV zeL|*8R$ca%T%Wv){2zs_iiJvgN^h0dsuZZ2sQy$tsNSU!s;Q*;LF<6_B%M@UD?LHI zSNcZ`78uqV#TeU~$eS{ozBIdFzSClfs*^S+dw;4dus<{M;#|MXC)T}S9v!D zcV!QCPhBq)ZyO(X-(bH4|NMaZz==UigLj2o41F2S6d@OB6%`R(5i>J(Puzn9wnW{e zu;hl6HK{k#IWjCVGqdJqU(99Cv(K+6*i`tgSi2;vbXD1#3jNBGs$DgVwO(~o>mN4i zHPtkqZIx>)Y(Ls5-Br|mx>vQYvH$Kwn@O`L|D75??eGkZnfg$5<;Xeg_o%+-I&+-3%01W^SH2RkDT>t<8AY({UO#lFTB>(_`g8%^e z{{R4h=>PzAFaQARU;qF*m;eA5Z<1fdMgRZ-c}YY;RCwBA6#B`)$o+)@00030|6=6+ z-_EG^{xtvq0RR7DRK3N>;Jb;D`>XdBMg{-?009601i>)@03Zy&u=d3nvQaQOJ4@ny zNQN{L>=8mf00030|6(*f#lXnGz`($eGMj;soBt^T10#dQafTO?j9lLsERQiTFfcGO zK$RrUV`N}pU;vObhgJxJQ2>R%S3wiaU|;|n)dg&_fDFMDPC+pmUBF5+o6HnVrbqbe zJ@=j)^?1#KhFknLmkFeEyj!OSl3n<2b+e@T2T8NA|5Q;74li|-*6~SIKH1-4Woiyt z8VchuivRv#koS$ks)$84kS$Ivf>{iFprep8*udou3ur*{)t>V{XBryhw}w|H#btG z3Y{6O;~37qkRzAiX0pGyn1cLUK<^p1<2~g#+Nz@tc&Z*l9cmoz1^{D=R7*v#{s;g7 N002ovPDHLkV1kz(HhKU6 literal 0 HcmV?d00001 diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 05c39c7971..44fdeba0e2 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -8,7 +8,6 @@ if __debug__: internal_entropy = None current_word = None - @unimport async def layout_reset_device(ctx, msg): from trezor import config @@ -56,10 +55,16 @@ async def layout_reset_device(ctx, msg): entropy = ehash.digest() mnemonic = bip39.from_data(entropy[:msg.strength // 8]) - 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!') + # 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) - await show_mnemonic(ctx, mnemonic) + await show_mnemonic(mnemonic) if curpin != newpin: config.change_pin(curpin, newpin) @@ -99,7 +104,7 @@ async def show_mnemonic_by_word(ctx, mnemonic): ConfirmWord, confirm='Next', cancel=None) -async def show_mnemonic(ctx, mnemonic): +async def show_mnemonic(mnemonic): from trezor.ui.scroll import paginate first_page = const(0) @@ -111,20 +116,17 @@ async def show_mnemonic(ctx, mnemonic): async def show_mnemonic_page(page, page_count, mnemonic): from trezor.ui.button import Button - from trezor.ui.scroll import render_scrollbar, animate_swipe - - ui.display.clear() - ui.header('Write down seed', ui.ICON_RESET, ui.FG, ui.BG) - render_scrollbar(page, page_count) + from trezor.ui.text import Text + from trezor.ui.scroll import Scrollpage, animate_swipe + lines = [] for pi, (wi, word) in enumerate(mnemonic[page]): - top = pi * 35 + 68 pos = wi + 1 - offset = 0 - if pos > 9: - offset += 12 - ui.display.text(10, top, '%d.' % pos, ui.BOLD, ui.LIGHT_GREEN, ui.BG) - ui.display.text(30 + offset, top, '%s' % word, ui.BOLD, ui.FG, ui.BG) + lines.append(str('%d. %s' % (pos, word))) + + 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( diff --git a/src/trezor/res/swipedown.toig b/src/trezor/res/swipedown.toig new file mode 100644 index 0000000000000000000000000000000000000000..0b5707ddf2bd7c3fef33a04819af15a2bab675b0 GIT binary patch literal 137 zcmV;40CxXWPf2GO01yCu0000jj=>GWKnw);LW0CE9gqeP*FkvlOAB;B3sgZrR6q?> zfCA(f80`4`utxHFciW@NTvNp bbox: padding = bbox // page_count @@ -62,11 +60,16 @@ def render_scrollbar(page, page_count): size, ui.FG, ui.BG, 4) -class Scrollbar(ui.Widget): +class Scrollpage(ui.Widget): - def __init__(self, page, page_count): + def __init__(self, content, page, page_count): + self.content = content self.page = page self.page_count = page_count def render(self): + self.content.render() render_scrollbar(self.page, self.page_count) + + async def __iter__(self): + return await loop.wait(super().__iter__(), self.content) diff --git a/src/trezor/ui/style.py b/src/trezor/ui/style.py index 42cef048d1..7e21370dfe 100644 --- a/src/trezor/ui/style.py +++ b/src/trezor/ui/style.py @@ -56,6 +56,7 @@ ICON_SEND = 'trezor/res/send.toig' ICON_CLICK = 'trezor/res/click.toig' ICON_BACK = 'trezor/res/left.toig' ICON_NOCOPY = 'trezor/res/nocopy.toig' +ICON_SWIPE = 'trezor/res/swipedown.toig' # buttons BTN_DEFAULT = { diff --git a/src/trezor/ui/text.py b/src/trezor/ui/text.py index 3d8338312d..688aca8648 100644 --- a/src/trezor/ui/text.py +++ b/src/trezor/ui/text.py @@ -22,11 +22,20 @@ class Text(ui.Widget): bg = ui.BG ui.header(self.header_text, self.header_icon, ui.TITLE_GREY, ui.BG, self.icon_color) - for item in self.content: - if isinstance(item, str): - ui.display.text(offset_x, offset_y, item, style, fg, bg) + def process(eitem): + nonlocal offset_y + nonlocal style + nonlocal fg + if isinstance(eitem, str): + ui.display.text(offset_x, offset_y, eitem, style, fg, bg) offset_y += TEXT_LINE_HEIGHT - elif item == ui.MONO or item == ui.NORMAL or item == ui.BOLD: - style = item + elif isinstance(eitem, (tuple, list, dict, set)): + for i in eitem: + process(i) + elif eitem == ui.MONO or eitem == ui.NORMAL or eitem == ui.BOLD: + style = eitem else: - fg = item + fg = eitem + + for item in self.content: + process(item) From f5445d7db97f1d3242764aee826fd1663723bea4 Mon Sep 17 00:00:00 2001 From: Peter Jensen Date: Wed, 17 Jan 2018 18:34:39 +0100 Subject: [PATCH 3/6] apps/management/reset_device: adding check for written seed --- src/apps/management/reset_device.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 44fdeba0e2..8aa3cf0731 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -12,13 +12,13 @@ if __debug__: async def layout_reset_device(ctx, msg): from trezor import config from trezor.ui.text import Text - from trezor.crypto import hashlib, random, bip39 + from trezor.crypto import hashlib, random, bip39, random + from trezor.ui.keyboard import MnemonicKeyboard from trezor.messages.EntropyRequest import EntropyRequest from trezor.messages.Success import Success from trezor.messages import FailureType from trezor.messages import ButtonRequestType from trezor.messages.wire_types import EntropyAck - from apps.management.change_pin import request_pin_confirm from apps.common.confirm import require_confirm from apps.common import storage @@ -61,11 +61,27 @@ async def layout_reset_device(ctx, msg): 'copy of your recovery', 'seed and never upload', 'it online!') - await require_confirm(ctx, warning_content, ButtonRequestType.ResetDevice) + # ask to write down mnemonic await show_mnemonic(mnemonic) + # ask for random number to check correctness + words = list(enumerate(mnemonic.split())) + index = random.uniform(len(words)) + word = words[index] + board = MnemonicKeyboard() + board.prompt = ('Type %s. word' % (index + 1)) + res = await board + # TBD + if res is not word: + fail_content = Text('Failed!', ui.ICON_NOCOPY, ui.NORMAL, + 'You have entered', + 'wrong seed word.', + 'Please, reconnect', + 'device and try again.') + await require_confirm(ctx, fail_content, ButtonRequestType.ResetDevice) + if curpin != newpin: config.change_pin(curpin, newpin) storage.load_settings(label=msg.label, @@ -123,15 +139,13 @@ async def show_mnemonic_page(page, page_count, mnemonic): for pi, (wi, word) in enumerate(mnemonic[page]): pos = wi + 1 lines.append(str('%d. %s' % (pos, word))) - 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), - 'Finish', + 'Finalize', normal_style=ui.BTN_CONFIRM, active_style=ui.BTN_CONFIRM_ACTIVE) else: From acf9d789c73ab5788351a0db537e6fae9e14c7d8 Mon Sep 17 00:00:00 2001 From: Peter Jensen Date: Fri, 19 Jan 2018 13:17:50 +0100 Subject: [PATCH 4/6] ui/confirm: correct button positions --- src/trezor/ui/confirm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/trezor/ui/confirm.py b/src/trezor/ui/confirm.py index 5d9c278f7c..2eb381d9e4 100644 --- a/src/trezor/ui/confirm.py +++ b/src/trezor/ui/confirm.py @@ -16,10 +16,10 @@ class ConfirmDialog(Widget): def __init__(self, content, confirm=DEFAULT_CONFIRM, cancel=DEFAULT_CANCEL): self.content = content if cancel is not None: - self.confirm = Button(ui.grid(8, n_x=2), confirm, + self.confirm = Button(ui.grid(9, n_x=2), confirm, normal_style=ui.BTN_CONFIRM, active_style=ui.BTN_CONFIRM_ACTIVE) - self.cancel = Button(ui.grid(9, n_x=2), cancel, + self.cancel = Button(ui.grid(8, n_x=2), cancel, normal_style=ui.BTN_CANCEL, active_style=ui.BTN_CANCEL_ACTIVE) else: From 5701e57b48798f742b861d5a20eb4893865c0e22 Mon Sep 17 00:00:00 2001 From: Peter Jensen Date: Fri, 19 Jan 2018 14:54:39 +0100 Subject: [PATCH 5/6] apps/management/reset_device: improve visuals --- src/apps/management/reset_device.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 8aa3cf0731..5b6c5d348e 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -69,25 +69,33 @@ async def layout_reset_device(ctx, msg): # ask for random number to check correctness words = list(enumerate(mnemonic.split())) index = random.uniform(len(words)) - word = words[index] + word = words[index][1] board = MnemonicKeyboard() board.prompt = ('Type %s. word' % (index + 1)) res = await board - # TBD - if res is not word: - fail_content = Text('Failed!', ui.ICON_NOCOPY, ui.NORMAL, + 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.') + '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) - + if curpin != newpin: config.change_pin(curpin, newpin) 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) + return Success(message='Initialized') @@ -148,5 +156,6 @@ async def show_mnemonic_page(page, page_count, mnemonic): 'Finalize', normal_style=ui.BTN_CONFIRM, active_style=ui.BTN_CONFIRM_ACTIVE) + ui.display.clear() else: await animate_swipe() From 57e350fbbf74e91fe1358bc9580488d542559bde Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Mon, 22 Jan 2018 15:29:53 +0100 Subject: [PATCH 6/6] apps/management/reset_device: minor fixes --- src/apps/management/__init__.py | 4 +- src/apps/management/reset_device.py | 128 +++++++++++++--------------- 2 files changed, 59 insertions(+), 73 deletions(-) diff --git a/src/apps/management/__init__.py b/src/apps/management/__init__.py index df1d776fba..88ff912d81 100644 --- a/src/apps/management/__init__.py +++ b/src/apps/management/__init__.py @@ -12,8 +12,8 @@ def dispatch_LoadDevice(*args, **kwargs): @unimport def dispatch_ResetDevice(*args, **kwargs): - from .reset_device import layout_reset_device - return layout_reset_device(*args, **kwargs) + from .reset_device import reset_device + return reset_device(*args, **kwargs) @unimport diff --git a/src/apps/management/reset_device.py b/src/apps/management/reset_device.py index 5b6c5d348e..77fdb7d210 100644 --- a/src/apps/management/reset_device.py +++ b/src/apps/management/reset_device.py @@ -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()