From 43acd09df84db600be440b8f19df7a42e4c3f93f Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 5 Dec 2018 14:26:19 +0100 Subject: [PATCH] trezor: support outdated firmware notifications Outdated firmware error messages were originally raised from create_client, which would mean that a client for an outdated device would not be created. This had a number of undesirable outcomes due to "client does not exist" being conflated with "no device is connected". Instead, we raise in setup_client (which prevents creating new wallets with outdated devices, BUT shows them in device list), and python-trezor also raises on most calls (which gives us an error message when opening wallet and/or trying to do basically anything with it). This is still suboptimal - i.e., there's currently no way for Electrum to claim higher version requirement than the underlying python-trezor, and so minimum_firmware property is pretty much useless ATM. --- electrum/plugins/trezor/clientbase.py | 16 ++++++++-------- electrum/plugins/trezor/trezor.py | 22 ++++++++-------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/electrum/plugins/trezor/clientbase.py b/electrum/plugins/trezor/clientbase.py index 037afeca0..687f4c95f 100644 --- a/electrum/plugins/trezor/clientbase.py +++ b/electrum/plugins/trezor/clientbase.py @@ -2,12 +2,12 @@ import time from struct import pack from electrum.i18n import _ -from electrum.util import PrintError, UserCancelled +from electrum.util import PrintError, UserCancelled, UserFacingException from electrum.keystore import bip39_normalize_passphrase from electrum.bip32 import serialize_xpub, convert_bip32_path_to_list_of_uint32 as parse_path from trezorlib.client import TrezorClient -from trezorlib.exceptions import TrezorFailure, Cancelled +from trezorlib.exceptions import TrezorFailure, Cancelled, OutdatedFirmwareError from trezorlib.messages import WordRequestType, FailureType, RecoveryDeviceType import trezorlib.btc import trezorlib.device @@ -66,6 +66,8 @@ class TrezorClientBase(PrintError): raise UserCancelled from exc_value elif issubclass(exc_type, TrezorFailure): raise RuntimeError(exc_value.message) from exc_value + elif issubclass(exc_type, OutdatedFirmwareError): + raise UserFacingException(exc_value) from exc_value else: return False return True @@ -163,12 +165,10 @@ class TrezorClientBase(PrintError): self.print_error("closing client") self.clear_session() - def firmware_version(self): - f = self.features - return (f.major_version, f.minor_version, f.patch_version) - - def atleast_version(self, major, minor=0, patch=0): - return self.firmware_version() >= (major, minor, patch) + def is_uptodate(self): + if self.client.is_outdated(): + return False + return self.client.version >= self.plugin.minimum_firmware def get_trezor_model(self): """Returns '1' for Trezor One, 'T' for Trezor T.""" diff --git a/electrum/plugins/trezor/trezor.py b/electrum/plugins/trezor/trezor.py index 77954bf56..92ea25cc5 100644 --- a/electrum/plugins/trezor/trezor.py +++ b/electrum/plugins/trezor/trezor.py @@ -141,20 +141,7 @@ class TrezorPlugin(HW_PluginBase): self.print_error("connected to device at", device.path) # note that this call can still raise! - client = TrezorClientBase(transport, handler, self) - - if not client.atleast_version(*self.minimum_firmware): - msg = (_('Outdated {} firmware for device labelled {}. Please ' - 'download the updated firmware from {}') - .format(self.device, client.label(), self.firmware_URL)) - self.print_error(msg) - if handler: - handler.show_error(msg) - else: - raise UserFacingException(msg) - return None - - return client + return TrezorClientBase(transport, handler, self) def get_client(self, keystore, force_pair=True): devmgr = self.device_manager() @@ -265,6 +252,13 @@ class TrezorPlugin(HW_PluginBase): if client is None: raise UserFacingException(_('Failed to create a client for this device.') + '\n' + _('Make sure it is in the correct state.')) + + if not client.is_uptodate(): + msg = (_('Outdated {} firmware for device labelled {}. Please ' + 'download the updated firmware from {}') + .format(self.device, client.label(), self.firmware_URL)) + raise UserFacingException(msg) + # fixme: we should use: client.handler = wizard client.handler = self.create_handler(wizard) if not device_info.initialized: