1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-18 10:32:02 +00:00

fix(core/ui): don't return CONFIRMED/CANCELLED from layouts

This commit is contained in:
Martin Milata 2021-02-10 00:14:11 +01:00
parent f128e4a1c2
commit 035f114125
3 changed files with 141 additions and 102 deletions

View File

@ -4,13 +4,17 @@ if __debug__:
from apps.debug import confirm_signal from apps.debug import confirm_signal
if False: if False:
from typing import List, Tuple, Optional from typing import List, Tuple, Optional, Any
CONFIRMED = object() CONFIRMED = object()
CANCELLED = object() CANCELLED = object()
INFO = object() INFO = object()
def is_confirmed(x: Any) -> bool:
return x is CONFIRMED
class ConfirmBase(ui.Layout): class ConfirmBase(ui.Layout):
def __init__( def __init__(
self, self,

View File

@ -3,8 +3,6 @@ from trezor.messages import ButtonRequestType
from trezor.messages.ButtonAck import ButtonAck from trezor.messages.ButtonAck import ButtonAck
from trezor.messages.ButtonRequest import ButtonRequest from trezor.messages.ButtonRequest import ButtonRequest
from ..components.common.confirm import CONFIRMED
if False: if False:
from typing import Any, Awaitable from typing import Any, Awaitable
@ -13,9 +11,9 @@ if False:
LayoutType = Awaitable[Any] LayoutType = Awaitable[Any]
async def require(a: LayoutType) -> None: async def require(a: Awaitable[bool]) -> None:
result = await a result = await a
if result is not CONFIRMED: if not result:
raise wire.ActionCancelled raise wire.ActionCancelled

View File

@ -8,7 +8,7 @@ from trezor.ui.qr import Qr
from trezor.utils import chunks from trezor.utils import chunks
from ..components.common import break_path_to_lines from ..components.common import break_path_to_lines
from ..components.common.confirm import CONFIRMED from ..components.common.confirm import is_confirmed
from ..components.tt.button import ButtonCancel, ButtonDefault from ..components.tt.button import ButtonCancel, ButtonDefault
from ..components.tt.confirm import Confirm, HoldToConfirm from ..components.tt.confirm import Confirm, HoldToConfirm
from ..components.tt.scroll import Paginated from ..components.tt.scroll import Paginated
@ -29,8 +29,6 @@ if False:
from trezor import wire from trezor import wire
from trezor.messages.ButtonRequest import EnumTypeButtonRequestType from trezor.messages.ButtonRequest import EnumTypeButtonRequestType
from . import LayoutType
__all__ = ( __all__ = (
"confirm_action", "confirm_action",
@ -55,39 +53,49 @@ __all__ = (
) )
def confirm_action( async def confirm_action(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
title: str, title: str,
action: str, action: str,
description: str = None, description: str = None,
verb: Union[str, bytes] = Confirm.DEFAULT_CONFIRM, verb: Union[str, bytes] = Confirm.DEFAULT_CONFIRM,
verb_cancel: Union[str, bytes] = Confirm.DEFAULT_CANCEL,
icon: str = None, icon: str = None,
br_code: EnumTypeButtonRequestType = ButtonRequestType.Other, br_code: EnumTypeButtonRequestType = ButtonRequestType.Other,
**kwargs: Any, **kwargs: Any,
) -> LayoutType: ) -> bool:
text = Text(title, icon if icon is not None else ui.ICON_DEFAULT, new_lines=False) text = Text(title, icon if icon is not None else ui.ICON_DEFAULT, new_lines=False)
text.bold(action) text.bold(action)
text.br() text.br()
if description: if description:
text.normal(description) text.normal(description)
return interact(ctx, Confirm(text, confirm=verb), br_type, br_code) return is_confirmed(
await interact(
ctx,
def confirm_wipe(ctx: wire.GenericContext) -> LayoutType: Confirm(text, confirm=verb, cancel=verb_cancel),
text = Text("Wipe device", ui.ICON_WIPE, ui.RED) br_type,
text.normal("Do you really want to", "wipe the device?", "") br_code,
text.bold("All data will be lost.") )
return interact(
ctx,
HoldToConfirm(text, confirm_style=ButtonCancel, loader_style=LoaderDanger),
"wipe_device",
ButtonRequestType.WipeDevice,
) )
def confirm_reset_device(ctx: wire.GenericContext, prompt: str) -> LayoutType: async def confirm_wipe(ctx: wire.GenericContext) -> bool:
text = Text("Wipe device", ui.ICON_WIPE, ui.RED)
text.normal("Do you really want to", "wipe the device?", "")
text.bold("All data will be lost.")
return is_confirmed(
await interact(
ctx,
HoldToConfirm(text, confirm_style=ButtonCancel, loader_style=LoaderDanger),
"wipe_device",
ButtonRequestType.WipeDevice,
)
)
async def confirm_reset_device(ctx: wire.GenericContext, prompt: str) -> bool:
text = Text("Create new wallet", ui.ICON_RESET, new_lines=False) text = Text("Create new wallet", ui.ICON_RESET, new_lines=False)
text.bold(prompt) text.bold(prompt)
text.br() text.br()
@ -96,11 +104,13 @@ def confirm_reset_device(ctx: wire.GenericContext, prompt: str) -> LayoutType:
text.br() text.br()
text.normal("to") text.normal("to")
text.bold("https://trezor.io/tos") text.bold("https://trezor.io/tos")
return interact( return is_confirmed(
ctx, await interact(
Confirm(text, major_confirm=True), ctx,
"setup_device", Confirm(text, major_confirm=True),
ButtonRequestType.ResetDevice, "setup_device",
ButtonRequestType.ResetDevice,
)
) )
@ -115,38 +125,39 @@ async def confirm_backup(ctx: wire.GenericContext) -> bool:
text2.br_half() text2.br_half()
text2.normal("You can back up your", "Trezor once, at any time.") text2.normal("You can back up your", "Trezor once, at any time.")
if ( if is_confirmed(
await interact( await interact(
ctx, ctx,
Confirm(text1, cancel="Skip", confirm="Back up", major_confirm=True), Confirm(text1, cancel="Skip", confirm="Back up", major_confirm=True),
"backup_device", "backup_device",
ButtonRequestType.ResetDevice, ButtonRequestType.ResetDevice,
) )
is CONFIRMED
): ):
return True return True
confirmed = ( confirmed = is_confirmed(
await interact( await interact(
ctx, ctx,
Confirm(text2, cancel="Skip", confirm="Back up", major_confirm=True), Confirm(text2, cancel="Skip", confirm="Back up", major_confirm=True),
"backup_device", "backup_device",
ButtonRequestType.ResetDevice, ButtonRequestType.ResetDevice,
) )
) is CONFIRMED )
return confirmed return confirmed
def confirm_path_warning(ctx: wire.GenericContext, path: str) -> LayoutType: async def confirm_path_warning(ctx: wire.GenericContext, path: str) -> bool:
text = Text("Confirm path", ui.ICON_WRONG, ui.RED) text = Text("Confirm path", ui.ICON_WRONG, ui.RED)
text.normal("Path") text.normal("Path")
text.mono(*break_path_to_lines(path, MONO_CHARS_PER_LINE)) text.mono(*break_path_to_lines(path, MONO_CHARS_PER_LINE))
text.normal("is unknown.", "Are you sure?") text.normal("is unknown.", "Are you sure?")
return interact( return is_confirmed(
ctx, await interact(
Confirm(text), ctx,
"path_warning", Confirm(text),
ButtonRequestType.UnknownDerivationPath, "path_warning",
ButtonRequestType.UnknownDerivationPath,
)
) )
@ -203,11 +214,16 @@ def _show_xpub(xpub: str, desc: str, cancel: str) -> Paginated:
return content return content
def show_xpub( async def show_xpub(
ctx: wire.GenericContext, xpub: str, desc: str, cancel: str ctx: wire.GenericContext, xpub: str, desc: str, cancel: str
) -> LayoutType: ) -> bool:
return interact( return is_confirmed(
ctx, _show_xpub(xpub, desc, cancel), "show_xpub", ButtonRequestType.PublicKey await interact(
ctx,
_show_xpub(xpub, desc, cancel),
"show_xpub",
ButtonRequestType.PublicKey,
)
) )
@ -222,17 +238,16 @@ async def show_address(
) -> None: ) -> None:
is_multisig = len(xpubs) > 0 is_multisig = len(xpubs) > 0
while True: while True:
if ( if is_confirmed(
await interact( await interact(
ctx, ctx,
_show_address(address, desc, network), _show_address(address, desc, network),
"show_address", "show_address",
ButtonRequestType.Address, ButtonRequestType.Address,
) )
is CONFIRMED
): ):
break break
if ( if is_confirmed(
await interact( await interact(
ctx, ctx,
_show_qr( _show_qr(
@ -243,7 +258,6 @@ async def show_address(
"show_qr", "show_qr",
ButtonRequestType.Address, ButtonRequestType.Address,
) )
is CONFIRMED
): ):
break break
@ -252,169 +266,188 @@ async def show_address(
cancel = "Next" if i < len(xpubs) - 1 else "Address" cancel = "Next" if i < len(xpubs) - 1 else "Address"
desc_xpub = "XPUB #%d" % (i + 1) desc_xpub = "XPUB #%d" % (i + 1)
desc_xpub += " (yours)" if i == multisig_index else " (cosigner)" desc_xpub += " (yours)" if i == multisig_index else " (cosigner)"
if ( if is_confirmed(
await interact( await interact(
ctx, ctx,
_show_xpub(xpub, desc=desc_xpub, cancel=cancel), _show_xpub(xpub, desc=desc_xpub, cancel=cancel),
"show_xpub", "show_xpub",
ButtonRequestType.PublicKey, ButtonRequestType.PublicKey,
) )
is CONFIRMED
): ):
return return
# FIXME: this is basically same as confirm_hex # FIXME: this is basically same as confirm_hex
# TODO: pagination for long keys # TODO: pagination for long keys
def show_pubkey( async def show_pubkey(
ctx: wire.Context, pubkey: str, title: str = "Confirm public key" ctx: wire.Context, pubkey: str, title: str = "Confirm public key"
) -> LayoutType: ) -> bool:
text = Text(title, ui.ICON_RECEIVE, ui.GREEN) text = Text(title, ui.ICON_RECEIVE, ui.GREEN)
text.mono(*_hex_lines(pubkey)) text.mono(*_hex_lines(pubkey))
return interact(ctx, Confirm(text), "show_pubkey", ButtonRequestType.PublicKey) return is_confirmed(
await interact(ctx, Confirm(text), "show_pubkey", ButtonRequestType.PublicKey)
)
def show_warning( async def show_warning(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
content: str, content: str,
subheader: Optional[str] = None, subheader: Optional[str] = None,
button: str = "Try again", button: str = "Try again",
) -> LayoutType: ) -> bool:
text = Text("Warning", ui.ICON_WRONG, ui.RED, new_lines=False) text = Text("Warning", ui.ICON_WRONG, ui.RED, new_lines=False)
if subheader: if subheader:
text.bold(subheader) text.bold(subheader)
text.br() text.br()
text.br_half() text.br_half()
text.normal(content) text.normal(content)
return interact( return is_confirmed(
ctx, await interact(
Confirm(text, confirm=button, cancel=None), ctx,
br_type, Confirm(text, confirm=button, cancel=None),
ButtonRequestType.Warning, br_type,
ButtonRequestType.Warning,
)
) )
def show_success( async def show_success(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
content: str, content: str,
subheader: Optional[str] = None, subheader: Optional[str] = None,
button: str = "Continue", button: str = "Continue",
) -> LayoutType: ) -> bool:
text = Text("Success", ui.ICON_CONFIRM, ui.GREEN, new_lines=False) text = Text("Success", ui.ICON_CONFIRM, ui.GREEN, new_lines=False)
if subheader: if subheader:
text.bold(subheader) text.bold(subheader)
text.br() text.br()
text.br_half() text.br_half()
text.normal(content) text.normal(content)
return interact( return is_confirmed(
ctx, await interact(
Confirm(text, confirm=button, cancel=None), ctx,
br_type, Confirm(text, confirm=button, cancel=None),
ButtonRequestType.Success, br_type,
ButtonRequestType.Success,
)
) )
def confirm_output( async def confirm_output(
ctx: wire.GenericContext, ctx: wire.GenericContext,
address: str, address: str,
amount: str, amount: str,
) -> LayoutType: ) -> bool:
text = Text("Confirm sending", ui.ICON_SEND, ui.GREEN) text = Text("Confirm sending", ui.ICON_SEND, ui.GREEN)
text.normal(amount + " to") text.normal(amount + " to")
text.mono(*_split_address(address)) text.mono(*_split_address(address))
return interact( return is_confirmed(
ctx, Confirm(text), "confirm_output", ButtonRequestType.ConfirmOutput await interact(
ctx, Confirm(text), "confirm_output", ButtonRequestType.ConfirmOutput
)
) )
def confirm_decred_sstx_submission( async def confirm_decred_sstx_submission(
ctx: wire.GenericContext, ctx: wire.GenericContext,
address: str, address: str,
amount: str, amount: str,
) -> LayoutType: ) -> bool:
text = Text("Purchase ticket", ui.ICON_SEND, ui.GREEN) text = Text("Purchase ticket", ui.ICON_SEND, ui.GREEN)
text.normal(amount) text.normal(amount)
text.normal("with voting rights to") text.normal("with voting rights to")
text.mono(*_split_address(address)) text.mono(*_split_address(address))
return interact( return is_confirmed(
ctx, await interact(
Confirm(text), ctx,
"confirm_decred_sstx_submission", Confirm(text),
ButtonRequestType.ConfirmOutput, "confirm_decred_sstx_submission",
ButtonRequestType.ConfirmOutput,
)
) )
def confirm_hex( async def confirm_hex(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
title: str, title: str,
data: str, data: str,
br_code: EnumTypeButtonRequestType = ButtonRequestType.Other, br_code: EnumTypeButtonRequestType = ButtonRequestType.Other,
) -> LayoutType: ) -> bool:
text = Text(title, ui.ICON_SEND, ui.GREEN) text = Text(title, ui.ICON_SEND, ui.GREEN)
text.mono(*_hex_lines(data)) text.mono(*_hex_lines(data))
return interact(ctx, Confirm(text), br_type, br_code) return is_confirmed(await interact(ctx, Confirm(text), br_type, br_code))
def confirm_total( async def confirm_total(
ctx: wire.GenericContext, total_amount: str, fee_amount: str ctx: wire.GenericContext, total_amount: str, fee_amount: str
) -> LayoutType: ) -> bool:
text = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN) text = Text("Confirm transaction", ui.ICON_SEND, ui.GREEN)
text.normal("Total amount:") text.normal("Total amount:")
text.bold(total_amount) text.bold(total_amount)
text.normal("including fee:") text.normal("including fee:")
text.bold(fee_amount) text.bold(fee_amount)
return interact(ctx, HoldToConfirm(text), "confirm_total", ButtonRequestType.SignTx) return is_confirmed(
await interact(
ctx, HoldToConfirm(text), "confirm_total", ButtonRequestType.SignTx
)
)
def confirm_joint_total( async def confirm_joint_total(
ctx: wire.GenericContext, spending_amount: str, total_amount: str ctx: wire.GenericContext, spending_amount: str, total_amount: str
) -> LayoutType: ) -> bool:
text = Text("Joint transaction", ui.ICON_SEND, ui.GREEN) text = Text("Joint transaction", ui.ICON_SEND, ui.GREEN)
text.normal("You are contributing:") text.normal("You are contributing:")
text.bold(spending_amount) text.bold(spending_amount)
text.normal("to the total amount:") text.normal("to the total amount:")
text.bold(total_amount) text.bold(total_amount)
return interact( return is_confirmed(
ctx, HoldToConfirm(text), "confirm_joint_total", ButtonRequestType.SignTx await interact(
ctx, HoldToConfirm(text), "confirm_joint_total", ButtonRequestType.SignTx
)
) )
def confirm_metadata( async def confirm_metadata(
ctx: wire.GenericContext, ctx: wire.GenericContext,
br_type: str, br_type: str,
title: str, title: str,
content: str, content: str,
param: Optional[str] = None, param: Optional[str] = None,
br_code: EnumTypeButtonRequestType = ButtonRequestType.SignTx, br_code: EnumTypeButtonRequestType = ButtonRequestType.SignTx,
) -> LayoutType: ) -> bool:
text = Text(title, ui.ICON_SEND, ui.GREEN, new_lines=False) text = Text(title, ui.ICON_SEND, ui.GREEN, new_lines=False)
text.format_parametrized(content, param if param is not None else "") text.format_parametrized(content, param if param is not None else "")
text.br() text.br()
text.normal("Continue?") text.normal("Continue?")
return interact(ctx, Confirm(text), br_type, br_code) return is_confirmed(await interact(ctx, Confirm(text), br_type, br_code))
def confirm_replacement( async def confirm_replacement(
ctx: wire.GenericContext, description: str, txid: str ctx: wire.GenericContext, description: str, txid: str
) -> LayoutType: ) -> bool:
text = Text(description, ui.ICON_SEND, ui.GREEN) text = Text(description, ui.ICON_SEND, ui.GREEN)
text.normal("Confirm transaction ID:") text.normal("Confirm transaction ID:")
text.mono(*_hex_lines(txid, TEXT_MAX_LINES - 1)) text.mono(*_hex_lines(txid, TEXT_MAX_LINES - 1))
return interact(ctx, Confirm(text), "confirm_replacement", ButtonRequestType.SignTx) return is_confirmed(
await interact(
ctx, Confirm(text), "confirm_replacement", ButtonRequestType.SignTx
)
)
def confirm_modify_output( async def confirm_modify_output(
ctx: wire.GenericContext, ctx: wire.GenericContext,
address: str, address: str,
sign: int, sign: int,
amount_change: str, amount_change: str,
amount_new: str, amount_new: str,
) -> LayoutType: ) -> bool:
page1 = Text("Modify amount", ui.ICON_SEND, ui.GREEN) page1 = Text("Modify amount", ui.ICON_SEND, ui.GREEN)
page1.normal("Address:") page1.normal("Address:")
page1.br_half() page1.br_half()
@ -430,20 +463,22 @@ def confirm_modify_output(
page2.normal("New amount:") page2.normal("New amount:")
page2.bold(amount_new) page2.bold(amount_new)
return interact( return is_confirmed(
ctx, interact(
Paginated([page1, Confirm(page2)]), ctx,
"modify_output", Paginated([page1, Confirm(page2)]),
ButtonRequestType.ConfirmOutput, "modify_output",
ButtonRequestType.ConfirmOutput,
)
) )
def confirm_modify_fee( async def confirm_modify_fee(
ctx: wire.GenericContext, ctx: wire.GenericContext,
sign: int, sign: int,
user_fee_change: str, user_fee_change: str,
total_fee_new: str, total_fee_new: str,
) -> LayoutType: ) -> bool:
text = Text("Modify fee", ui.ICON_SEND, ui.GREEN) text = Text("Modify fee", ui.ICON_SEND, ui.GREEN)
if sign == 0: if sign == 0:
text.normal("Your fee did not change.") text.normal("Your fee did not change.")
@ -456,4 +491,6 @@ def confirm_modify_fee(
text.br_half() text.br_half()
text.normal("Transaction fee:") text.normal("Transaction fee:")
text.bold(total_fee_new) text.bold(total_fee_new)
return interact(ctx, HoldToConfirm(text), "modify_fee", ButtonRequestType.SignTx) return is_confirmed(
await interact(ctx, HoldToConfirm(text), "modify_fee", ButtonRequestType.SignTx)
)