From 0f2bbdca3a444bc4b559a9a452dd66e0cc79ffa6 Mon Sep 17 00:00:00 2001 From: "Jamie C. Driver" Date: Tue, 24 Oct 2023 17:00:26 +0100 Subject: [PATCH] jade: update Jade api to 1.0.24 This addresses: - update cbor dependency - avoids deprecated logging.warn() function (thanks fametrano) - proper nesting of loggers (thanks fametrano) - new api calls to access new Jade functionality - first step to using Jade's 'sign_psbt()' functionality (fw 0.1.47+) --- hwilib/devices/jadepy/jade.py | 366 ++++++++++++++++++++++----- hwilib/devices/jadepy/jade_serial.py | 18 +- hwilib/devices/jadepy/jade_tcp.py | 5 +- poetry.lock | 51 +++- pyproject.toml | 2 +- setup.py | 2 +- test/test_jade.py | 2 +- 7 files changed, 375 insertions(+), 71 deletions(-) diff --git a/hwilib/devices/jadepy/jade.py b/hwilib/devices/jadepy/jade.py index 3ea523c35..b21ee4c1e 100644 --- a/hwilib/devices/jadepy/jade.py +++ b/hwilib/devices/jadepy/jade.py @@ -1,4 +1,4 @@ -import cbor +import cbor2 as cbor import hashlib import json import time @@ -20,9 +20,7 @@ logger = logging.getLogger(__name__) device_logger = logging.getLogger(f'{__name__}-device') - # Default serial connection -DEFAULT_SERIAL_DEVICE = '/dev/ttyUSB0' DEFAULT_BAUD_RATE = 115200 DEFAULT_SERIAL_TIMEOUT = 120 @@ -84,21 +82,29 @@ def _http_request(params): # Use the first non-onion url url = [url for url in params['urls'] if not url.endswith('.onion')][0] + if params['method'] == 'GET': assert 'data' not in params, 'Cannot pass body to requests.get' - f = requests.get(url) + def http_call_fn(): return requests.get(url) elif params['method'] == 'POST': data = json.dumps(params['data']) - f = requests.post(url, data) + def http_call_fn(): return requests.post(url, data) + else: + raise JadeError(1, "Only GET and POST methods supported", params['method']) - logger.debug("http_request received reply: {}".format(f.text)) + try: + f = http_call_fn() + logger.debug("http_request received reply: {}".format(f.text)) - if f.status_code != 200: - logger.error("http error {} : {}".format(f.status_code, f.text)) - raise ValueError(f.status_code) + if f.status_code != 200: + logger.error("http error {} : {}".format(f.status_code, f.text)) + raise ValueError(f.status_code) - assert params['accept'] == 'json' - f = f.json() + assert params['accept'] == 'json' + f = f.json() + except Exception as e: + logging.error(e) + f = None return {'body': f} @@ -330,16 +336,41 @@ def _jadeRpc(self, method, params=None, inputid=None, http_request_fn=None, long return result - def get_version_info(self): + def ping(self): + """ + RPC call to test the connection to Jade and that Jade is powered on and receiving data, and + return whether the main task is currently handling a message, handling user menu navigation + or is idle. + + NOTE: unlike all other calls this is not queued and handled in fifo order - this message is + handled immediately and the response sent as quickly as possible. This call does not block. + If this call is made in parallel with Jade processing other messages, the replies may be + out of order (although the message 'id' should still be correct). Use with caution. + + Returns + ------- + 0 if the main task is currently idle + 1 if the main task is handling a client message + 2 if the main task is handling user ui menu navigation + """ + return self._jadeRpc('ping') + + def get_version_info(self, nonblocking=False): """ RPC call to fetch summary details pertaining to the hardware unit and running firmware. + Parameters + ---------- + nonblocking : bool + If True message will be handled immediately (see also ping()) *experimental feature* + Returns ------- dict Contains keys for various info describing the hw and running fw """ - return self._jadeRpc('get_version_info') + params = {'nonblocking': True} if nonblocking else None + return self._jadeRpc('get_version_info', params) def add_entropy(self, entropy): """ @@ -377,7 +408,20 @@ def set_epoch(self, epoch=None): params = {'epoch': epoch if epoch is not None else int(time.time())} return self._jadeRpc('set_epoch', params) - def ota_update(self, fwcmp, fwlen, chunksize, patchlen=None, cb=None): + def logout(self): + """ + RPC call to logout of any wallet loaded on the Jade unit. + Any key material is freed and zero'd. + Call always returns true. + + Returns + ------- + bool + True + """ + return self._jadeRpc('logout') + + def ota_update(self, fwcmp, fwlen, chunksize, fwhash=None, patchlen=None, cb=None): """ RPC call to attempt to update the unit's firmware. @@ -393,6 +437,12 @@ def ota_update(self, fwcmp, fwlen, chunksize, patchlen=None, cb=None): and ack'd by the hw unit. The maximum supported chunk size is given in the version info data, under the key 'JADE_OTA_MAX_CHUNK'. + fwhash: 32-bytes, optional + The sha256 hash of the full uncompressed final firmware image. In the case of a full + firmware upload this should be the hash of the uncompressed file. In the case of a + delta update this is the hash of the expected final image - ie. the existing firmware + with the uploaded delta applied. ie. it is a verification of the fw image Jade will try + to boot. Optional for backward-compatibility - may become mandatory in a future release. patchlen: int, optional If the compressed firmware bytes are an incremental diff to be applied to the running firmware image, this is the size of that patch when uncompressed. @@ -424,6 +474,9 @@ def ota_update(self, fwcmp, fwlen, chunksize, patchlen=None, cb=None): 'cmpsize': cmplen, 'cmphash': cmphash} + if fwhash is not None: + params['fwhash'] = fwhash + if patchlen is not None: ota_method = 'ota_delta' params['patchsize'] = patchlen @@ -454,8 +507,9 @@ def run_remote_selfcheck(self): Returns ------- - bool - True on success. + int + Time in ms for the internal tests to run, as measured on the hw. + ie. excluding any messaging overhead """ return self._jadeRpc('debug_selfcheck', long_timeout=True) @@ -560,6 +614,38 @@ def set_seed(self, seed): params = {'seed': seed} return self._jadeRpc('debug_set_mnemonic', params) + def get_bip85_bip39_entropy(self, num_words, index, pubkey): + """ + RPC call to fetch encrypted bip85-bip39 entropy. + NOTE: Only available in a DEBUG build of the firmware. + + Parameters + ---------- + num_words : int + The number of words the entropy is required to produce. + + index : int + The index to use in the bip32 path to calcuate the entropy. + + pubkey: 33-bytes + The host ephemeral pubkey to use to generate a shared ecdh secret to use as an AES key + to encrypt the returned entropy. + + Returns + ------- + dict + pubkey - 33-bytes, Jade's ephemeral pubkey used to generate a shared ecdh secret used as + an AES key to encrypt the returned entropy + encrypted - bytes, the requested bip85 bip39 entropy, AES encrypted with the first key + derived from the ecdh shared secret, prefixed with the iv + hmac - 32-bytes, the hmac of the encrypted buffer, using the second key derived from the + ecdh shared secret + """ + params = {'num_words': num_words, + 'index': index, + 'pubkey': pubkey} + return self._jadeRpc('get_bip85_bip39_entropy', params) + def set_pinserver(self, urlA=None, urlB=None, pubkey=None, cert=None): """ RPC call to explicitly set (override) the details of the blind pinserver used to @@ -779,8 +865,59 @@ def register_multisig(self, network, multisig_name, variant, sorted_keys, thresh 'master_blinding_key': master_blinding_key}} return self._jadeRpc('register_multisig', params) + def register_multisig_file(self, multisig_file): + """ + RPC call to register a new multisig wallet, which must contain the hw signer. + A registration file is provided - as produced my several wallet apps. + + Parameters + ---------- + multisig_file : string + The multisig file as produced by several wallet apps. + eg: + Name: MainWallet + Policy: 2 of 3 + Format: P2WSH + Derivation: m/48'/0'/0'/2' + + B237FE9D: xpub6E8C7BX4c7qfTsX7urnXggcAyFuhDmYLQhwRwZGLD9maUGWPinuc9k96ejhEQ1DCk... + 249192D2: xpub6EbXynW6xjYR3crcztum6KzSWqDJoAJQoovwamwVnLaCSHA6syXKPnJo6U3bVeGde... + 67F90FFC: xpub6EHuWWrYd8bp5FS1XAZsMPkmCqLSjpULmygWqAqWRCCjSWQwz6ntq5KnuQnL23No2... + + Returns + ------- + bool + True on success, implying the mutisig wallet can now be used. + """ + params = {'multisig_file': multisig_file} + return self._jadeRpc('register_multisig', params) + + def register_descriptor(self, network, descriptor_name, descriptor_script, datavalues=None): + """ + RPC call to register a new descriptor wallet, which must contain the hw signer. + A registration name is provided - if it already exists that record is overwritten. + + Parameters + ---------- + network : string + Network to which the multisig should apply - eg. 'mainnet', 'liquid', 'testnet', etc. + + descriptor_name : string + Name to use to identify this descriptor wallet registration record. + If a registration record exists with the name given, that record is overwritten. + + Returns + ------- + bool + True on success, implying the descriptor wallet can now be used. + """ + params = {'network': network, 'descriptor_name': descriptor_name, + 'descriptor': descriptor_script, 'datavalues': datavalues} + return self._jadeRpc('register_descriptor', params) + def get_receive_address(self, *args, recovery_xpub=None, csv_blocks=0, - variant=None, multisig_name=None, confidential=None): + variant=None, multisig_name=None, descriptor_name=None, + confidential=None): """ RPC call to generate, show, and return an address for the given path. The call has three forms. @@ -826,6 +963,16 @@ def get_receive_address(self, *args, recovery_xpub=None, csv_blocks=0, multisig_name : str The name of the registered multisig wallet record used to generate the address. + 4. Descriptor wallet addresses + branch : int + Multi-path derivation branch, usually 0. + + pointer : int + Path index to descriptor + + descriptor_name : str + The name of the registered descriptor wallet record used to generate the address. + Returns ------- str @@ -836,6 +983,10 @@ def get_receive_address(self, *args, recovery_xpub=None, csv_blocks=0, assert len(args) == 2 keys = ['network', 'paths', 'multisig_name'] args += (multisig_name,) + elif descriptor_name is not None: + assert len(args) == 3 + keys = ['network', 'branch', 'pointer', 'descriptor_name'] + args += (descriptor_name,) elif variant is not None: assert len(args) == 2 keys = ['network', 'path', 'variant'] @@ -896,6 +1047,26 @@ def sign_message(self, path, message, use_ae_signatures=False, params = {'path': path, 'message': message} return self._jadeRpc('sign_message', params) + def sign_message_file(self, message_file): + """ + RPC call to format and sign the given message, using the given bip32 path. + A message file is provided - as produced by eg. Specter wallet. + Supports RFC6979 only. + + Parameters + ---------- + message_file : str + Message file to parse and produce signature for. + eg: 'signmessage m/84h/0h/0h/0/0 ascii:this is a test message' + + Returns + ------- + str + base64-encoded RFC6979 signature + """ + params = {'message_file': message_file} + return self._jadeRpc('sign_message', params) + def get_identity_pubkey(self, identity, curve, key_type, index=0): """ RPC call to fetch a pubkey for the given identity (slip13/slip17). @@ -1065,26 +1236,22 @@ def get_shared_nonce(self, script, their_pubkey, include_pubkey=False, multisig_ def get_blinding_factor(self, hash_prevouts, output_index, bftype, multisig_name=None): """ - RPC call to get a deterministic "trusted" blinding factor to blind an output. - Normally the blinding factors are generated and returned in the `get_commitments` call, - but for the last output the vbf must be generated on the host, so this call allows the - host to get a valid abf to compute the generator and then the "final" vbf. - Nonetheless, this call is kept generic, and can also generate vbfs, hence the "bftype" - parameter. + RPC call to get deterministic blinding factors to blind an output. + Predicated on the host calculating the 'hash_prevouts' value correctly. + Can fetch abf, vbf, or both together. Parameters ---------- hash_prevouts : 32-bytes - This value is computed as specified in bip143. - It is verified immediately since at this point Jade doesn't have the tx in question. - It will be checked later during `sign_liquid_tx()`. + This value should be computed by the host as specified in bip143. + It is not verified by Jade, since at this point Jade does not have the tx in question. output_index : int The index of the output we are trying to blind bftype : str - Can be eitehr "ASSET" or "VALUE", to generate abfs or vbfs. + Can be "ASSET", "VALUE", or "ASSET_AND_VALUE", to generate abf, vbf, or both. multisig_name : str, optional The name of any registered multisig wallet for which to fetch the blinding factor. @@ -1092,8 +1259,9 @@ def get_blinding_factor(self, hash_prevouts, output_index, bftype, multisig_name Returns ------- - 32-bytes - The requested blinding factor + 32-bytes or 64-bytes + The blinding factor for "ASSET" and "VALUE" requests, or both concatenated abf|vbf + ie. the first 32 bytes being abf, the second 32 bytes being vbf. """ params = {'hash_prevouts': hash_prevouts, 'output_index': output_index, @@ -1140,7 +1308,7 @@ def get_commitments(self, Returns ------- dict - Containing the following the blinding factors and output commitments. + Containing the blinding factors and output commitments. """ params = {'asset_id': asset_id, 'value': value, @@ -1192,7 +1360,7 @@ def _send_tx_inputs(self, base_id, inputs, use_ae_signatures): host_ae_entropy_values = [] for txinput in inputs: # ae-protocol - do not send the host entropy immediately - txinput = txinput.copy() # shallow copy + txinput = txinput.copy() if txinput else {} # shallow copy host_ae_entropy_values.append(txinput.pop('ae_host_entropy', None)) base_id += 1 @@ -1224,6 +1392,9 @@ def _send_tx_inputs(self, base_id, inputs, use_ae_signatures): # Send all n inputs requests = [] for txinput in inputs: + if txinput is None: + txinput = {} + base_id += 1 msg_id = str(base_id) request = self.jade.build_request(msg_id, 'tx_input', txinput) @@ -1243,31 +1414,44 @@ def _send_tx_inputs(self, base_id, inputs, use_ae_signatures): return signatures def sign_liquid_tx(self, network, txn, inputs, commitments, change, use_ae_signatures=False, - asset_info=None): + asset_info=None, additional_info=None): """ RPC call to sign a liquid transaction. Parameters ---------- network : str - Network to which the address should apply - eg. 'liquid', 'liquid-testnet', etc. + Network to which the txn should apply - eg. 'liquid', 'liquid-testnet', etc. txn : bytes The transaction to sign inputs : [dict] - The tx inputs. Should contain keys: + The tx inputs. + If signing this input, should contain keys: is_witness, bool - whether this is a segwit input - value_commitment, 33-bytes - The value commitment of ths input - - These are only required if signing this input: script, bytes- the redeem script path, [int] - the bip32 path to sign with + value_commitment, 33-bytes - The value commitment of ths input + + This is optional if signing this input: + sighash, int - The sighash to use, defaults to 0x01 (SIGHASH_ALL) These are only required for Anti-Exfil signatures: ae_host_commitment, 32-bytes - The host-commitment for Anti-Exfil signatures ae_host_entropy, 32-bytes - The host-entropy for Anti-Exfil signatures + These are only required for advanced transactions, eg. swaps, and only when the + inputs need unblinding. + Not needed for vanilla send-payment/redeposit etc: + abf, 32-bytes - asset blinding factor + asset_id, 32-bytes - the unblinded asset-id + asset_generator, 33-bytes - the (blinded) asset-generator + vbf, 32-bytes - the value blinding factor + value, int - the unblinded sats value of the input + + If not signing this input a null or an empty dict can be passed. + commitments : [dict] An array sized for the number of outputs. Unblinded outputs should have a 'null' placeholder element. @@ -1277,16 +1461,18 @@ def sign_liquid_tx(self, network, txn, inputs, commitments, change, use_ae_signa change : [dict] An array sized for the number of outputs. - Outputs which are not change should have a 'null' placeholder element. - Change elements with data will be automatically verified by Jade, and not by the user. - Populated elements should contain sufficient data to generate the change address. + Outputs which are not to this wallet should have a 'null' placeholder element. + The output scripts for the elements with data will be verified by Jade. + Unless the element also contains 'is_change': False, these outputs will automatically + be approved and not be verified by the user. + Populated elements should contain sufficient data to generate the wallet address. See `get_receive_address()` use_ae_signatures : bool, optional Whether to use the anti-exfil protocol to generate the signatures. Defaults to False. - asset_info : [dict] + asset_info : [dict], optional Any asset-registry data relevant to the assets being transacted, such that Jade can display a meaningful name, issuer, ticker etc. rather than just asset-id. At the very least must contain 'asset_id', 'contract' and 'issuance_prevout' items, @@ -1294,6 +1480,17 @@ def sign_liquid_tx(self, network, txn, inputs, commitments, change, use_ae_signa not required. Defaults to None. + additional_info: dict, optional + Extra data about the transaction. Only required for advanced transactions, eg. swaps. + Not needed for vanilla send-payment/redeposit etc: + tx_type, str: 'swap' indicates the tx represents an asset-swap proposal or transaction. + wallet_input_summary, dict: a list of entries containing 'asset_id' (32-bytes) and + 'satoshi' (int) showing net movement of assets out of the wallet (ie. sum of wallet + inputs per asset, minus any change outputs). + wallet_output_summary, dict: a list of entries containing 'asset_id' (32-bytes) and + 'satoshi' (int) showing net movement of assets into the wallet (ie. sum of wallet + outputs per asset, excluding any change outputs). + Returns ------- 1. if use_ae_signatures is False @@ -1317,7 +1514,8 @@ def sign_liquid_tx(self, network, txn, inputs, commitments, change, use_ae_signa 'trusted_commitments': commitments, 'use_ae_signatures': use_ae_signatures, 'change': change, - 'asset_info': asset_info} + 'asset_info': asset_info, + 'additional_info': additional_info} reply = self._jadeRpc('sign_liquid_tx', params, str(base_id)) assert reply @@ -1332,23 +1530,25 @@ def sign_tx(self, network, txn, inputs, change, use_ae_signatures=False): Parameters ---------- network : str - Network to which the address should apply - eg. 'mainnet', 'testnet', etc. + Network to which the txn should apply - eg. 'mainnet', 'testnet', etc. txn : bytes The transaction to sign inputs : [dict] The tx inputs. Should contain keys: - is_witness, bool - whether this is a segwit input + One of these is required: + input_tx, bytes - The prior transaction which created the utxo of this input + satoshi, int - The satoshi amount of this input - can be used in place of + 'input_tx' for a tx with a single segwit input These are only required if signing this input: + is_witness, bool - whether this is a segwit input script, bytes- the redeem script path, [int] - the bip32 path to sign with - One of these is required: - input_tx, bytes - The prior transaction which created the utxo of this input - satoshi, int - The satoshi amount of this input - can be used in place of - 'input_tx' for a tx with a single segwit input + This is optional if signing this input: + sighash, int - The sighash to use, defaults to 0x01 (SIGHASH_ALL) These are only required for Anti-Exfil signatures: ae_host_commitment, 32-bytes - The host-commitment for Anti-Exfil signatures @@ -1356,9 +1556,11 @@ def sign_tx(self, network, txn, inputs, change, use_ae_signatures=False): change : [dict] An array sized for the number of outputs. - Outputs which are not change should have a 'null' placeholder element. - Change elements with data will be automatically verified by Jade, and not by the user. - Populated elements should contain sufficient data to generate the change address. + Outputs which are not to this wallet should have a 'null' placeholder element. + The output scripts for the elements with data will be verified by Jade. + Unless the element also contains 'is_change': False, these outputs will automatically + be approved and not be verified by the user. + Populated elements should contain sufficient data to generate the wallet address. See `get_receive_address()` use_ae_signatures : bool @@ -1393,6 +1595,50 @@ def sign_tx(self, network, txn, inputs, change, use_ae_signatures=False): # Send inputs and receive signatures return self._send_tx_inputs(base_id, inputs, use_ae_signatures) + def sign_psbt(self, network, psbt): + """ + RPC call to sign a passed psbt as required + + Parameters + ---------- + network : str + Network to which the txn should apply - eg. 'mainnet', 'testnet', etc. + + psbt : bytes + The psbt formatted as bytes + + Returns + ------- + bytes + The psbt, updated with any signatures required from the hw signer + """ + # Send PSBT message + params = {'network': network, 'psbt': psbt} + msgid = str(random.randint(100000, 999999)) + request = self.jade.build_request(msgid, 'sign_psbt', params) + self.jade.write_request(request) + + # Read replies until we have them all, collate data and return. + # NOTE: we send 'get_extended_data' messages to request more 'chunks' of the reply data. + psbt_out = bytearray() + while True: + reply = self.jade.read_response() + self.jade.validate_reply(request, reply) + psbt_out.extend(self._get_result_or_raise_error(reply)) + + if 'seqnum' not in reply or reply['seqnum'] == reply['seqlen']: + break + + newid = str(random.randint(100000, 999999)) + params = {'origid': msgid, + 'orig': 'sign_psbt', + 'seqnum': reply['seqnum'] + 1, + 'seqlen': reply['seqlen']} + request = self.jade.build_request(newid, 'get_extended_data', params) + self.jade.write_request(request) + + return psbt_out + class JadeInterface: """ @@ -1460,7 +1706,7 @@ def create_serial(device=None, baud=None, timeout=None): if device and JadeTCPImpl.isSupportedDevice(device): impl = JadeTCPImpl(device, timeout or DEFAULT_SERIAL_TIMEOUT) else: - impl = JadeSerialImpl(device or DEFAULT_SERIAL_DEVICE, + impl = JadeSerialImpl(device, baud or DEFAULT_BAUD_RATE, timeout or DEFAULT_SERIAL_TIMEOUT) return JadeInterface(impl) @@ -1541,7 +1787,7 @@ def drain(self): Log any/all outstanding messages/data. NOTE: can run indefinitely if data is arriving constantly. """ - logger.warn("Draining interface...") + logger.warning("Draining interface...") drained = bytearray() finished = False @@ -1552,14 +1798,14 @@ def drain(self): if finished or byte_ == b'\n' or len(drained) > 256: try: - device_logger.warn(drained.decode('utf-8')) + device_logger.warning(drained.decode('utf-8')) except Exception as e: # Dump the bytes raw and as hex if decoding as utf-8 failed - device_logger.warn("Raw:") - device_logger.warn(drained) - device_logger.warn("----") - device_logger.warn("Hex dump:") - device_logger.warn(drained.hex()) + device_logger.warning("Raw:") + device_logger.warning(drained) + device_logger.warning("----") + device_logger.warning("Hex dump:") + device_logger.warning(drained.hex()) # Clear and loop to continue collecting drained.clear() @@ -1693,7 +1939,7 @@ def read_cbor_message(self): response = message['log'].decode("utf-8") log_methods = { 'E': device_logger.error, - 'W': device_logger.warn, + 'W': device_logger.warning, 'I': device_logger.info, 'D': device_logger.debug, 'V': device_logger.debug, diff --git a/hwilib/devices/jadepy/jade_serial.py b/hwilib/devices/jadepy/jade_serial.py index 615ea0275..ac08119d0 100644 --- a/hwilib/devices/jadepy/jade_serial.py +++ b/hwilib/devices/jadepy/jade_serial.py @@ -1,6 +1,7 @@ import serial import logging +from serial.tools import list_ports logger = logging.getLogger(__name__) @@ -19,8 +20,23 @@ # (caveat cranium) # class JadeSerialImpl: + # Used when searching for devices that might be a Jade/compatible hw + JADE_DEVICE_IDS = [(0x10c4, 0xea60), (0x1a86, 0x55d4), (0x0403, 0x6001), (0x1a86, 0x7523)] + + @classmethod + def _get_first_compatible_device(cls): + jades = [] + for devinfo in list_ports.comports(): + if (devinfo.vid, devinfo.pid) in cls.JADE_DEVICE_IDS: + jades.append(devinfo.device) + + if len(jades) > 1: + logger.warning(f'Multiple potential jade devices detected: {jades}') + + return jades[0] if jades else None + def __init__(self, device, baud, timeout): - self.device = device + self.device = device or self._get_first_compatible_device() self.baud = baud self.timeout = timeout self.ser = None diff --git a/hwilib/devices/jadepy/jade_tcp.py b/hwilib/devices/jadepy/jade_tcp.py index 84d9cc82a..6d7799ad6 100644 --- a/hwilib/devices/jadepy/jade_tcp.py +++ b/hwilib/devices/jadepy/jade_tcp.py @@ -59,4 +59,7 @@ def write(self, bytes_): def read(self, n): assert self.tcp_sock is not None - return self.tcp_sock.recv(n) + buf = self.tcp_sock.recv(n) + while len(buf) < n: + buf += self.tcp_sock.recv(n - len(buf)) + return buf diff --git a/poetry.lock b/poetry.lock index bf4279b0b..e9408667b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -52,15 +52,54 @@ files = [ pytz = ">=2015.7" [[package]] -name = "cbor" -version = "1.0.0" -description = "RFC 7049 - Concise Binary Object Representation" +name = "cbor2" +version = "5.4.6" +description = "CBOR (de)serializer with extensive tag support" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "cbor-1.0.0.tar.gz", hash = "sha256:13225a262ddf5615cbd9fd55a76a0d53069d18b07d2e9f19c39e6acb8609bbb6"}, + {file = "cbor2-5.4.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:309fffbb7f561d67f02095d4b9657b73c9220558701c997e9bfcfbca2696e927"}, + {file = "cbor2-5.4.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ff95b33e5482313a74648ca3620c9328e9f30ecfa034df040b828e476597d352"}, + {file = "cbor2-5.4.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9eb582fce972f0fa429d8159b7891ff8deccb7affc4995090afc61ce0d328a"}, + {file = "cbor2-5.4.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3950be57a1698086cf26d8710b4e5a637b65133c5b1f9eec23967d4089d8cfed"}, + {file = "cbor2-5.4.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:78304df140b9e13b93bcbb2aecee64c9aaa9f1cadbd45f043b5e7b93cc2f21a2"}, + {file = "cbor2-5.4.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e73ca40dd3c7210ff776acff9869ddc9ff67bae7c425b58e5715dcf55275163f"}, + {file = "cbor2-5.4.6-cp310-cp310-win_amd64.whl", hash = "sha256:0b956f19e93ba3180c336282cd1b6665631f2d3a196a9c19b29a833bf979e7a4"}, + {file = "cbor2-5.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1c12c0ab78f5bc290b08a79152a8621822415836a86f8f4b50dadba371736fda"}, + {file = "cbor2-5.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3545b16f9f0d5f34d4c99052829c3726020a07be34c99c250d0df87418f02954"}, + {file = "cbor2-5.4.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24144822f8d2b0156f4cda9427f071f969c18683ffed39663dc86bc0a75ae4dd"}, + {file = "cbor2-5.4.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1835536e76ea16e88c934aac5e369ba9f93d495b01e5fa2d93f0b4986b89146d"}, + {file = "cbor2-5.4.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:39452c799453f5bf33281ffc0752c620b8bfa0b7c13070b87d370257a1311976"}, + {file = "cbor2-5.4.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3316f09a77af85e7772ecfdd693b0f450678a60b1aee641bac319289757e3fa0"}, + {file = "cbor2-5.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:456cdff668a50a52fdb8aa6d0742511e43ed46d6a5b463dba80a5a720fa0d320"}, + {file = "cbor2-5.4.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9394ca49ecdf0957924e45d09a4026482d184a465a047f60c4044eb464c43de9"}, + {file = "cbor2-5.4.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56dfa030cd3d67e5b6701d3067923f2f61536a8ffb1b45be14775d1e866b59ae"}, + {file = "cbor2-5.4.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5094562dfe3e5583202b93ef7ca5082c2ba5571accb2c4412d27b7d0ba8a563"}, + {file = "cbor2-5.4.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:94f844d0e232aca061a86dd6ff191e47ba0389ddd34acb784ad9a41594dc99a4"}, + {file = "cbor2-5.4.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7bbd3470eb685325398023e335be896b74f61b014896604ed45049a7b7b6d8ac"}, + {file = "cbor2-5.4.6-cp37-cp37m-win_amd64.whl", hash = "sha256:0bd12c54a48949d11f5ffc2fa27f5df1b4754111f5207453e5fae3512ebb3cab"}, + {file = "cbor2-5.4.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d2984a488f350aee1d54fa9cb8c6a3c1f1f5b268abbc91161e47185de4d829f3"}, + {file = "cbor2-5.4.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c285a2cb2c04004bfead93df89d92a0cef1874ad337d0cb5ea53c2c31e97bfdb"}, + {file = "cbor2-5.4.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6709d97695205cd08255363b54afa035306d5302b7b5e38308c8ff5a47e60f2a"}, + {file = "cbor2-5.4.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96087fa5336ebfc94465c0768cd5de0fcf9af3840d2cf0ce32f5767855f1a293"}, + {file = "cbor2-5.4.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0d2b926b024d3a1549b819bc82fdc387062bbd977b0299dd5fa5e0ea3267b98b"}, + {file = "cbor2-5.4.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6e1b5aee920b6a2f737aa12e2b54de3826b09f885a7ce402db84216343368140"}, + {file = "cbor2-5.4.6-cp38-cp38-win_amd64.whl", hash = "sha256:79e048e623846d60d735bb350263e8fdd36cb6195d7f1a2b57eacd573d9c0b33"}, + {file = "cbor2-5.4.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:80ac8ba450c7a41c5afe5f7e503d3092442ed75393e1de162b0bf0d97edf7c7f"}, + {file = "cbor2-5.4.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4ce1a2c272ba8523a55ea2f1d66e3464e89fa0e37c9a3d786a919fe64e68dbd7"}, + {file = "cbor2-5.4.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1618d16e310f7ffed141762b0ff5d8bb6b53ad449406115cc465bf04213cefcf"}, + {file = "cbor2-5.4.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4bbbdb2e3ef274865dc3f279aae109b5d94f4654aea3c72c479fb37e4a1e7ed7"}, + {file = "cbor2-5.4.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6f9c702bee2954fffdfa3de95a5af1a6b1c5f155e39490353d5654d83bb05bb9"}, + {file = "cbor2-5.4.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4b9f3924da0e460a93b3674c7e71020dd6c9e9f17400a34e52a88c0af2dcd2aa"}, + {file = "cbor2-5.4.6-cp39-cp39-win_amd64.whl", hash = "sha256:d54bd840b4fe34f097b8665fc0692c7dd175349e53976be6c5de4433b970daa4"}, + {file = "cbor2-5.4.6-py3-none-any.whl", hash = "sha256:181ac494091d1f9c5bb373cd85514ce1eb967a8cf3ec298e8dfa8878aa823956"}, + {file = "cbor2-5.4.6.tar.gz", hash = "sha256:b893500db0fe033e570c3adc956af6eefc57e280026bd2d86fd53da9f1e594d7"}, ] +[package.extras] +doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["pytest", "pytest-cov"] + [[package]] name = "certifi" version = "2022.12.7" @@ -1203,4 +1242,4 @@ qt = ["pyside2"] [metadata] lock-version = "2.0" python-versions = "^3.7,<3.12" -content-hash = "fb58d9f81e83da6ac11708f02d1d0503daef1c29dcc5e77b1997868a221cb574" +content-hash = "e678b0f47446a616b50acd4ffbce3bb51cc70895e4d31322d566c334ce571f07" diff --git a/pyproject.toml b/pyproject.toml index a4d92d52f..0ada7839c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ mnemonic = "~0" typing-extensions = "^4.4" libusb1 = ">=1.7,<4" pyside2 = { version = "^5.14.0", optional = true, python = "<3.10" } -cbor = "^1.0.0" +cbor2 = "^5.4.6" pyserial = "^3.5" dataclasses = {version = "^0.8", python = ">=3.6,<3.7"} semver = "^3.0.1" diff --git a/setup.py b/setup.py index df95686d8..7f1cd5782 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ modules = \ ['hwi', 'hwi-qt'] install_requires = \ -['cbor>=1.0.0,<2.0.0', +['cbor2>=5.4.6,<6.0.0', 'ecdsa>=0,<1', 'hidapi>=0.14.0', 'libusb1>=1.7,<4', diff --git a/test/test_jade.py b/test/test_jade.py index 9e8e57220..1d57c4fc4 100755 --- a/test/test_jade.py +++ b/test/test_jade.py @@ -24,7 +24,7 @@ from hwilib.devices.jadepy.jade import JadeAPI USE_SIMULATOR = True -JADE_PATH = 'tcp:127.0.0.1:30121' if USE_SIMULATOR else '/dev/ttyUSB0' +JADE_PATH = 'tcp:127.0.0.1:30121' if USE_SIMULATOR else None # None -> should search and find plugged unit TEST_SEED = bytes.fromhex('b90e532426d0dc20fffe01037048c018e940300038b165c211915c672e07762c') LOGGING = None # logging.INFO