diff --git a/python/.changelog.d/2289.added b/python/.changelog.d/2289.added new file mode 100644 index 000000000..a72e473f9 --- /dev/null +++ b/python/.changelog.d/2289.added @@ -0,0 +1 @@ +Add UnlockPath message. diff --git a/python/src/trezorlib/btc.py b/python/src/trezorlib/btc.py index c72d162d0..e1026f8c1 100644 --- a/python/src/trezorlib/btc.py +++ b/python/src/trezorlib/btc.py @@ -114,7 +114,21 @@ def get_public_node( coin_name: Optional[str] = None, script_type: messages.InputScriptType = messages.InputScriptType.SPENDADDRESS, ignore_xpub_magic: bool = False, + preauthorized: bool = False, + unlock_path: Optional[List[int]] = None, + unlock_path_mac: Optional[bytes] = None, ) -> "MessageType": + if unlock_path: + res = client.call( + messages.UnlockPath(address_n=unlock_path, mac=unlock_path_mac) + ) + if not isinstance(res, messages.UnlockedPathRequest): + raise exceptions.TrezorException("Unexpected message") + elif preauthorized: + res = client.call(messages.DoPreauthorized()) + if not isinstance(res, messages.PreauthorizedRequest): + raise exceptions.TrezorException("Unexpected message") + return client.call( messages.GetPublicKey( address_n=n, @@ -141,7 +155,21 @@ def get_authenticated_address( multisig: Optional[messages.MultisigRedeemScriptType] = None, script_type: messages.InputScriptType = messages.InputScriptType.SPENDADDRESS, ignore_xpub_magic: bool = False, + preauthorized: bool = False, + unlock_path: Optional[List[int]] = None, + unlock_path_mac: Optional[bytes] = None, ) -> "MessageType": + if unlock_path: + res = client.call( + messages.UnlockPath(address_n=unlock_path, mac=unlock_path_mac) + ) + if not isinstance(res, messages.UnlockedPathRequest): + raise exceptions.TrezorException("Unexpected message") + elif preauthorized: + res = client.call(messages.DoPreauthorized()) + if not isinstance(res, messages.PreauthorizedRequest): + raise exceptions.TrezorException("Unexpected message") + return client.call( messages.GetAddress( address_n=n, @@ -257,6 +285,8 @@ def sign_tx( prev_txes: Optional["TxCacheType"] = None, payment_reqs: Sequence[messages.TxAckPaymentRequest] = (), preauthorized: bool = False, + unlock_path: Optional[List[int]] = None, + unlock_path_mac: Optional[bytes] = None, **kwargs: Any, ) -> Tuple[Sequence[Optional[bytes]], bytes]: """Sign a Bitcoin-like transaction. @@ -294,7 +324,13 @@ def sign_tx( if hasattr(signtx, name): setattr(signtx, name, value) - if preauthorized: + if unlock_path: + res = client.call( + messages.UnlockPath(address_n=unlock_path, mac=unlock_path_mac) + ) + if not isinstance(res, messages.UnlockedPathRequest): + raise exceptions.TrezorException("Unexpected message") + elif preauthorized: res = client.call(messages.DoPreauthorized()) if not isinstance(res, messages.PreauthorizedRequest): raise exceptions.TrezorException("Unexpected message") diff --git a/python/src/trezorlib/device.py b/python/src/trezorlib/device.py index 6f632d1af..d596681a4 100644 --- a/python/src/trezorlib/device.py +++ b/python/src/trezorlib/device.py @@ -19,8 +19,8 @@ import time from typing import TYPE_CHECKING, Callable, Optional from . import messages -from .exceptions import Cancelled -from .tools import expect, session +from .exceptions import Cancelled, TrezorFailure +from .tools import Address, expect, session if TYPE_CHECKING: from .client import TrezorClient @@ -220,6 +220,20 @@ def cancel_authorization(client: "TrezorClient") -> "MessageType": return client.call(messages.CancelAuthorization()) +@expect(messages.UnlockedPathRequest, field="mac", ret_type=bytes) +def unlock_path(client: "TrezorClient", n: "Address") -> "MessageType": + resp = client.call(messages.UnlockPath(address_n=n)) + + # Cancel the UnlockPath workflow now that we have the authentication code. + cancel_resp = client.call_raw(messages.Cancel()) + if not isinstance(cancel_resp, messages.Failure): + raise RuntimeError("Invalid response") + if cancel_resp.code != messages.FailureType.ActionCancelled: + raise TrezorFailure(cancel_resp) + + return resp + + @session @expect(messages.Success, field="message", ret_type=str) def reboot_to_bootloader(client: "TrezorClient") -> "MessageType":