hardware wallets: better handle label collision when selecting device
related: #5759
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user