Handle Trezor canceled actions and bad arguments to trezorlib

This commit is contained in:
Andrew Chow 2019-01-30 22:52:02 -05:00
parent 9d52695699
commit 4e49da29ad

View File

@ -1,9 +1,10 @@
# Trezor interaction script # Trezor interaction script
from ..hwwclient import HardwareWalletClient from ..hwwclient import HardwareWalletClient
from ..errors import BadArgumentError, DeviceAlreadyInitError, DeviceAlreadyUnlockedError, UnavailableActionError, DeviceNotReadyError from ..errors import ActionCanceledError, BadArgumentError, DeviceAlreadyInitError, DeviceAlreadyUnlockedError, DeviceConnectionError, UnavailableActionError, DeviceNotReadyError
from trezorlib.client import TrezorClient as Trezor from trezorlib.client import TrezorClient as Trezor
from trezorlib.debuglink import TrezorClientDebugLink from trezorlib.debuglink import TrezorClientDebugLink
from trezorlib.exceptions import Cancelled
from trezorlib.transport import enumerate_devices, get_transport from trezorlib.transport import enumerate_devices, get_transport
from trezorlib.ui import ClickUI, mnemonic_words, PIN_MATRIX_DESCRIPTION from trezorlib.ui import ClickUI, mnemonic_words, PIN_MATRIX_DESCRIPTION
from trezorlib import protobuf, tools, btc, device from trezorlib import protobuf, tools, btc, device
@ -11,6 +12,7 @@ from trezorlib import messages as proto
from ..base58 import get_xpub_fingerprint, decode, to_address, xpub_main_2_test, get_xpub_fingerprint_hex from ..base58 import get_xpub_fingerprint, decode, to_address, xpub_main_2_test, get_xpub_fingerprint_hex
from ..serializations import ser_uint256, uint256_from_str from ..serializations import ser_uint256, uint256_from_str
from .. import bech32 from .. import bech32
from usb1 import USBErrorNoDevice
import base64 import base64
import binascii import binascii
@ -66,6 +68,18 @@ class TrezorNoInit(Trezor):
self.session_counter = 0 self.session_counter = 0
def trezor_exception(f):
def func(*args, **kwargs):
try:
return f(*args, **kwargs)
except ValueError as e:
raise BadArgumentError(str(e))
except Cancelled as e:
raise ActionCanceledError('{} canceled'.format(f.__name__))
except USBErrorNoDevice as e:
raise DeviceConnectionError('Device disconnected')
return func
# This class extends the HardwareWalletClient for Trezor specific things # This class extends the HardwareWalletClient for Trezor specific things
class TrezorClient(HardwareWalletClient): class TrezorClient(HardwareWalletClient):
@ -93,6 +107,7 @@ class TrezorClient(HardwareWalletClient):
# Must return a dict with the xpub # Must return a dict with the xpub
# Retrieves the public key at the specified BIP 32 derivation path # Retrieves the public key at the specified BIP 32 derivation path
@trezor_exception
def get_pubkey_at_path(self, path): def get_pubkey_at_path(self, path):
self._check_unlocked() self._check_unlocked()
try: try:
@ -107,6 +122,7 @@ class TrezorClient(HardwareWalletClient):
# Must return a hex string with the signed transaction # Must return a hex string with the signed transaction
# The tx must be in the psbt format # The tx must be in the psbt format
@trezor_exception
def sign_tx(self, tx): def sign_tx(self, tx):
self._check_unlocked() self._check_unlocked()
@ -285,6 +301,7 @@ class TrezorClient(HardwareWalletClient):
# Must return a base64 encoded string with the signed message # Must return a base64 encoded string with the signed message
# The message can be any string # The message can be any string
@trezor_exception
def sign_message(self, message, keypath): def sign_message(self, message, keypath):
self._check_unlocked() self._check_unlocked()
path = tools.parse_path(keypath) path = tools.parse_path(keypath)
@ -292,6 +309,7 @@ class TrezorClient(HardwareWalletClient):
return {'signature': base64.b64encode(result.signature).decode('utf-8')} return {'signature': base64.b64encode(result.signature).decode('utf-8')}
# Display address of specified type on the device. Only supports single-key based addresses. # Display address of specified type on the device. Only supports single-key based addresses.
@trezor_exception
def display_address(self, keypath, p2sh_p2wpkh, bech32): def display_address(self, keypath, p2sh_p2wpkh, bech32):
self._check_unlocked() self._check_unlocked()
expanded_path = tools.parse_path(keypath) expanded_path = tools.parse_path(keypath)
@ -305,7 +323,9 @@ class TrezorClient(HardwareWalletClient):
return {'address': address} return {'address': address}
# Setup a new device # Setup a new device
@trezor_exception
def setup_device(self, label='', passphrase=''): def setup_device(self, label='', passphrase=''):
self.client.init_device()
if self.client.features.initialized: if self.client.features.initialized:
raise DeviceAlreadyInitError('Device is already initialized. Use wipe first and try again') raise DeviceAlreadyInitError('Device is already initialized. Use wipe first and try again')
passphrase_enabled = False passphrase_enabled = False
@ -315,12 +335,14 @@ class TrezorClient(HardwareWalletClient):
return {'success': True} return {'success': True}
# Wipe this device # Wipe this device
@trezor_exception
def wipe_device(self): def wipe_device(self):
self._check_unlocked() self._check_unlocked()
device.wipe(self.client) device.wipe(self.client)
return {'success': True} return {'success': True}
# Restore device from mnemonic or xprv # Restore device from mnemonic or xprv
@trezor_exception
def restore_device(self, label=''): def restore_device(self, label=''):
passphrase_enabled = False passphrase_enabled = False
device.recover(self.client, label=label, input_callback=mnemonic_words, passphrase_protection=bool(self.password)) device.recover(self.client, label=label, input_callback=mnemonic_words, passphrase_protection=bool(self.password))
@ -331,10 +353,12 @@ class TrezorClient(HardwareWalletClient):
raise UnavailableActionError('The Trezor does not support creating a backup via software') raise UnavailableActionError('The Trezor does not support creating a backup via software')
# Close the device # Close the device
@trezor_exception
def close(self): def close(self):
self.client.close() self.client.close()
# Prompt for a pin on device # Prompt for a pin on device
@trezor_exception
def prompt_pin(self): def prompt_pin(self):
self.client.init_device() self.client.init_device()
if not self.client.features.pin_protection: if not self.client.features.pin_protection:
@ -347,6 +371,7 @@ class TrezorClient(HardwareWalletClient):
return {'success': True} return {'success': True}
# Send the pin # Send the pin
@trezor_exception
def send_pin(self, pin): def send_pin(self, pin):
self.client.features = self.client.call_raw(proto.GetFeatures()) self.client.features = self.client.call_raw(proto.GetFeatures())
if isinstance(self.client.features, proto.Features): if isinstance(self.client.features, proto.Features):