async def request_passphrase_ack(ctx, on_device): if not on_device: text = Text("Passphrase entry", ui.ICON_CONFIG) text.normal("Please, type passphrase", "on connected host.") text.render() req = PassphraseRequest(on_device=on_device) ack = await ctx.call(req, MessageType.PassphraseAck, MessageType.Cancel) if ack.MESSAGE_WIRE_TYPE == MessageType.Cancel: raise wire.ActionCancelled("Passphrase cancelled") if on_device: if ack.passphrase is not None: raise wire.ProcessError( "Passphrase provided when it should not be") keyboard = PassphraseKeyboard("Enter passphrase") passphrase = await ctx.wait(keyboard) if passphrase == CANCELLED: raise wire.ActionCancelled("Passphrase cancelled") else: if ack.passphrase is None: raise wire.ProcessError("Passphrase not provided") passphrase = ack.passphrase req = PassphraseStateRequest( state=get_state(prev_state=ack.state, passphrase=passphrase)) ack = await ctx.call(req, MessageType.PassphraseStateAck, MessageType.Cancel) return passphrase
async def cardano_sign_message(ctx, msg): mnemonic = storage.get_mnemonic() root_node = bip32.from_mnemonic_cardano(mnemonic) try: signature = _sign_message(root_node, msg.message, msg.address_n) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed") mnemonic = None root_node = None if not await show_swipable_with_confirmation( ctx, msg.message, "Signing message", ui.ICON_RECEIVE, ui.GREEN ): raise wire.ActionCancelled("Signing cancelled") if not await show_swipable_with_confirmation( ctx, _break_address_n_to_lines(msg.address_n), "With address", ui.ICON_RECEIVE, ui.GREEN, ): raise wire.ActionCancelled("Signing cancelled") return signature
async def request_passphrase_ack(ctx, on_device): if not on_device: text = Text('Passphrase entry', ui.ICON_CONFIG, 'Please, type passphrase', 'on connected host.') text.render() req = PassphraseRequest(on_device=on_device) ack = await ctx.call(req, wire_types.PassphraseAck, wire_types.Cancel) if ack.MESSAGE_WIRE_TYPE == wire_types.Cancel: raise wire.ActionCancelled('Passphrase cancelled') if on_device: if ack.passphrase is not None: raise wire.ProcessError( 'Passphrase provided when it should not be') keyboard = PassphraseKeyboard('Enter passphrase') passphrase = await ctx.wait(keyboard) if passphrase == CANCELLED: raise wire.ActionCancelled('Passphrase cancelled') else: if ack.passphrase is None: raise wire.ProcessError('Passphrase not provided') passphrase = ack.passphrase req = PassphraseStateRequest( state=get_state(prev_state=ack.state, passphrase=passphrase)) ack = await ctx.call(req, wire_types.PassphraseStateAck, wire_types.Cancel) return passphrase
async def cardano_get_address(ctx, msg): mnemonic = storage.get_mnemonic() root_node = bip32.from_mnemonic_cardano(mnemonic) try: address, _ = derive_address_and_node(root_node, msg.address_n) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Deriving address failed") mnemonic = None root_node = None if msg.show_display: if not await show_swipable_with_confirmation(ctx, address, "Export address", icon=ui.ICON_SEND, icon_color=ui.GREEN): raise wire.ActionCancelled("Exporting cancelled") else: lines = _break_address_n_to_lines(msg.address_n) if not await show_swipable_with_confirmation(ctx, lines, "For BIP32 path", icon=ui.ICON_SEND, icon_color=ui.GREEN): raise wire.ActionCancelled("Exporting cancelled") return CardanoAddress(address=address)
async def sign_tx(ctx, msg): keychain = await seed.get_keychain(ctx) progress.init(msg.transactions_count, "Loading data") try: attested = len(msg.inputs) * [False] input_coins_sum = 0 # request transactions tx_req = CardanoTxRequest() for index in range(msg.transactions_count): progress.advance() tx_ack = await request_transaction(ctx, tx_req, index) tx_hash = hashlib.blake2b(data=bytes(tx_ack.transaction), outlen=32).digest() tx_decoded = cbor.decode(tx_ack.transaction) for i, input in enumerate(msg.inputs): if not attested[i] and input.prev_hash == tx_hash: attested[i] = True outputs = tx_decoded[1] amount = outputs[input.prev_index][1] input_coins_sum += amount if not all(attested): raise wire.ProcessError("No tx data sent for input " + str(attested.index(False))) transaction = Transaction(msg.inputs, msg.outputs, keychain, msg.protocol_magic, input_coins_sum) # clear progress bar display_homescreen() for i in msg.inputs: await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE) # sign the transaction bundle and prepare the result tx_body, tx_hash = transaction.serialise_tx() tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed") # display the transaction in UI if not await show_tx( ctx, transaction.output_addresses, transaction.outgoing_coins, transaction.fee, transaction.network_name, transaction.inputs, transaction.outputs, ): raise wire.ActionCancelled("Signing cancelled") return tx
async def get_address(ctx, msg): await paths.validate_path(ctx, validate_full_path, path=msg.address_n) mnemonic = storage.get_mnemonic() passphrase = await seed._get_cached_passphrase(ctx) root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase) try: address, _ = derive_address_and_node(root_node, msg.address_n) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Deriving address failed") mnemonic = None root_node = None if msg.show_display: if not await confirm_with_pagination(ctx, address, "Export address", icon=ui.ICON_SEND, icon_color=ui.GREEN): raise wire.ActionCancelled("Exporting cancelled") return CardanoAddress(address=address)
async def request_passphrase_ack(ctx: wire.Context, on_device: bool) -> str: if not on_device: text = Text("Passphrase entry", ui.ICON_CONFIG) text.normal("Please, type passphrase", "on connected host.") await Popup(text) req = PassphraseRequest(on_device=on_device) ack = await ctx.call(req, PassphraseAck) if on_device: if ack.passphrase is not None: raise wire.ProcessError( "Passphrase provided when it should not be") keyboard = PassphraseKeyboard("Enter passphrase", _MAX_PASSPHRASE_LEN) if __debug__: passphrase = await ctx.wait(keyboard, input_signal()) else: passphrase = await ctx.wait(keyboard) if passphrase is CANCELLED: raise wire.ActionCancelled("Passphrase cancelled") else: if ack.passphrase is None: raise wire.ProcessError("Passphrase not provided") passphrase = ack.passphrase state = cache.get_state(prev_state=ack.state, passphrase=passphrase) req = PassphraseStateRequest(state=state) ack = await ctx.call(req, PassphraseStateAck) return passphrase
async def add_resident_credential( ctx: wire.Context, msg: WebAuthnAddResidentCredential ) -> Success: if not msg.credential_id: raise wire.ProcessError("Missing credential ID parameter.") try: cred = Fido2Credential.from_cred_id(bytes(msg.credential_id), None) except Exception: text = Text("Import credential", ui.ICON_WRONG, ui.RED) text.normal( "The credential you are", "trying to import does", "not belong to this", "authenticator.", ) await require_confirm(ctx, text, confirm=None, cancel="Close") raise wire.ActionCancelled("Cancelled") from None content = ConfirmContent(ConfirmAddCredential(cred)) await require_confirm(ctx, content) if store_resident_credential(cred): return Success(message="Credential added") else: raise wire.ProcessError("Internal credential storage is full.")
async def request_pin_ack(ctx, *args, **kwargs): try: await ctx.call(ButtonRequest(code=ButtonRequestType.Other), MessageType.ButtonAck) return await ctx.wait(request_pin(*args, **kwargs)) except PinCancelled: raise wire.ActionCancelled("Cancelled")
async def _require_confirm_output( ctx, dst: MoneroTransactionDestinationEntry, network_type: int, payment_id: bytes ): """ Single transaction destination confirmation """ from apps.monero.xmr.addresses import encode_addr from apps.monero.xmr.networks import net_version version = net_version(network_type, dst.is_subaddress, payment_id is not None) addr = encode_addr( version, dst.addr.spend_public_key, dst.addr.view_public_key, payment_id ) text_addr = common.split_address(addr.decode()) text_amount = common.format_amount(dst.amount) if not await common.naive_pagination( ctx, [ui.BOLD, text_amount, ui.MONO] + list(text_addr), "Confirm send", ui.ICON_SEND, ui.GREEN, 4, ): raise wire.ActionCancelled("Cancelled")
async def _show_page(page: int, page_count: int, content): content = Scrollpage(content[page], page, page_count) if page + 1 == page_count: if await ConfirmDialog(content) != CONFIRMED: raise wire.ActionCancelled("Action cancelled") else: content.render() await animate_swipe()
async def request_pin_ack(ctx: wire.Context, *args: Any, **kwargs: Any) -> str: try: await ctx.call(ButtonRequest(code=ButtonRequestType.Other), ButtonAck) pin = await ctx.wait(request_pin(*args, **kwargs)) assert isinstance(pin, str) return pin except PinCancelled: raise wire.ActionCancelled("Cancelled")
async def _require_confirm_payment_id(ctx, payment_id): if not await common.naive_pagination( ctx, [ui.MONO] + list(chunks(hexlify((payment_id)), 16)), "Payment ID", ui.ICON_SEND, ui.GREEN, ): raise wire.ActionCancelled("Cancelled")
async def recovery_process(ctx: wire.GenericContext) -> Success: try: return await _continue_recovery_process(ctx) except recover.RecoveryAborted: dry_run = storage_recovery.is_dry_run() if dry_run: storage_recovery.end_progress() else: storage.wipe() raise wire.ActionCancelled("Cancelled")
async def cardano_verify_message(ctx, msg): try: res = _verify_message(msg.public_key, msg.signature, msg.message) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Verifying failed") if not res: return Failure(message="Invalid signature") if not await show_swipable_with_confirmation( ctx, msg.message, "Verifying message", ui.ICON_RECEIVE, ui.GREEN): raise wire.ActionCancelled("Verifying cancelled") if not await show_swipable_with_confirmation(ctx, hexlify( msg.public_key), "With public key", ui.ICON_RECEIVE, ui.GREEN): raise wire.ActionCancelled("Verifying cancelled") return Success(message="Message verified")
async def _request_on_device(ctx: wire.Context) -> str: await button_request(ctx, code=ButtonRequestType.PassphraseEntry) keyboard = PassphraseKeyboard("Enter passphrase", _MAX_PASSPHRASE_LEN) passphrase = await ctx.wait(keyboard) if passphrase is CANCELLED: raise wire.ActionCancelled("Passphrase entry cancelled") assert isinstance(passphrase, str) return passphrase
async def _require_confirm_properties(ctx, definition: NEMMosaicDefinition): # TODO: we should send a button request here pages = _get_mosaic_properties(definition) pages[-1] = Confirm(pages[-1]) paginated = Paginated(pages) if __debug__: result = await ctx.wait(paginated, confirm_signal) else: result = await ctx.wait(paginated) if result is not CONFIRMED: raise wire.ActionCancelled("Action cancelled")
async def request_passphrase_entry(ctx): text = Text('Enter passphrase', ui.ICON_CONFIG, 'Where to enter your', 'passphrase?') text.render() ack = await ctx.call(ButtonRequest(code=ButtonRequestType.PassphraseType), wire_types.ButtonAck, wire_types.Cancel) if ack.MESSAGE_WIRE_TYPE == wire_types.Cancel: raise wire.ActionCancelled('Passphrase cancelled') selector = EntrySelector(text) return await ctx.wait(selector)
async def request_passphrase_on_device(ctx: wire.GenericContext, max_len: int) -> str: await button_request( ctx, "passphrase_device", code=ButtonRequestType.PassphraseEntry ) keyboard = passphrase.PassphraseKeyboard("Enter passphrase", max_len) result = await ctx.wait(keyboard) if result is passphrase.CANCELLED: raise wire.ActionCancelled("Passphrase entry cancelled") assert isinstance(result, str) return result
async def require_confirm_output(ctx, address:str, amount:int): text_addr = common.split_address(address) text_amount = common.format_amount(amount) if not await common.naive_pagination( ctx, [ui.BOLD, text_amount, ui.MONO] + list(text_addr), "Confirm send", ui.ICON_SEND, ui.GREEN, 4, ): raise wire.ActionCancelled("Cancelled")
async def verify_message(ctx, msg): await paths.validate_path(ctx, validate_full_path, path=msg.address_n) try: res = _verify_message(msg.public_key, msg.signature, msg.message) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Verifying failed") if not res: return Failure(message="Invalid signature") if not await confirm_with_pagination(ctx, msg.message, "Verifying message", ui.ICON_RECEIVE, ui.GREEN): raise wire.ActionCancelled("Verifying cancelled") if not await confirm_with_pagination(ctx, hexlify( msg.public_key), "With public key", ui.ICON_RECEIVE, ui.GREEN): raise wire.ActionCancelled("Verifying cancelled") return Success(message="Message verified")
async def show_proposal_page(page: int, page_count: int, pages: list, title: str): text = Text(title, ui.ICON_SEND, icon_color=ui.PURPLE) text.bold("Proposal {}: ".format(page + 1)) text.mono(*split_proposal(pages[page])) content = Scrollpage(text, page, page_count) if page + 1 >= page_count: confirm = await ConfirmDialog(content) if confirm == CANCELLED: raise wire.ActionCancelled("Cancelled") else: content.render() await animate_swipe()
async def _request_on_device(ctx: wire.Context) -> str: await ctx.call(ButtonRequest(code=ButtonRequestType.PassphraseEntry), ButtonAck) keyboard = PassphraseKeyboard("Enter passphrase", _MAX_PASSPHRASE_LEN) if __debug__: passphrase = await ctx.wait(keyboard, input_signal()) else: passphrase = await ctx.wait(keyboard) if passphrase is CANCELLED: raise wire.ActionCancelled("Passphrase entry cancelled") assert isinstance(passphrase, str) return passphrase
async def show_lines_page(page: int, page_count: int, pages: list, header: str): if header == "Arbitrary data": text = Text(header, ui.ICON_WIPE, icon_color=ui.RED) else: text = Text(header, ui.ICON_CONFIRM, icon_color=ui.GREEN) text.mono(*pages[page]) content = Scrollpage(text, page, page_count) if page + 1 == page_count: if await ConfirmDialog(content) != CONFIRMED: raise wire.ActionCancelled("Action cancelled") else: content.render() await animate_swipe()
async def show_voter_page(page: int, page_count: int, pages: list): lines = [ "{:2d}. {}".format(wi + 1, helpers.eos_name_to_string(producer)) for wi, producer in pages[page] ] text = Text("Vote for producers", ui.ICON_CONFIRM, icon_color=ui.GREEN) text.mono(*lines) content = Scrollpage(text, page, page_count) if page + 1 == page_count: if await ConfirmDialog(content) != CONFIRMED: raise wire.ActionCancelled("Action cancelled") else: content.render() await animate_swipe()
async def request_passphrase_entry(ctx): text = Text("Enter passphrase", ui.ICON_CONFIG) text.normal("Where to enter your", "passphrase?") text.render() ack = await ctx.call( ButtonRequest(code=ButtonRequestType.PassphraseType), MessageType.ButtonAck, MessageType.Cancel, ) if ack.MESSAGE_WIRE_TYPE == MessageType.Cancel: raise wire.ActionCancelled("Passphrase cancelled") selector = EntrySelector(text) return await ctx.wait(selector)
async def sign_tx(ctx, msg): mnemonic = storage.get_mnemonic() passphrase = await seed._get_cached_passphrase(ctx) root_node = bip32.from_mnemonic_cardano(mnemonic, passphrase) progress.init(msg.transactions_count, "Loading data") try: # request transactions transactions = [] tx_req = CardanoTxRequest() for index in range(msg.transactions_count): progress.advance() tx_ack = await request_transaction(ctx, tx_req, index) transactions.append(tx_ack.transaction) # clear progress bar display_homescreen() for i in msg.inputs: await validate_path(ctx, validate_full_path, path=i.address_n) # sign the transaction bundle and prepare the result transaction = Transaction(msg.inputs, msg.outputs, transactions, root_node, msg.network) tx_body, tx_hash = transaction.serialise_tx() tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed") # display the transaction in UI if not await show_tx( ctx, transaction.output_addresses, transaction.outgoing_coins, transaction.change_derivation_paths, transaction.change_coins, transaction.fee, len(tx_body), transaction.network_name, ): raise wire.ActionCancelled("Signing cancelled") return tx
async def sign_tx(ctx, msg): keychain = await seed.get_keychain(ctx) progress.init(msg.transactions_count, "Loading data") try: # request transactions transactions = [] tx_req = CardanoTxRequest() for index in range(msg.transactions_count): progress.advance() tx_ack = await request_transaction(ctx, tx_req, index) transactions.append(tx_ack.transaction) # clear progress bar display_homescreen() for i in msg.inputs: await validate_path(ctx, validate_full_path, keychain, i.address_n, CURVE) # sign the transaction bundle and prepare the result transaction = Transaction(msg.inputs, msg.outputs, transactions, keychain, msg.protocol_magic) tx_body, tx_hash = transaction.serialise_tx() tx = CardanoSignedTx(tx_body=tx_body, tx_hash=tx_hash) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Signing failed") # display the transaction in UI if not await show_tx( ctx, transaction.output_addresses, transaction.outgoing_coins, transaction.fee, transaction.network_name, transaction.inputs, transaction.outputs, ): raise wire.ActionCancelled("Signing cancelled") return tx
async def cardano_get_public_key(ctx, msg): mnemonic = storage.get_mnemonic() root_node = bip32.from_mnemonic_cardano(mnemonic) try: key = _get_public_key(root_node, msg.address_n) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Deriving public key failed") mnemonic = None root_node = None lines = ["For BIP32 path: ", ""] lines.extend(_break_address_n_to_lines(msg.address_n)) if not await show_swipable_with_confirmation(ctx, lines, "Export xpub key"): raise wire.ActionCancelled("Exporting cancelled") return key
async def get_address(ctx, msg): keychain = await seed.get_keychain(ctx) await paths.validate_path(ctx, validate_full_path, path=msg.address_n) try: address, _ = derive_address_and_node(keychain, msg.address_n) except ValueError as e: if __debug__: log.exception(__name__, e) raise wire.ProcessError("Deriving address failed") if msg.show_display: if not await confirm_with_pagination(ctx, address, "Export address", icon=ui.ICON_SEND, icon_color=ui.GREEN): raise wire.ActionCancelled("Exporting cancelled") return CardanoAddress(address=address)