Skip to content

Commit b5786ad

Browse files
committed
Merge #729: Add --emulators option to explicitly choose to detect emulators in enumeration and device auto detection
ea7310f Bump version to 3.0.0 (Ava Chow) 27c1b42 Add --emulators option and skip enumerating emulators by default (Ava Chow) Pull request description: This changes the default behavior to ignore emulators unless specified with `--emulators`. Since this is a backwards incompatible change, the major version number is bumped to 3. Closes #653 Top commit has no ACKs. Tree-SHA512: 373dbf21e813471c58262cd8e27f1c33f63d42db783ff0f567d223b5e35589e116f3c1029c13befddb741555da41940f97bafd443fc135ad0de0b7e7086749f7
2 parents cfaf26c + ea7310f commit b5786ad

18 files changed

+98
-78
lines changed

hwilib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.4.0"
1+
__version__ = "3.0.0-dev"

hwilib/_cli.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def displayaddress_handler(args: argparse.Namespace, client: HardwareWalletClien
6060
return displayaddress(client, desc=args.desc, path=args.path, addr_type=args.addr_type)
6161

6262
def enumerate_handler(args: argparse.Namespace) -> List[Dict[str, Any]]:
63-
return enumerate(password=args.password, expert=args.expert, chain=args.chain)
63+
return enumerate(password=args.password, expert=args.expert, chain=args.chain, allow_emulators=args.allow_emulators)
6464

6565
def getmasterxpub_handler(args: argparse.Namespace, client: HardwareWalletClient) -> Dict[str, str]:
6666
return getmasterxpub(client, addrtype=args.addr_type, account=args.account)
@@ -145,6 +145,7 @@ def get_parser() -> HWIArgumentParser:
145145
parser.add_argument('--stdin', help='Enter commands and arguments via stdin', action='store_true')
146146
parser.add_argument('--interactive', '-i', help='Use some commands interactively. Currently required for all device configuration commands', action='store_true')
147147
parser.add_argument('--expert', help='Do advanced things and get more detailed information returned from some commands. Use at your own risk.', action='store_true')
148+
parser.add_argument("--emulators", help="Enable enumeration and detection of device emulators", action="store_true", dest="allow_emulators")
148149

149150
subparsers = parser.add_subparsers(description='Commands', dest='command')
150151
# work-around to make subparser required
@@ -277,9 +278,9 @@ def process_commands(cli_args: List[str]) -> Any:
277278

278279
# Auto detect if we are using fingerprint or type to identify device
279280
if args.fingerprint or (args.device_type and not args.device_path):
280-
client = find_device(args.password, args.device_type, args.fingerprint, args.expert, args.chain)
281+
client = find_device(args.password, args.device_type, args.fingerprint, args.expert, args.chain, args.allow_emulators)
281282
if not client:
282-
return {'error': 'Could not find device with specified fingerprint', 'code': DEVICE_CONN_ERROR}
283+
return {'error': 'Could not find device with specified fingerprint or type', 'code': DEVICE_CONN_ERROR}
283284
elif args.device_type and args.device_path:
284285
with handle_errors(result=result, code=DEVICE_CONN_ERROR):
285286
client = get_client(device_type, device_path, password, args.expert, args.chain)

hwilib/_gui.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def attestation_check(self, result: bool) -> None:
321321
pass
322322

323323
class HWIQt(QMainWindow):
324-
def __init__(self, passphrase=None, chain=Chain.MAIN):
324+
def __init__(self, passphrase=None, chain=Chain.MAIN, allow_emulators: bool = False):
325325
super(HWIQt, self).__init__()
326326
self.ui = Ui_MainWindow()
327327
self.ui.setupUi(self)
@@ -343,6 +343,7 @@ def __init__(self, passphrase=None, chain=Chain.MAIN):
343343
'path': None,
344344
'account_used': True
345345
}
346+
self.allow_emulators = allow_emulators
346347

347348
self.ui.enumerate_refresh_button.clicked.connect(self.refresh_clicked)
348349
self.ui.setpass_button.clicked.connect(self.show_setpassphrasedialog)
@@ -372,7 +373,7 @@ def refresh_clicked(self):
372373
self.client.close()
373374
self.client = None
374375

375-
self.devices = commands.enumerate(self.passphrase)
376+
self.devices = commands.enumerate(password=self.passphrase, expert=False, chain=self.chain, allow_emulators=self.allow_emulators)
376377
self.ui.enumerate_combobox.currentIndexChanged.disconnect()
377378
self.ui.enumerate_combobox.clear()
378379
self.ui.enumerate_combobox.addItem('')
@@ -524,6 +525,7 @@ def process_gui_commands(cli_args):
524525
parser.add_argument('--chain', help='Select chain to work with', type=Chain.argparse, choices=list(Chain), default=Chain.MAIN)
525526
parser.add_argument('--debug', help='Print debug statements', action='store_true')
526527
parser.add_argument('--version', action='version', version='%(prog)s {}'.format(__version__))
528+
parser.add_argument("--emulators", help="Enable enumeration and detection of device emulators", action="store_true", dest="allow_emulators")
527529

528530
# Parse arguments again for anything entered over stdin
529531
args = parser.parse_args(cli_args)
@@ -536,7 +538,7 @@ def process_gui_commands(cli_args):
536538
# Qt setup
537539
app = QApplication()
538540

539-
window = HWIQt(args.password, args.chain)
541+
window = HWIQt(args.password, args.chain, args.allow_emulators)
540542

541543
window.refresh_clicked()
542544

hwilib/commands.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ def get_client(device_type: str, device_path: str, password: Optional[str] = Non
101101
return client
102102

103103
# Get a list of all available hardware wallets
104-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
104+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
105105
"""
106106
Enumerate all of the devices that HWI can potentially access.
107107
@@ -114,7 +114,7 @@ def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain
114114
for module in all_devs:
115115
try:
116116
imported_dev = importlib.import_module('.devices.' + module, __package__)
117-
result.extend(imported_dev.enumerate(password, expert, chain))
117+
result.extend(imported_dev.enumerate(password, expert, chain, allow_emulators))
118118
except ImportError as e:
119119
# Warn for ImportErrors, but largely ignore them to allow users not install
120120
# all device dependencies if only one or some devices are wanted.
@@ -129,6 +129,7 @@ def find_device(
129129
fingerprint: Optional[str] = None,
130130
expert: bool = False,
131131
chain: Chain = Chain.MAIN,
132+
allow_emulators: bool = False,
132133
) -> Optional[HardwareWalletClient]:
133134
"""
134135
Find a device from the device type or fingerprint and get a client to access it.
@@ -145,7 +146,7 @@ def find_device(
145146
:return: A client to interact with the found device
146147
"""
147148

148-
devices = enumerate(password)
149+
devices = enumerate(password, expert, chain, allow_emulators)
149150
for d in devices:
150151
if device_type is not None and d['type'] != device_type and d['model'] != device_type:
151152
continue

hwilib/devices/bitbox02.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def _xpubs_equal_ignoring_version(xpub1: bytes, xpub2: bytes) -> bool:
173173
return xpub1[4:] == xpub2[4:]
174174

175175

176-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
176+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
177177
"""
178178
Enumerate all BitBox02 devices. Bootloaders excluded.
179179
"""

hwilib/devices/coldcard.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,11 @@ def can_sign_taproot(self) -> bool:
399399
return False
400400

401401

402-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
402+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = True) -> List[Dict[str, Any]]:
403403
results = []
404404
devices = hid.enumerate(COINKITE_VID, CKCC_PID)
405-
devices.append({'path': CC_SIMULATOR_SOCK.encode()})
405+
if allow_emulators:
406+
devices.append({'path': CC_SIMULATOR_SOCK.encode()})
406407
for d in devices:
407408
d_data: Dict[str, Any] = {}
408409

hwilib/devices/digitalbitbox.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -679,17 +679,18 @@ def can_sign_taproot(self) -> bool:
679679
return False
680680

681681

682-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
682+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
683683
results = []
684684
devices = hid.enumerate(DBB_VENDOR_ID, DBB_DEVICE_ID)
685685
# Try connecting to simulator
686-
try:
687-
dev = BitboxSimulator('127.0.0.1', 35345)
688-
dev.send_recv(b'{"device" : "info"}')
689-
devices.append({'path': b'udp:127.0.0.1:35345', 'interface_number': 0})
690-
dev.close()
691-
except Exception:
692-
pass
686+
if allow_emulators:
687+
try:
688+
dev = BitboxSimulator('127.0.0.1', 35345)
689+
dev.send_recv(b'{"device" : "info"}')
690+
devices.append({'path': b'udp:127.0.0.1:35345', 'interface_number': 0})
691+
dev.close()
692+
except Exception:
693+
pass
693694
for d in devices:
694695
if ('interface_number' in d and d['interface_number'] == 0
695696
or ('usage_page' in d and d['usage_page'] == 0xffff)):

hwilib/devices/jade.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,7 @@ def can_sign_taproot(self) -> bool:
508508
return False
509509

510510

511-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
511+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
512512
results = []
513513

514514
def _get_device_entry(device_model: str, device_path: str) -> Dict[str, Any]:
@@ -537,16 +537,17 @@ def _get_device_entry(device_model: str, device_path: str) -> Dict[str, Any]:
537537
results.append(_get_device_entry('jade', devinfo.device))
538538

539539
# If we can connect to the simulator, add it too
540-
try:
541-
with JadeAPI.create_serial(SIMULATOR_PATH, timeout=1) as jade:
542-
verinfo = jade.get_version_info()
540+
if allow_emulators:
541+
try:
542+
with JadeAPI.create_serial(SIMULATOR_PATH, timeout=1) as jade:
543+
verinfo = jade.get_version_info()
543544

544-
if verinfo is not None:
545-
results.append(_get_device_entry('jade_simulator', SIMULATOR_PATH))
545+
if verinfo is not None:
546+
results.append(_get_device_entry('jade_simulator', SIMULATOR_PATH))
546547

547-
except Exception as e:
548-
# If we get any sort of error do not add the simulator
549-
logging.debug(f'Failed to connect to Jade simulator at {SIMULATOR_PATH}')
550-
logging.debug(e)
548+
except Exception as e:
549+
# If we get any sort of error do not add the simulator
550+
logging.debug(f'Failed to connect to Jade simulator at {SIMULATOR_PATH}')
551+
logging.debug(e)
551552

552553
return results

hwilib/devices/keepkey.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,12 @@ def can_sign_taproot(self) -> bool:
172172
return False
173173

174174

175-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
175+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
176176
results = []
177177
devs = hid.HidTransport.enumerate(usb_ids=KEEPKEY_HID_IDS)
178178
devs.extend(webusb.WebUsbTransport.enumerate(usb_ids=KEEPKEY_WEBUSB_IDS))
179-
devs.extend(udp.UdpTransport.enumerate(KEEPKEY_SIMULATOR_PATH))
179+
if allow_emulators:
180+
devs.extend(udp.UdpTransport.enumerate(KEEPKEY_SIMULATOR_PATH))
180181
for dev in devs:
181182
d_data: Dict[str, Any] = {}
182183

hwilib/devices/ledger.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,11 +546,12 @@ def can_sign_taproot(self) -> bool:
546546
return isinstance(self.client, NewClient)
547547

548548

549-
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> List[Dict[str, Any]]:
549+
def enumerate(password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, allow_emulators: bool = False) -> List[Dict[str, Any]]:
550550
results = []
551551
devices = []
552552
devices.extend(hid.enumerate(LEDGER_VENDOR_ID, 0))
553-
devices.append({'path': SIMULATOR_PATH.encode(), 'interface_number': 0, 'product_id': 0x1000})
553+
if allow_emulators:
554+
devices.append({'path': SIMULATOR_PATH.encode(), 'interface_number': 0, 'product_id': 0x1000})
554555

555556
for d in devices:
556557
if ('interface_number' in d and d['interface_number'] == 0

0 commit comments

Comments
 (0)