mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
hww: distinguish devices based on "soft device id" (not just labels)
fixes #5759
This commit is contained in:
parent
7dabbdd082
commit
9d0bb295e6
8 changed files with 50 additions and 6 deletions
|
@ -438,6 +438,7 @@ class BaseWizard(Logger):
|
|||
if not client: raise Exception("failed to find client for device id")
|
||||
root_fingerprint = client.request_root_fingerprint_from_device()
|
||||
label = client.label() # use this as device_info.label might be outdated!
|
||||
soft_device_id = client.get_soft_device_id() # use this as device_info.device_id might be outdated!
|
||||
except ScriptTypeNotSupported:
|
||||
raise # this is handled in derivation_dialog
|
||||
except BaseException as e:
|
||||
|
@ -451,6 +452,7 @@ class BaseWizard(Logger):
|
|||
'root_fingerprint': root_fingerprint,
|
||||
'xpub': xpub,
|
||||
'label': label,
|
||||
'soft_device_id': soft_device_id,
|
||||
}
|
||||
k = hardware_keystore(d)
|
||||
self.on_keystore(k)
|
||||
|
@ -612,7 +614,7 @@ class BaseWizard(Logger):
|
|||
if os.path.exists(path):
|
||||
raise Exception('file already exists at path')
|
||||
if not self.pw_args:
|
||||
return
|
||||
return # FIXME
|
||||
pw_args = self.pw_args
|
||||
self.pw_args = None # clean-up so that it can get GC-ed
|
||||
storage = WalletStorage(path)
|
||||
|
|
|
@ -724,6 +724,7 @@ class Hardware_KeyStore(Xpub, KeyStore):
|
|||
# device reconnects
|
||||
self.xpub = d.get('xpub')
|
||||
self.label = d.get('label')
|
||||
self.soft_device_id = d.get('soft_device_id') # type: Optional[str]
|
||||
self.handler = None # type: Optional[HardwareHandlerBase]
|
||||
run_hook('init_keystore', self)
|
||||
|
||||
|
@ -747,6 +748,7 @@ class Hardware_KeyStore(Xpub, KeyStore):
|
|||
'derivation': self.get_derivation_prefix(),
|
||||
'root_fingerprint': self.get_root_fingerprint(),
|
||||
'label':self.label,
|
||||
'soft_device_id': self.soft_device_id,
|
||||
}
|
||||
|
||||
def unpaired(self):
|
||||
|
@ -788,6 +790,9 @@ class Hardware_KeyStore(Xpub, KeyStore):
|
|||
if self.label != client.label():
|
||||
self.label = client.label()
|
||||
self.is_requesting_to_be_rewritten_to_wallet_file = True
|
||||
if self.soft_device_id != client.get_soft_device_id():
|
||||
self.soft_device_id = client.get_soft_device_id()
|
||||
self.is_requesting_to_be_rewritten_to_wallet_file = True
|
||||
|
||||
|
||||
KeyStoreWithMPK = Union[KeyStore, MasterPublicKeyMixin] # intersection really...
|
||||
|
|
|
@ -306,6 +306,7 @@ class DeviceInfo(NamedTuple):
|
|||
initialized: Optional[bool] = None
|
||||
exception: Optional[Exception] = None
|
||||
plugin_name: Optional[str] = None # manufacturer, e.g. "trezor"
|
||||
soft_device_id: Optional[str] = None # if available, used to distinguish same-type hw devices
|
||||
|
||||
|
||||
class HardwarePluginToScan(NamedTuple):
|
||||
|
@ -548,7 +549,8 @@ class DeviceMgr(ThreadJob):
|
|||
infos.append(DeviceInfo(device=device,
|
||||
label=client.label(),
|
||||
initialized=client.is_initialized(),
|
||||
plugin_name=plugin.name))
|
||||
plugin_name=plugin.name,
|
||||
soft_device_id=client.get_soft_device_id()))
|
||||
|
||||
return infos
|
||||
|
||||
|
@ -575,6 +577,11 @@ class DeviceMgr(ThreadJob):
|
|||
devices = None
|
||||
if len(infos) == 1:
|
||||
return infos[0]
|
||||
# select device by id
|
||||
if keystore.soft_device_id:
|
||||
for info in infos:
|
||||
if info.soft_device_id == keystore.soft_device_id:
|
||||
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]
|
||||
|
@ -583,7 +590,7 @@ class DeviceMgr(ThreadJob):
|
|||
for info in infos:
|
||||
if info.label == keystore.label:
|
||||
return info
|
||||
# ask user to select device
|
||||
# ask user to select device manually
|
||||
msg = _("Please select which {} device to use:").format(plugin.device)
|
||||
descriptions = ["{label} ({init}, {transport})"
|
||||
.format(label=info.label or _("An unnamed {}").format(info.plugin_name),
|
||||
|
@ -594,8 +601,9 @@ class DeviceMgr(ThreadJob):
|
|||
if c is None:
|
||||
raise UserCancelled()
|
||||
info = infos[c]
|
||||
# save new label
|
||||
# save new label / soft_device_id
|
||||
keystore.set_label(info.label)
|
||||
keystore.soft_device_id = info.soft_device_id
|
||||
wallet = handler.get_wallet()
|
||||
if wallet is not None:
|
||||
wallet.save_keystore()
|
||||
|
|
|
@ -167,7 +167,7 @@ class HW_PluginBase(BasePlugin):
|
|||
class HardwareClientBase:
|
||||
|
||||
plugin: 'HW_PluginBase'
|
||||
handler: Optional['HardwareHandlerBase']
|
||||
handler = None # type: Optional['HardwareHandlerBase']
|
||||
|
||||
def is_pairable(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
@ -191,6 +191,16 @@ class HardwareClientBase:
|
|||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_soft_device_id(self) -> Optional[str]:
|
||||
"""An id-like string that is used to distinguish devices programmatically.
|
||||
This is a long term id for the device, that does not change between reconnects.
|
||||
This method should not prompt the user, i.e. no user interaction, as it is used
|
||||
during USB device enumeration (called for each unpaired device).
|
||||
Stored in the wallet file.
|
||||
"""
|
||||
# This functionality is optional. If not implemented just return None:
|
||||
return None
|
||||
|
||||
def has_usable_connection_with_device(self) -> bool:
|
||||
raise NotImplementedError()
|
||||
|
||||
|
|
|
@ -119,6 +119,9 @@ class KeepKeyClientBase(HardwareClientBase, GuiMixin, Logger):
|
|||
def label(self):
|
||||
return self.features.label
|
||||
|
||||
def get_soft_device_id(self):
|
||||
return self.features.device_id
|
||||
|
||||
def is_initialized(self):
|
||||
return self.features.initialized
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ class Ledger_Client(HardwareClientBase):
|
|||
self.dongleObject = btchip(hidDevice)
|
||||
self.preflightDone = False
|
||||
self._is_hw1 = is_hw1
|
||||
self._soft_device_id = None
|
||||
|
||||
def is_pairable(self):
|
||||
return True
|
||||
|
@ -82,6 +83,14 @@ class Ledger_Client(HardwareClientBase):
|
|||
def label(self):
|
||||
return ""
|
||||
|
||||
def get_soft_device_id(self):
|
||||
if self._soft_device_id is None:
|
||||
# modern ledger can provide xpub without user interaction
|
||||
# (hw1 would prompt for PIN)
|
||||
if not self.is_hw1():
|
||||
self._soft_device_id = self.request_root_fingerprint_from_device()
|
||||
return self._soft_device_id
|
||||
|
||||
def is_hw1(self) -> bool:
|
||||
return self._is_hw1
|
||||
|
||||
|
@ -176,7 +185,8 @@ class Ledger_Client(HardwareClientBase):
|
|||
# Acquire the new client on the next run
|
||||
else:
|
||||
raise e
|
||||
if self.has_detached_pin_support(self.dongleObject) and not self.is_pin_validated(self.dongleObject) and (self.handler is not None):
|
||||
if self.has_detached_pin_support(self.dongleObject) and not self.is_pin_validated(self.dongleObject):
|
||||
assert self.handler, "no handler for client"
|
||||
remaining_attempts = self.dongleObject.getVerifyPinRemainingAttempts()
|
||||
if remaining_attempts != 1:
|
||||
msg = "Enter your Ledger PIN - remaining attempts : " + str(remaining_attempts)
|
||||
|
|
|
@ -121,6 +121,9 @@ class SafeTClientBase(HardwareClientBase, GuiMixin, Logger):
|
|||
def label(self):
|
||||
return self.features.label
|
||||
|
||||
def get_soft_device_id(self):
|
||||
return self.features.device_id
|
||||
|
||||
def is_initialized(self):
|
||||
return self.features.initialized
|
||||
|
||||
|
|
|
@ -98,6 +98,9 @@ class TrezorClientBase(HardwareClientBase, Logger):
|
|||
def label(self):
|
||||
return self.features.label
|
||||
|
||||
def get_soft_device_id(self):
|
||||
return self.features.device_id
|
||||
|
||||
def is_initialized(self):
|
||||
return self.features.initialized
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue