diff --git a/electrum/plugin.py b/electrum/plugin.py index 084063cd9..d86e76706 100644 --- a/electrum/plugin.py +++ b/electrum/plugin.py @@ -360,9 +360,8 @@ class DeviceMgr(ThreadJob): # A list of clients. The key is the client, the value is # a (path, id_) pair. Needs self.lock. self.clients = {} # type: Dict[HardwareClientBase, Tuple[Union[str, bytes], str]] - # What we recognise. Each entry is a (vendor_id, product_id) - # pair. - self.recognised_hardware = set() + # What we recognise. (vendor_id, product_id) -> Plugin + self._recognised_hardware = {} # type: Dict[Tuple[int, int], HW_PluginBase] # Custom enumerate functions for devices we don't know about. self._enumerate_func = set() # Needs self.lock. # locks: if you need to take multiple ones, acquire them in the order they are defined here! @@ -390,9 +389,9 @@ class DeviceMgr(ThreadJob): for client in clients: client.timeout(cutoff) - def register_devices(self, device_pairs): + def register_devices(self, device_pairs, *, plugin: 'HW_PluginBase'): for pair in device_pairs: - self.recognised_hardware.add(pair) + self._recognised_hardware[pair] = plugin def register_enumerate_func(self, func): with self.lock: @@ -642,24 +641,10 @@ class DeviceMgr(ThreadJob): devices = [] for d in hid_list: product_key = (d['vendor_id'], d['product_id']) - if product_key in self.recognised_hardware: - # Older versions of hid don't provide interface_number - interface_number = d.get('interface_number', -1) - usage_page = d['usage_page'] - id_ = d['serial_number'] - if len(id_) == 0: - id_ = str(d['path']) - id_ += str(interface_number) + str(usage_page) - # The BitBox02's product_id is not unique per device, thus use the path instead to - # distinguish devices. - if d["product_id"] == 0x2403: - id_ = d['path'] - devices.append(Device(path=d['path'], - interface_number=interface_number, - id_=id_, - product_key=product_key, - usage_page=usage_page, - transport_ui_string='hid')) + if product_key in self._recognised_hardware: + plugin = self._recognised_hardware[product_key] + device = plugin.create_device_from_hid_enumeration(d, product_key=product_key) + devices.append(device) return devices @with_scan_lock diff --git a/electrum/plugins/bitbox02/bitbox02.py b/electrum/plugins/bitbox02/bitbox02.py index 9d6143583..6a62bee88 100644 --- a/electrum/plugins/bitbox02/bitbox02.py +++ b/electrum/plugins/bitbox02/bitbox02.py @@ -546,7 +546,7 @@ class BitBox02Plugin(HW_PluginBase): self.libraries_available = self.check_libraries_available() if not self.libraries_available: return - self.device_manager().register_devices(self.DEVICE_IDS) + self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) def get_library_version(self): try: @@ -617,3 +617,10 @@ class BitBox02Plugin(HW_PluginBase): derivation = keystore.get_derivation_prefix() xtype = keystore.get_bip32_node_for_xpub().xtype client.get_xpub(derivation, xtype, display=True) + + def create_device_from_hid_enumeration(self, d: dict, *, product_key) -> 'Device': + device = super().create_device_from_hid_enumeration(d, product_key=product_key) + # The BitBox02's product_id is not unique per device, thus use the path instead to + # distinguish devices. + id_ = str(d['path']) + return device._replace(id_=id_) diff --git a/electrum/plugins/coldcard/coldcard.py b/electrum/plugins/coldcard/coldcard.py index 810fd91b3..b8cae820c 100644 --- a/electrum/plugins/coldcard/coldcard.py +++ b/electrum/plugins/coldcard/coldcard.py @@ -477,7 +477,7 @@ class ColdcardPlugin(HW_PluginBase): if not self.libraries_available: return - self.device_manager().register_devices(self.DEVICE_IDS) + self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) self.device_manager().register_enumerate_func(self.detect_simulator) def get_library_version(self): diff --git a/electrum/plugins/digitalbitbox/digitalbitbox.py b/electrum/plugins/digitalbitbox/digitalbitbox.py index b14195578..15b91de7c 100644 --- a/electrum/plugins/digitalbitbox/digitalbitbox.py +++ b/electrum/plugins/digitalbitbox/digitalbitbox.py @@ -675,7 +675,7 @@ class DigitalBitboxPlugin(HW_PluginBase): def __init__(self, parent, config, name): HW_PluginBase.__init__(self, parent, config, name) if self.libraries_available: - self.device_manager().register_devices(self.DEVICE_IDS) + self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) self.digitalbitbox_config = self.config.get('digitalbitbox', {}) diff --git a/electrum/plugins/hw_wallet/plugin.py b/electrum/plugins/hw_wallet/plugin.py index 884732dad..c7c0c1eef 100644 --- a/electrum/plugins/hw_wallet/plugin.py +++ b/electrum/plugins/hw_wallet/plugin.py @@ -60,6 +60,22 @@ class HW_PluginBase(BasePlugin): def device_manager(self) -> 'DeviceMgr': return self.parent.device_manager + def create_device_from_hid_enumeration(self, d: dict, *, product_key) -> 'Device': + # Older versions of hid don't provide interface_number + interface_number = d.get('interface_number', -1) + usage_page = d['usage_page'] + id_ = d['serial_number'] + if len(id_) == 0: + id_ = str(d['path']) + id_ += str(interface_number) + str(usage_page) + device = Device(path=d['path'], + interface_number=interface_number, + id_=id_, + product_key=product_key, + usage_page=usage_page, + transport_ui_string='hid') + return device + @hook def close_wallet(self, wallet: 'Abstract_Wallet'): for keystore in wallet.get_keystores(): diff --git a/electrum/plugins/keepkey/keepkey.py b/electrum/plugins/keepkey/keepkey.py index 1722eaea6..4b0f19a3f 100644 --- a/electrum/plugins/keepkey/keepkey.py +++ b/electrum/plugins/keepkey/keepkey.py @@ -88,7 +88,7 @@ class KeepKeyPlugin(HW_PluginBase): self.DEVICE_IDS = (keepkeylib.transport_hid.DEVICE_IDS + keepkeylib.transport_webusb.DEVICE_IDS) # only "register" hid device id: - self.device_manager().register_devices(keepkeylib.transport_hid.DEVICE_IDS) + self.device_manager().register_devices(keepkeylib.transport_hid.DEVICE_IDS, plugin=self) # for webusb transport, use custom enumerate function: self.device_manager().register_enumerate_func(self.enumerate) self.libraries_available = True diff --git a/electrum/plugins/ledger/ledger.py b/electrum/plugins/ledger/ledger.py index d5abc5dbe..08cea77a3 100644 --- a/electrum/plugins/ledger/ledger.py +++ b/electrum/plugins/ledger/ledger.py @@ -578,7 +578,7 @@ class LedgerPlugin(HW_PluginBase): self.segwit = config.get("segwit") HW_PluginBase.__init__(self, parent, config, name) if self.libraries_available: - self.device_manager().register_devices(self.DEVICE_IDS) + self.device_manager().register_devices(self.DEVICE_IDS, plugin=self) def get_btchip_device(self, device): ledger = False