electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 56c3de0e1eb28f6017286f51c37c5c45b86690bd
parent 6e3875ceabf75ee96e722358bcff33f883dddbf5
Author: SomberNight <somber.night@protonmail.com>
Date:   Sun, 17 Nov 2019 01:15:44 +0100

hardware wallets: better handle label collision when selecting device

related: #5759

Diffstat:
Melectrum/plugin.py | 26+++++++++++++++++++-------
Melectrum/plugins/hw_wallet/plugin.py | 7++++++-
2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/electrum/plugin.py b/electrum/plugin.py @@ -314,6 +314,9 @@ class HardwarePluginToScan(NamedTuple): exception: Optional[Exception] +PLACEHOLDER_HW_CLIENT_LABELS = {"", " "} + + class DeviceMgr(ThreadJob): '''Manages hardware clients. A client communicates over a hardware channel with the device. @@ -507,7 +510,7 @@ class DeviceMgr(ThreadJob): 'its seed (and passphrase, if any). Otherwise all bitcoins you ' 'receive will be unspendable.').format(plugin.device)) - def unpaired_device_infos(self, handler, plugin: 'HW_PluginBase', devices=None, + def unpaired_device_infos(self, handler, plugin: 'HW_PluginBase', devices: List['Device'] = None, include_failing_clients=False): '''Returns a list of DeviceInfo objects: one for each connected, unpaired device accepted by the plugin.''' @@ -537,7 +540,7 @@ class DeviceMgr(ThreadJob): return infos def select_device(self, plugin: 'HW_PluginBase', handler, - keystore: 'Hardware_KeyStore', devices=None) -> 'DeviceInfo': + keystore: 'Hardware_KeyStore', devices: List['Device'] = None) -> 'DeviceInfo': '''Ask the user to select a device to use if there is more than one, and return the DeviceInfo for the device.''' while True: @@ -557,12 +560,21 @@ class DeviceMgr(ThreadJob): devices = None if len(infos) == 1: return infos[0] - # select device by label - for info in infos: - if info.label == keystore.label: - return info + # select device by label automatically; + # but only if not a placeholder label and only if there is no collision + device_labels = [info.label for info in infos] + if (keystore.label not in PLACEHOLDER_HW_CLIENT_LABELS + and device_labels.count(keystore.label) == 1): + for info in infos: + if info.label == keystore.label: + return info + # ask user to select device msg = _("Please select which {} device to use:").format(plugin.device) - descriptions = [str(info.label) + ' (%s)'%(_("initialized") if info.initialized else _("wiped")) for info in infos] + descriptions = ["{label} ({init}, {transport})" + .format(label=info.label, + init=(_("initialized") if info.initialized else _("wiped")), + transport=info.device.transport_ui_string) + for info in infos] c = handler.query_choice(msg, descriptions) if c is None: raise UserCancelled() diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py @@ -160,7 +160,12 @@ class HardwareClientBase: raise NotImplementedError() def label(self) -> str: - """The name given by the user to the device.""" + """The name given by the user to the device. + + Note: labels are shown to the user to help distinguish their devices, + and they are also used as a fallback to distinguish devices programmatically. + So ideally, different devices would have different labels. + """ raise NotImplementedError() def has_usable_connection_with_device(self) -> bool: