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.
This commit is contained in:
@@ -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())
|
||||||
|
|||||||
@@ -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.'''
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user