Skip to content

Commit d4cf550

Browse files
committed
Change passphrase (password) to Optional
We need to distinguish between passphrase not set, and empty passphrase. So use an Optional instead of checking for the empty string.
1 parent 7e3e2e6 commit d4cf550

10 files changed

+31
-27
lines changed

hwilib/_cli.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def get_parser() -> HWIArgumentParser:
136136
parser = HWIArgumentParser(description='Hardware Wallet Interface, version {}.\nAccess and send commands to a hardware wallet device. Responses are in JSON format.'.format(__version__))
137137
parser.add_argument('--device-path', '-d', help='Specify the device path of the device to connect to')
138138
parser.add_argument('--device-type', '-t', help='Specify the type of device that will be connected. If `--device-path` not given, the first device of this type enumerated is used.')
139-
parser.add_argument('--password', '-p', help='Device password if it has one (e.g. DigitalBitbox)', default='')
139+
parser.add_argument('--password', '-p', help='Device password if it has one (e.g. DigitalBitbox)')
140140
parser.add_argument('--stdinpass', help='Enter the device password on the command line', action='store_true')
141141
parser.add_argument('--chain', help='Select chain to work with', type=Chain.argparse, choices=list(Chain), default=Chain.MAIN) # type: ignore
142142
parser.add_argument('--debug', help='Print debug statements', action='store_true')

hwilib/commands.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171

7272

7373
# Get the client for the device
74-
def get_client(device_type: str, device_path: str, password: str = "", expert: bool = False, chain: Chain = Chain.MAIN) -> Optional[HardwareWalletClient]:
74+
def get_client(device_type: str, device_path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> Optional[HardwareWalletClient]:
7575
"""
7676
Returns a HardwareWalletClient for the given device type at the device path
7777
@@ -101,7 +101,7 @@ def get_client(device_type: str, device_path: str, password: str = "", expert: b
101101
return client
102102

103103
# Get a list of all available hardware wallets
104-
def enumerate(password: str = "") -> List[Dict[str, Any]]:
104+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
105105
"""
106106
Enumerate all of the devices that HWI can potentially access.
107107
@@ -124,7 +124,7 @@ def enumerate(password: str = "") -> List[Dict[str, Any]]:
124124

125125
# Fingerprint or device type required
126126
def find_device(
127-
password: str = "",
127+
password: Optional[str] = None,
128128
device_type: Optional[str] = None,
129129
fingerprint: Optional[str] = None,
130130
expert: bool = False,

hwilib/devices/bitbox02.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def _xpubs_equal_ignoring_version(xpub1: bytes, xpub2: bytes) -> bool:
174174
return xpub1[4:] == xpub2[4:]
175175

176176

177-
def enumerate(password: str = "") -> List[Dict[str, object]]:
177+
def enumerate(password: Optional[str] = None) -> List[Dict[str, object]]:
178178
"""
179179
Enumerate all BitBox02 devices. Bootloaders excluded.
180180
"""
@@ -259,15 +259,15 @@ def func(*args, **kwargs): # type: ignore
259259

260260
# This class extends the HardwareWalletClient for BitBox02 specific things
261261
class Bitbox02Client(HardwareWalletClient):
262-
def __init__(self, path: str, password: str = "", expert: bool = False, chain: Chain = Chain.MAIN) -> None:
262+
def __init__(self, path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> None:
263263
"""
264264
Initializes a new BitBox02 client instance.
265265
"""
266-
super().__init__(path, password=password, expert=expert, chain=chain)
267-
if password:
266+
if password is not None:
268267
raise BadArgumentError(
269268
"The BitBox02 does not accept a passphrase from the host. Please enable the passphrase option and enter the passphrase on the device during unlock."
270269
)
270+
super().__init__(path, password=password, expert=expert, chain=chain)
271271

272272
hid_device = hid.device()
273273
hid_device.open_path(path.encode())

hwilib/devices/coldcard.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
from typing import (
6868
Any,
6969
Callable,
70+
Optional,
7071
)
7172

7273
CC_SIMULATOR_SOCK = '/tmp/ckcc-simulator.sock'
@@ -89,7 +90,7 @@ def func(*args: Any, **kwargs: Any) -> Any:
8990
# This class extends the HardwareWalletClient for ColdCard specific things
9091
class ColdcardClient(HardwareWalletClient):
9192

92-
def __init__(self, path: str, password: str = "", expert: bool = False, chain: Chain = Chain.MAIN) -> None:
93+
def __init__(self, path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> None:
9394
super(ColdcardClient, self).__init__(path, password, expert, chain)
9495
# Simulator hard coded pipe socket
9596
if path == CC_SIMULATOR_SOCK:
@@ -398,7 +399,7 @@ def can_sign_taproot(self) -> bool:
398399
return False
399400

400401

401-
def enumerate(password: str = "") -> List[Dict[str, Any]]:
402+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
402403
results = []
403404
devices = hid.enumerate(COINKITE_VID, CKCC_PID)
404405
devices.append({'path': CC_SIMULATOR_SOCK.encode()})

hwilib/devices/digitalbitbox.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
Callable,
2323
Dict,
2424
List,
25+
Optional,
2526
Tuple,
2627
Union,
2728
)
@@ -345,17 +346,17 @@ def format_backup_filename(name: str) -> str:
345346
# This class extends the HardwareWalletClient for Digital Bitbox specific things
346347
class DigitalbitboxClient(HardwareWalletClient):
347348

348-
def __init__(self, path: str, password: str, expert: bool = False, chain: Chain = Chain.MAIN) -> None:
349+
def __init__(self, path: str, password: Optional[str], expert: bool = False, chain: Chain = Chain.MAIN) -> None:
349350
"""
350351
The `DigitalbitboxClient` is a `HardwareWalletClient` for interacting with BitBox01 devices (previously known as the Digital BitBox).
351352
352353
:param path: Path to the device as given by `enumerate`
353354
:param password: The password required to communicate with the device. Must be provided.
354355
:param expert: Whether to be in expert mode and return additional information.
355356
"""
356-
super(DigitalbitboxClient, self).__init__(path, password, expert, chain)
357-
if not password:
357+
if password is None:
358358
raise NoPasswordError('Password must be supplied for digital BitBox')
359+
super(DigitalbitboxClient, self).__init__(path, password, expert, chain)
359360
if path.startswith('udp:'):
360361
split_path = path.split(':')
361362
ip = split_path[1]
@@ -364,7 +365,7 @@ def __init__(self, path: str, password: str, expert: bool = False, chain: Chain
364365
else:
365366
self.device = hid.device()
366367
self.device.open_path(path.encode())
367-
self.password = password
368+
self.password: str = password
368369

369370
@digitalbitbox_exception
370371
def get_pubkey_at_path(self, path: str) -> ExtendedKey:
@@ -678,7 +679,7 @@ def can_sign_taproot(self) -> bool:
678679
return False
679680

680681

681-
def enumerate(password: str = "") -> List[Dict[str, Any]]:
682+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
682683
results = []
683684
devices = hid.enumerate(DBB_VENDOR_ID, DBB_DEVICE_ID)
684685
# Try connecting to simulator
@@ -707,7 +708,7 @@ def enumerate(password: str = "") -> List[Dict[str, Any]]:
707708
client = DigitalbitboxClient(path, password)
708709

709710
# Check initialized
710-
reply = send_encrypt('{"device" : "info"}', password, client.device)
711+
reply = send_encrypt('{"device" : "info"}', "" if password is None else password, client.device)
711712
if 'error' in reply and (reply['error']['code'] == 101 or reply['error']['code'] == '101'):
712713
d_data['error'] = 'Not initialized'
713714
d_data['code'] = DEVICE_NOT_INITIALIZED

hwilib/devices/jade.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def _get_multisig_name(type: str, threshold: int, signers: List[Tuple[bytes, Seq
125125
hash_summary = sha256(summary.encode()).hex()
126126
return 'hwi' + hash_summary[:12]
127127

128-
def __init__(self, path: str, password: str = '', expert: bool = False, chain: Chain = Chain.MAIN, timeout: Optional[int] = None) -> None:
128+
def __init__(self, path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN, timeout: Optional[int] = None) -> None:
129129
super(JadeClient, self).__init__(path, password, expert, chain)
130130
self.jade = JadeAPI.create_serial(path, timeout=timeout)
131131
self.jade.connect()
@@ -508,7 +508,7 @@ def can_sign_taproot(self) -> bool:
508508
return False
509509

510510

511-
def enumerate(password: str = '') -> List[Dict[str, Any]]:
511+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
512512
results = []
513513

514514
def _get_device_entry(device_model: str, device_path: str) -> Dict[str, Any]:

hwilib/devices/keepkey.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def __init__(
141141

142142

143143
class KeepkeyClient(TrezorClient):
144-
def __init__(self, path: str, password: str = "", expert: bool = False, chain: Chain = Chain.MAIN) -> None:
144+
def __init__(self, path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> None:
145145
"""
146146
The `KeepkeyClient` is a `HardwareWalletClient` for interacting with the Keepkey.
147147
@@ -171,7 +171,7 @@ def can_sign_taproot(self) -> bool:
171171
return False
172172

173173

174-
def enumerate(password: str = "") -> List[Dict[str, Any]]:
174+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
175175
results = []
176176
devs = hid.HidTransport.enumerate(usb_ids=KEEPKEY_HID_IDS)
177177
devs.extend(webusb.WebUsbTransport.enumerate(usb_ids=KEEPKEY_WEBUSB_IDS))
@@ -202,7 +202,7 @@ def enumerate(password: str = "") -> List[Dict[str, Any]]:
202202
d_data['needs_passphrase_sent'] = client.client.features.passphrase_protection # always need the passphrase sent for Keepkey if it has passphrase protection enabled
203203
if d_data['needs_pin_sent']:
204204
raise DeviceNotReadyError('Keepkey is locked. Unlock by using \'promptpin\' and then \'sendpin\'.')
205-
if d_data['needs_passphrase_sent'] and not password:
205+
if d_data['needs_passphrase_sent'] and password is None:
206206
raise DeviceNotReadyError("Passphrase needs to be specified before the fingerprint information can be retrieved")
207207
if client.client.features.initialized:
208208
d_data['fingerprint'] = client.get_master_fingerprint().hex()

hwilib/devices/ledger.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def func(*args: Any, **kwargs: Any) -> Any:
147147
# This class extends the HardwareWalletClient for Ledger Nano S and Nano X specific things
148148
class LedgerClient(HardwareWalletClient):
149149

150-
def __init__(self, path: str, password: str = "", expert: bool = False, chain: Chain = Chain.MAIN) -> None:
150+
def __init__(self, path: str, password: Optional[str] = None, expert: bool = False, chain: Chain = Chain.MAIN) -> None:
151151
super(LedgerClient, self).__init__(path, password, expert, chain)
152152

153153
is_debug = logging.getLogger().getEffectiveLevel() == logging.DEBUG
@@ -560,7 +560,7 @@ def can_sign_taproot(self) -> bool:
560560
return isinstance(self.client, NewClient)
561561

562562

563-
def enumerate(password: str = '') -> List[Dict[str, Any]]:
563+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
564564
results = []
565565
devices = []
566566
devices.extend(hid.enumerate(LEDGER_VENDOR_ID, 0))

hwilib/devices/trezor.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ class TrezorClient(HardwareWalletClient):
281281
def __init__(
282282
self,
283283
path: str,
284-
password: str = "",
284+
password: Optional[str] = None,
285285
expert: bool = False,
286286
chain: Chain = Chain.MAIN,
287287
hid_ids: Set[Tuple[int, int]] = HID_IDS,
@@ -326,6 +326,8 @@ def _check_unlocked(self) -> None:
326326
self.client.ui.disallow_passphrase()
327327
if self.client.features.pin_protection and not self.client.features.unlocked:
328328
raise DeviceNotReadyError('{} is locked. Unlock by using \'promptpin\' and then \'sendpin\'.'.format(self.type))
329+
if self.client.features.passphrase_protection and self.password is None:
330+
raise NoPasswordError("Passphrase protection is enabled, passphrase must be provided")
329331

330332
def _supports_external(self) -> bool:
331333
if self.client.features.model == "1" and self.client.version <= (1, 10, 5):
@@ -843,7 +845,7 @@ def can_sign_taproot(self) -> bool:
843845
return bool(self.client.version >= (1, 10, 4))
844846

845847

846-
def enumerate(password: str = "") -> List[Dict[str, Any]]:
848+
def enumerate(password: Optional[str] = None) -> List[Dict[str, Any]]:
847849
results = []
848850
devs = hid.HidTransport.enumerate()
849851
devs.extend(webusb.WebUsbTransport.enumerate())
@@ -876,7 +878,7 @@ def enumerate(password: str = "") -> List[Dict[str, Any]]:
876878
d_data['needs_passphrase_sent'] = False
877879
if d_data['needs_pin_sent']:
878880
raise DeviceNotReadyError('Trezor is locked. Unlock by using \'promptpin\' and then \'sendpin\'.')
879-
if d_data['needs_passphrase_sent'] and not password:
881+
if d_data['needs_passphrase_sent'] and password is None:
880882
raise DeviceNotReadyError("Passphrase needs to be specified before the fingerprint information can be retrieved")
881883
if client.client.features.initialized:
882884
d_data['fingerprint'] = client.get_master_fingerprint().hex()

hwilib/hwwclient.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class HardwareWalletClient(object):
2727
that hardware wallet subclasses should implement.
2828
"""
2929

30-
def __init__(self, path: str, password: str, expert: bool, chain: Chain = Chain.MAIN) -> None:
30+
def __init__(self, path: str, password: Optional[str], expert: bool, chain: Chain = Chain.MAIN) -> None:
3131
"""
3232
:param path: Path to the device as returned by :func:`~hwilib.commands.enumerate`
3333
:param password: A password/passphrase to use with the device.

0 commit comments

Comments
 (0)