Browse Source

Trezor/KeepKey: force watching only improvements

Only warn about watching only once given a chance to pair.
Failure to pair makes watching-only and warns.
In error message to user, distinguish between failure to connect
and failure to pair.
283
Neil Booth 9 years ago
parent
commit
e61fffab55
  1. 1
      gui/qt/main_window.py
  2. 52
      lib/plugins.py
  3. 13
      plugins/hw_wallet/hw_wallet.py
  4. 15
      plugins/trezor/plugin.py

1
gui/qt/main_window.py

@ -311,6 +311,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
title = 'Electrum %s - %s' % (self.wallet.electrum_version, title = 'Electrum %s - %s' % (self.wallet.electrum_version,
self.wallet.basename()) self.wallet.basename())
if self.wallet.is_watching_only(): if self.wallet.is_watching_only():
self.warn_if_watching_only()
title += ' [%s]' % (_('watching only')) title += ' [%s]' % (_('watching only'))
self.setWindowTitle(title) self.setWindowTitle(title)
self.password_menu.setEnabled(self.wallet.can_change_password()) self.password_menu.setEnabled(self.wallet.can_change_password())

52
lib/plugins.py

@ -234,6 +234,13 @@ class BasePlugin(PrintError):
def settings_dialog(self): def settings_dialog(self):
pass pass
class DeviceNotFoundError(Exception):
pass
class DeviceUnpairableError(Exception):
pass
Device = namedtuple("Device", "path interface_number id_ product_key") Device = namedtuple("Device", "path interface_number id_ product_key")
DeviceInfo = namedtuple("DeviceInfo", "device description initialized") DeviceInfo = namedtuple("DeviceInfo", "device description initialized")
@ -368,25 +375,38 @@ class DeviceMgr(PrintError):
return self.create_client(device, wallet.handler, plugin) return self.create_client(device, wallet.handler, plugin)
if force_pair: if force_pair:
first_address, derivation = wallet.first_address() return self.force_pair_wallet(plugin, wallet, devices)
assert first_address
# The wallet has not been previously paired, so let the user
# choose an unpaired device and compare its first address.
info = self.select_device(wallet, plugin, devices)
if info:
client = self.client_lookup(info.device.id_)
if client and client.is_pairable():
# See comment above for same code
client.handler = wallet.handler
# This will trigger a PIN/passphrase entry request
client_first_address = client.first_address(derivation)
if client_first_address == first_address:
self.pair_wallet(wallet, info.device.id_)
return client
return None return None
def force_pair_wallet(self, plugin, wallet, devices):
first_address, derivation = wallet.first_address()
assert first_address
# The wallet has not been previously paired, so let the user
# choose an unpaired device and compare its first address.
info = self.select_device(wallet, plugin, devices)
if info:
client = self.client_lookup(info.device.id_)
if client and client.is_pairable():
# See comment above for same code
client.handler = wallet.handler
# This will trigger a PIN/passphrase entry request
client_first_address = client.first_address(derivation)
if client_first_address == first_address:
self.pair_wallet(wallet, info.device.id_)
return client
if info and client:
# The user input has wrong PIN or passphrase
raise DeviceUnpairableError(
_('Unable to pair with your %s.') % plugin.device)
raise DeviceNotFoundError(
_('Could not connect to your %s. Verify the cable is '
'connected and that no other application is using it.')
% plugin.device)
def unpaired_device_infos(self, handler, plugin, devices=None): def unpaired_device_infos(self, handler, plugin, devices=None):
'''Returns a list of DeviceInfo objects: one for each connected, '''Returns a list of DeviceInfo objects: one for each connected,
unpaired device accepted by the plugin.''' unpaired device accepted by the plugin.'''

13
plugins/hw_wallet/hw_wallet.py

@ -39,26 +39,29 @@ class BIP44_HW_Wallet(BIP44_Wallet):
# handler. The handler is per-window and preserved across # handler. The handler is per-window and preserved across
# device reconnects # device reconnects
self.handler = None self.handler = None
self.force_watching_only = True self.force_watching_only = False
def set_session_timeout(self, seconds): def set_session_timeout(self, seconds):
self.print_error("setting session timeout to %d seconds" % seconds) self.print_error("setting session timeout to %d seconds" % seconds)
self.session_timeout = seconds self.session_timeout = seconds
self.storage.put('session_timeout', seconds) self.storage.put('session_timeout', seconds)
def set_force_watching_only(self, value):
if value != self.force_watching_only:
self.force_watching_only = value
self.handler.watching_only_changed()
def unpaired(self): def unpaired(self):
'''A device paired with the wallet was diconnected. This can be '''A device paired with the wallet was diconnected. This can be
called in any thread context.''' called in any thread context.'''
self.print_error("unpaired") self.print_error("unpaired")
self.force_watching_only = True self.set_force_watching_only(True)
self.handler.watching_only_changed()
def paired(self): def paired(self):
'''A device paired with the wallet was (re-)connected. This can be '''A device paired with the wallet was (re-)connected. This can be
called in any thread context.''' called in any thread context.'''
self.print_error("paired") self.print_error("paired")
self.force_watching_only = False self.set_force_watching_only(False)
self.handler.watching_only_changed()
def timeout(self): def timeout(self):
'''Called when the wallet session times out. Note this is called from '''Called when the wallet session times out. Note this is called from

15
plugins/trezor/plugin.py

@ -20,9 +20,6 @@ from ..hw_wallet import BIP44_HW_Wallet, HW_PluginBase
# TREZOR initialization methods # TREZOR initialization methods
TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4) TIM_NEW, TIM_RECOVER, TIM_MNEMONIC, TIM_PRIVKEY = range(0, 4)
class DeviceDisconnectedError(Exception):
pass
class TrezorCompatibleWallet(BIP44_HW_Wallet): class TrezorCompatibleWallet(BIP44_HW_Wallet):
def get_public_key(self, bip32_path): def get_public_key(self, bip32_path):
@ -137,17 +134,15 @@ class TrezorCompatiblePlugin(HW_PluginBase):
assert self.main_thread != threading.current_thread() assert self.main_thread != threading.current_thread()
devmgr = self.device_manager() devmgr = self.device_manager()
client = devmgr.client_for_wallet(self, wallet, force_pair) try:
client = devmgr.client_for_wallet(self, wallet, force_pair)
except:
wallet.set_force_watching_only(True)
raise
if client: if client:
self.print_error("set last_operation") self.print_error("set last_operation")
wallet.last_operation = time.time() wallet.last_operation = time.time()
elif force_pair:
msg = (_('Could not connect to your %s. Verify the '
'cable is connected and that no other app is '
'using it.\nContinuing in watching-only mode '
'until the device is re-connected.') % self.device)
raise DeviceDisconnectedError(msg)
return client return client

Loading…
Cancel
Save