async def _require_confirm_address(ctx, action: str, address: str): text = Text("Confirm address", ui.ICON_SEND, icon_color=ui.GREEN) text.normal(action) text.mono(*split_address(address)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def recovery_device(ctx, msg): """ Recover BIP39 seed into empty device. 1. Ask for the number of words in recovered seed. 2. Let user type in the mnemonic words one by one. 3. Optionally check the seed validity. 4. Optionally ask for the PIN, with confirmation. 5. Save into storage. """ if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") if not msg.dry_run: title = "Device recovery" text = Text(title, ui.ICON_RECOVERY) text.normal("Do you really want to", "recover the device?", "") else: title = "Simulated recovery" text = Text(title, ui.ICON_RECOVERY) text.normal("Do you really want to", "check the recovery", "seed?") await require_confirm(ctx, text, code=ProtectCall) if msg.dry_run: if config.has_pin(): curpin = await request_pin_ack(ctx, "Enter PIN", config.get_pin_rem()) else: curpin = "" if not config.check_pin(pin_to_int(curpin)): raise wire.PinInvalid("PIN invalid") # ask for the number of words wordcount = await request_wordcount(ctx, title) # ask for mnemonic words one by one words = await request_mnemonic(ctx, wordcount) # check mnemonic validity if msg.enforce_wordlist or msg.dry_run: if not bip39.check(words): raise wire.ProcessError("Mnemonic is not valid") # ask for pin repeatedly if msg.pin_protection: newpin = await request_pin_confirm(ctx, allow_cancel=False) else: newpin = "" secret = mnemonic.process([words], mnemonic.TYPE_BIP39) # dry run if msg.dry_run: digest_input = sha256(secret).digest() stored, _ = mnemonic.get() digest_stored = sha256(stored).digest() if consteq(digest_stored, digest_input): return Success( message="The seed is valid and matches the one in the device" ) else: raise wire.ProcessError( "The seed is valid but does not match the one in the device" ) # save into storage if newpin: config.change_pin(pin_to_int(""), pin_to_int(newpin)) storage.set_u2f_counter(msg.u2f_counter) storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.store_mnemonic( secret=secret, mnemonic_type=mnemonic.TYPE_BIP39, needs_backup=False, no_backup=False, ) return Success(message="Device recovered")
async def show_entropy(ctx, entropy: bytes): entropy_str = hexlify(entropy).decode() lines = chunks(entropy_str, 16) text = Text("Internal entropy", ui.ICON_RESET) text.mono(*lines) await require_confirm(ctx, text, ButtonRequestType.ResetDevice)
async def require_confirm_change_autolock_delay(ctx, delay_ms): text = Text("Auto-lock delay", ui.ICON_CONFIG, new_lines=False) text.normal("Do you really want to", "auto-lock your device", "after") text.bold("{} seconds?".format(delay_ms // 1000)) await require_confirm(ctx, text, ButtonRequestType.ProtectCall)
async def require_confirm_change_label(ctx, label): text = Text("Change label", ui.ICON_CONFIG) text.normal("Do you really want to", "change the label to") text.bold("%s?" % label) await require_confirm(ctx, text, ButtonRequestType.ProtectCall)
def _entry_dialog() -> None: text = Text("Passphrase entry", ICON_CONFIG) text.normal("Please type your", "passphrase on the", "connected host.") draw_simple(text)
async def _require_confirm_transfer(ctx, recipient, value): text = Text("Confirm transfer", ui.ICON_SEND, ui.GREEN) text.bold("Send %s XEM" % format_amount(value, NEM_MAX_DIVISIBILITY)) text.normal("to") text.mono(*split_address(recipient)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def require_confirm_delegate_registration(ctx, delegate_name): text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.normal("Do you really want to") text.normal("register a delegate?") text.bold(*chunks(delegate_name, 20)) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def require_confirm_vote_tx(ctx, votes): text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.normal(*get_vote_tx_text(votes)) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def _require_confirm_fee(ctx, fee): content = Text("Confirm fee", ui.ICON_SEND, icon_color=ui.GREEN) content.bold(common.format_amount(fee)) await require_hold_to_confirm(ctx, content, ButtonRequestType.ConfirmOutput)
async def require_confirm_tx(ctx, to, value): text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_amount(value)) text.normal("to") text.mono(*split_address(to)) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def require_confirm_keyimage_sync(ctx): content = Text("Confirm ki sync", ui.ICON_SEND, icon_color=ui.GREEN) content.normal("Do you really want to", "sync key images?") return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def keyimage_sync_step(ctx, current, total_num): if current is None: return text = Text("Syncing", ui.ICON_SEND, icon_color=ui.BLUE) text.normal("%d/%d" % (current + 1, total_num)) text.render()
async def require_confirm_watchkey(ctx): content = Text("Confirm export", ui.ICON_SEND, icon_color=ui.GREEN) content.normal("Do you really want to", "export watch-only", "credentials?") return await require_confirm(ctx, content, ButtonRequestType.SignTx)
async def require_confirm_destination_tag(ctx, tag): text = Text("Confirm tag", ui.ICON_SEND, icon_color=ui.GREEN) text.normal("Destination tag:") text.bold(str(tag)) await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def require_confirm_multisig(ctx, multisignature): text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.normal("Keys group length: %s" % len(multisignature.keys_group)) text.normal("Life time: %s" % multisignature.life_time) text.normal("Min: %s" % multisignature.min) return await require_confirm(ctx, text, ButtonRequestType.SignTx)
async def _warn(ctx: wire.Context): text = Text("Loading seed") text.bold("Loading private seed", "is not recommended.") text.normal("Continue only if you", "know what you are doing!") await require_confirm(ctx, text)
async def require_confirm_fee(ctx, value, fee): text = Text("Confirm transaction", ui.ICON_SEND, icon_color=ui.GREEN) text.bold(format_amount(value)) text.normal("fee:") text.bold(format_amount(fee)) await require_hold_to_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def require_confirm_sign_message(ctx, message): message = split_message(message) text = Text("Sign Lisk message", new_lines=False) text.normal(*message) await require_confirm(ctx, text)
async def _show_tezos_pubkey(ctx, pubkey): lines = chunks(pubkey, 18) text = Text("Confirm public key", ui.ICON_RECEIVE, ui.GREEN) text.mono(*lines) await require_confirm(ctx, text, code=ButtonRequestType.PublicKey)
async def show_pubkey(ctx: wire.Context, pubkey: bytes) -> None: lines = chunks(hexlify(pubkey).decode(), 18) text = Text("Confirm public key", ui.ICON_RECEIVE, ui.GREEN) text.mono(*lines) await require_confirm(ctx, text, ButtonRequestType.PublicKey)
async def confirm_feeoverthreshold(ctx, fee, coin): text = Text("High fee", ui.ICON_SEND, icon_color=ui.GREEN) text.normal("The fee of") text.bold(format_coin_amount(fee, coin)) text.normal("is unexpectedly high.", "Continue?") return await confirm(ctx, text, ButtonRequestType.FeeOverThreshold)
async def require_confirm_change_homescreen(ctx): text = Text("Set homescreen", ui.ICON_CONFIG) text.normal("Do you really want to", "change the homescreen", "image?") await require_confirm(ctx, text, ButtonRequestType.ProtectCall)
async def confirm_foreign_address(ctx, address_n, coin): text = Text("Confirm sending", ui.ICON_SEND, icon_color=ui.RED) text.normal("Trying to spend", "coins from another chain.", "Continue?") return await confirm(ctx, text, ButtonRequestType.SignTx)
async def require_confirm_sign_message(ctx, message): message = split_message(message) content = Text('Sign message', ui.ICON_DEFAULT, max_lines=5, *message) await require_confirm(ctx, content)
async def require_confirm_ecdh_session_key(ctx, identity): lines = chunks(serialize_identity_without_proto(identity), 18) proto = identity.proto.upper() if identity.proto else "identity" text = Text("Decrypt %s" % proto) text.mono(*lines) await require_confirm(ctx, text)
async def pin_mismatch(): text = Text('PIN mismatch', ui.ICON_DEFAULT, 'Entered PINs do not', 'match each other.', '', 'Please, try again...') text.render() await loop.sleep(3 * 1000 * 1000)
async def require_confirm_fee(ctx, fee): text = Text("Confirm fee", ui.ICON_SEND, icon_color=ui.GREEN) text.normal("Transaction fee:") text.bold(format_amount(fee, helpers.DIVISIBILITY) + " XRP") await require_confirm(ctx, text, ButtonRequestType.ConfirmOutput)
async def reset_device(ctx, msg): # validate parameters and device state if msg.strength not in (128, 192, 256): raise wire.ProcessError( "Invalid strength (has to be 128, 192 or 256 bits)") if msg.display_random and (msg.skip_backup or msg.no_backup): raise wire.ProcessError( "Can't show internal entropy when backup is skipped") if storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") text = Text("Create a new wallet", ui.ICON_RESET, new_lines=False) text.normal("Do you really want to") text.br() text.normal("create a new wallet?") text.br() text.br_half() text.normal("By continuing you agree") text.br() text.normal("to") text.bold("https://trezor.io/tos") await require_confirm(ctx, text, code=ButtonRequestType.ResetDevice) # request new PIN if msg.pin_protection: newpin = await request_pin_confirm(ctx) else: newpin = "" # generate and display internal entropy internal_ent = random.bytes(32) if __debug__: debug.reset_internal_entropy = internal_ent if msg.display_random: await show_entropy(ctx, internal_ent) # request external entropy and compute mnemonic ent_ack = await ctx.call(EntropyRequest(), MessageType.EntropyAck) mnemonic = generate_mnemonic(msg.strength, internal_ent, ent_ack.entropy) if not msg.skip_backup and not msg.no_backup: # require confirmation of the mnemonic safety await show_warning(ctx) # show mnemonic and require confirmation of a random word while True: await show_mnemonic(ctx, mnemonic) if await check_mnemonic(ctx, mnemonic): break await show_wrong_entry(ctx) # write PIN into storage if not config.change_pin(pin_to_int(""), pin_to_int(newpin)): raise wire.ProcessError("Could not change PIN") # write settings and mnemonic into storage storage.load_settings(label=msg.label, use_passphrase=msg.passphrase_protection) storage.load_mnemonic(mnemonic=mnemonic, needs_backup=msg.skip_backup, no_backup=msg.no_backup) # show success message. if we skipped backup, it's possible that homescreen # is still running, uninterrupted. restart it to pick up new label. if not msg.skip_backup and not msg.no_backup: await show_success(ctx) else: workflow.restartdefault() return Success(message="Initialized")
async def _show_share_words(ctx, share_words, share_index=None, group_index=None): first, chunks, last = _split_share_into_pages(share_words) if share_index is None: header_title = "Recovery seed" elif group_index is None: header_title = "Recovery share #%s" % (share_index + 1) else: header_title = "Group %s - Share %s" % ((group_index + 1), (share_index + 1)) header_icon = ui.ICON_RESET pages = [] # ui page components shares_words_check = [] # check we display correct data # first page text = Text(header_title, header_icon) text.bold("Write down these") text.bold("%s words:" % len(share_words)) text.br_half() for index, word in first: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) pages.append(text) # middle pages for chunk in chunks: text = Text(header_title, header_icon) for index, word in chunk: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) pages.append(text) # last page text = Text(header_title, header_icon) for index, word in last: text.mono("%s. %s" % (index + 1, word)) shares_words_check.append(word) text.br_half() text.bold("I wrote down all %s" % len(share_words)) text.bold("words in order.") pages.append(text) # pagination paginated = Paginated(pages) if __debug__: word_pages = [first] + chunks + [last] def export_displayed_words(): # export currently displayed mnemonic words into debuglink words = [w for _, w in word_pages[paginated.page]] debug.reset_current_words.publish(words) paginated.on_change = export_displayed_words export_displayed_words() # make sure we display correct data utils.ensure(share_words == shares_words_check) # confirm the share await require_hold_to_confirm(ctx, paginated, ButtonRequestType.ResetDevice, cancel=False)