diff --git a/cryptnox_cli/command/command.py b/cryptnox_cli/command/command.py index 0f2d894..affc36c 100644 --- a/cryptnox_cli/command/command.py +++ b/cryptnox_cli/command/command.py @@ -55,6 +55,7 @@ def _handle_execution(self, serial_number: int = None) -> int: try: self.serial_number = self.data.serial except AttributeError: + # No serial provided in arguments; keep the passed-in serial_number pass try: card = self._cards[self.serial_number] @@ -65,7 +66,7 @@ def _handle_execution(self, serial_number: int = None) -> int: print(f"Error in retrieving information: {error}") return -1 - self.run_execute(card) + return self.run_execute(card) def run_execute(self, card) -> int: print(f"Using card with serial number {card.serial_number}") diff --git a/cryptnox_cli/command/erc_token/initialize.py b/cryptnox_cli/command/erc_token/initialize.py index e2089bb..40c0023 100644 --- a/cryptnox_cli/command/erc_token/initialize.py +++ b/cryptnox_cli/command/erc_token/initialize.py @@ -7,10 +7,10 @@ import gzip import json -import urllib +import urllib.error +import urllib.parse from argparse import Namespace from typing import List -from urllib import parse import cryptnox_sdk_py import requests @@ -202,7 +202,7 @@ def _token_slots() -> list[str]: def _abi() -> str: def uri_validator(x): try: - result = parse.urlparse(x) + result = urllib.parse.urlparse(x) return all([result.scheme, result.netloc]) except Exception: return False diff --git a/cryptnox_cli/command/eth.py b/cryptnox_cli/command/eth.py index 3e2673b..d436608 100644 --- a/cryptnox_cli/command/eth.py +++ b/cryptnox_cli/command/eth.py @@ -169,6 +169,8 @@ def logs(self): endpoint.block_number save_to_config(self.card, self.config) + return None + @staticmethod def _get_logs(event) -> List[Dict[str, Any]]: min_offset = 0 @@ -256,6 +258,8 @@ def _execute(self, card): print(error) return -1 + return None + def _get_endpoint(self, card): config = get_configuration(card) @@ -311,6 +315,8 @@ def _add(self, card): print(f"Contract added to application. Use it with alias:" f" {self.data.alias}") + return None + @staticmethod def _list(card) -> int: config = get_configuration(card) @@ -356,6 +362,8 @@ def _functions(self, card): print(tabulate(tabulate_table, headers=tabulate_header, tablefmt="grid")) + return None + def _call(self, card): config = get_configuration(card) try: @@ -645,3 +653,5 @@ def _send_token(self, card): contract.transfer(card, config["endpoint"], config["network"], config["api_key"], self.data.contract, self.data.address, self.data.amount, self.data.price, self.data.limit, derivation) + + return None diff --git a/cryptnox_cli/command/get_clearpubkey.py b/cryptnox_cli/command/get_clearpubkey.py index 1f08b29..d715b71 100644 --- a/cryptnox_cli/command/get_clearpubkey.py +++ b/cryptnox_cli/command/get_clearpubkey.py @@ -98,6 +98,7 @@ def _execute(self, card) -> int: else: card.derive(key_type, "m/44'/0'/0'") except Exception: + # Best-effort derivation; clear pubkey read below handles failures pass pubkey_bytes = card.get_public_key_clear(derivation, path, compressed) self._print_pubkey_info(key_type, compressed, pubkey_bytes) diff --git a/cryptnox_cli/command/helper/cards.py b/cryptnox_cli/command/helper/cards.py index f048b50..532d70d 100644 --- a/cryptnox_cli/command/helper/cards.py +++ b/cryptnox_cli/command/helper/cards.py @@ -113,6 +113,7 @@ def refresh(self, remote: bool = False) -> None: except cryptnox_sdk_py.exceptions.ReaderException: break except cryptnox_sdk_py.exceptions.CryptnoxException: + # Card at this index is unreadable; skip it and continue scanning pass index += 1 @@ -194,7 +195,7 @@ def _open_card(self, index: int, remote: bool = False) -> cryptnox_sdk_py.Card: if test_response: if index in self._cards_by_index: return self._cards_by_index[index] - except (BaseException, cryptnox_sdk_py.exceptions.ConnectionException): + except (Exception, cryptnox_sdk_py.exceptions.ConnectionException): # Connection is stale, remove it and create new one del _GLOBAL_CONNECTIONS[index] if index in self._cards_by_index: diff --git a/cryptnox_cli/command/helper/config.py b/cryptnox_cli/command/helper/config.py index 54c4ee4..439b037 100644 --- a/cryptnox_cli/command/helper/config.py +++ b/cryptnox_cli/command/helper/config.py @@ -185,6 +185,7 @@ def write_config(card: cryptnox_sdk_py.Card, section: str, key: str, value: str) print(error) return 1 except AttributeError: + # Key not present on the validator instance; fall through to config handling pass try: diff --git a/cryptnox_cli/command/helper/helper_methods.py b/cryptnox_cli/command/helper/helper_methods.py index 576e1ce..cd23830 100644 --- a/cryptnox_cli/command/helper/helper_methods.py +++ b/cryptnox_cli/command/helper/helper_methods.py @@ -102,5 +102,6 @@ def try_eval(value: str) -> Any: try: value = ast.literal_eval(value) except ValueError: + # Not a literal; keep the original string value pass return value diff --git a/cryptnox_cli/command/helper/security.py b/cryptnox_cli/command/helper/security.py index 64081c6..58724b5 100644 --- a/cryptnox_cli/command/helper/security.py +++ b/cryptnox_cli/command/helper/security.py @@ -140,6 +140,7 @@ def check(card, check_seed: bool = True) -> bool: try: result = user_keys.authenticate(card) except NotImplementedError: + # User-key auth unsupported here; fall back to PIN authentication below pass if not result: diff --git a/cryptnox_cli/command/seed.py b/cryptnox_cli/command/seed.py index 2f34f07..a74f110 100644 --- a/cryptnox_cli/command/seed.py +++ b/cryptnox_cli/command/seed.py @@ -96,6 +96,7 @@ def _dual_seed(self, card: cryptnox_sdk_py.Card) -> int: print(error) return -1 except cryptnox_sdk_py.exceptions.DataValidationException: + # Expected when probing dual-seed support without a PIN; safe to proceed pass print("Dual seed generation process starting...") diff --git a/cryptnox_cli/command/transfer.py b/cryptnox_cli/command/transfer.py index e0abac1..2859fb2 100644 --- a/cryptnox_cli/command/transfer.py +++ b/cryptnox_cli/command/transfer.py @@ -10,10 +10,8 @@ try: import enums - from wallet import eth as wallet # noqa: F401 except ImportError: from .. import enums - from ..wallet import eth as wallet # noqa: F401 class Transfer(Command): diff --git a/cryptnox_cli/command/user_keys/authentication.py b/cryptnox_cli/command/user_keys/authentication.py index 3caa2f4..6309895 100644 --- a/cryptnox_cli/command/user_keys/authentication.py +++ b/cryptnox_cli/command/user_keys/authentication.py @@ -21,6 +21,7 @@ try: importlib.import_module("." + submodule, package=__package__) except Exception: + # Optional submodule unavailable in frozen build; skip it pass else: # When running normally, dynamically discover submodules @@ -155,6 +156,7 @@ def delete(name: str, card: cryptnox_sdk_py.Card, puk: str) -> bool: try: user_key.delete() except user_key_base.UserKeyException: + # Best-effort local key removal; proceed to delete it from the card pass card.user_key_delete(user_key.slot_index, puk) diff --git a/cryptnox_cli/command/user_keys/hello/windows_hello.py b/cryptnox_cli/command/user_keys/hello/windows_hello.py index dac23c6..b1d9e22 100644 --- a/cryptnox_cli/command/user_keys/hello/windows_hello.py +++ b/cryptnox_cli/command/user_keys/hello/windows_hello.py @@ -95,6 +95,7 @@ async def _get_user_credentials(account_id: str) -> KeyCredential: return key_result.credential _error_handle(key_result.status) + return None async def _public_key(name: str) -> bytearray: diff --git a/cryptnox_cli/command/user_keys/piv/piv_card.py b/cryptnox_cli/command/user_keys/piv/piv_card.py index 0206438..596d6a0 100644 --- a/cryptnox_cli/command/user_keys/piv/piv_card.py +++ b/cryptnox_cli/command/user_keys/piv/piv_card.py @@ -220,6 +220,7 @@ def is_locked(self, pin_bank: int) -> bool: try: self.verify_pin(pin_bank, "") except PinException: + # Empty PIN rejected as expected; card is not locked pass except PIVCardException as error: if error.sw_code == 0x6983: diff --git a/cryptnox_cli/interactive_cli.py b/cryptnox_cli/interactive_cli.py index 2803263..fdfdabe 100644 --- a/cryptnox_cli/interactive_cli.py +++ b/cryptnox_cli/interactive_cli.py @@ -219,6 +219,7 @@ def run(self) -> int: self._cards.refresh(self.port and client is not None) self._card_info = list(self._cards.values())[0].info except IndexError: + # No cards found yet; leave _card_info unset and continue pass self._cards.print_card_list(show_warnings=True, print_with_one_card=True) @@ -294,6 +295,7 @@ def _process_command(self): if execute[0] not in ["use", "exit", "back"]: execute[0:0] = self.subcommand except LookupError: + # Empty command; nothing to prepend, ignore pass else: self._prepare_parser() @@ -312,6 +314,7 @@ def _process_command(self): try: self.parser.parse_args(execute) except SystemExit: + # argparse exits on help/error; keep the interactive loop alive pass UsageParser.throw_error = True else: @@ -399,6 +402,7 @@ def _run_command(self, args: argparse.Namespace, to_always_run: List = None) -> try: self._card_info = self._cards[command.serial_number].info except KeyError: + # Card no longer present; keep previous _card_info pass except (cryptnox_sdk_py.exceptions.CryptnoxException, ExitException, TimeoutException) as error: print(error) diff --git a/cryptnox_cli/lib/cryptos/deterministic.py b/cryptnox_cli/lib/cryptos/deterministic.py index 8a23c84..7045d69 100644 --- a/cryptnox_cli/lib/cryptos/deterministic.py +++ b/cryptnox_cli/lib/cryptos/deterministic.py @@ -224,6 +224,8 @@ def bip32_descend(*args, prefixes=DEFAULT): path = parse_bip32_path(args[1]) elif len(args): key, path = args[0], list(map(int, args[1:])) + else: + raise TypeError("bip32_descend() requires at least one positional argument") for p in path: key = bip32_ckd(key, p, prefixes) return bip32_extract_key(key, prefixes) diff --git a/cryptnox_cli/lib/cryptos/keystore.py b/cryptnox_cli/lib/cryptos/keystore.py index abdd82e..781aada 100644 --- a/cryptnox_cli/lib/cryptos/keystore.py +++ b/cryptnox_cli/lib/cryptos/keystore.py @@ -166,6 +166,7 @@ def get_pubkey_derivation(self, x_pubkey): addr = self.coin.p2sh_scriptaddr(x_pubkey[2:]) if addr in self.addresses: return self.addresses[addr].get('pubkey') + return None def update_password(self, old_password, new_password): self.check_password(old_password) @@ -238,7 +239,7 @@ def derive_pubkey(self, for_change, n): return self.get_pubkey_from_xpub(xpub, (n,), self.bip39_prefixes) @classmethod - def get_pubkey_from_xpub(self, xpub, sequence, bip39_prefixes): + def get_pubkey_from_xpub(cls, xpub, sequence, bip39_prefixes): return bip32_derive_key(xpub, sequence, bip39_prefixes) """needed? @@ -352,7 +353,7 @@ class Hardware_KeyStore(KeyStore, Xpub): max_change_outputs = 1 def __init__(self, d, coin): - Xpub.__init__(self, coin) + Xpub.__init__(self) KeyStore.__init__(self, coin) # Errors and other user interaction is done through the wallet's # handler. The handler is per-window and preserved across @@ -483,7 +484,7 @@ def xpubkey_to_address(x_pubkey, coin): pubkey = x_pubkey elif x_pubkey[0:2] == 'ff': xpub, s = BIP32_KeyStore.parse_xpubkey(x_pubkey) - pubkey = BIP32_KeyStore.get_pubkey_from_xpub(xpub, s) + pubkey = BIP32_KeyStore.get_pubkey_from_xpub(xpub, s, coin.bip39_prefixes) else: raise BaseException("Cannot parse pubkey") address = coin.pubtoaddr(pubkey) @@ -516,11 +517,12 @@ def get_private_keys(text): parts = list(filter(bool, parts)) if bool(parts) and all(bitcoin.is_private_key(x) for x in parts): return parts + return None def is_private_key_list(text): return bool(get_private_keys(text)) -is_mpk = lambda x: is_xpub(x) +is_mpk = is_xpub is_private = lambda x: is_seed(x) or is_xprv(x) or is_private_key_list(x) is_master_key = lambda x: is_xprv(x) or is_xpub(x) is_private_key = lambda x: is_xprv(x) or is_private_key_list(x) @@ -568,7 +570,7 @@ def from_master_key(text, coin): if is_xprv(text, prefixes): k = from_xprv(text, coin) elif is_xpub(text, prefixes): - k = from_xpub(text, coin) + k = from_xpub(text, coin, 'p2pkh') else: raise BaseException('Invalid key') return k diff --git a/cryptnox_cli/lib/cryptos/main.py b/cryptnox_cli/lib/cryptos/main.py index 8e9a584..d82da9f 100644 --- a/cryptnox_cli/lib/cryptos/main.py +++ b/cryptnox_cli/lib/cryptos/main.py @@ -147,7 +147,7 @@ def jacobian_multiply(a, n): return jacobian_multiply(a, n % N) if (n % 2) == 0: return jacobian_double(jacobian_multiply(a, n // 2)) - if (n % 2) == 1: + else: return jacobian_add(jacobian_double(jacobian_multiply(a, n // 2)), a) @@ -333,6 +333,7 @@ def compress(pubkey): return encode_pubkey(decode_pubkey(pubkey, f), 'bin_compressed') elif f == 'hex' or f == 'decimal': return encode_pubkey(decode_pubkey(pubkey, f), 'hex_compressed') + return None def decompress(pubkey): @@ -343,6 +344,7 @@ def decompress(pubkey): return encode_pubkey(decode_pubkey(pubkey, f), 'bin') elif f == 'hex_compressed' or f == 'decimal': return encode_pubkey(decode_pubkey(pubkey, f), 'hex') + return None def privkey_to_pubkey(privkey): @@ -398,7 +400,9 @@ def bin_hash160(string): digest = '' try: digest = hashlib.new('ripemd160', intermed).digest() - except: + except Exception: + # 'ripemd160' may be unavailable (e.g. OpenSSL 3 legacy provider off); + # fall back to the bundled pure-Python implementation. digest = RIPEMD160(intermed).digest() return digest @@ -423,7 +427,9 @@ def sha256(string): def bin_ripemd160(string): try: digest = hashlib.new('ripemd160', string).digest() - except: + except Exception: + # 'ripemd160' may be unavailable (e.g. OpenSSL 3 legacy provider off); + # fall back to the bundled pure-Python implementation. digest = RIPEMD160(string).digest() return digest @@ -541,7 +547,7 @@ def is_privkey(priv): try: get_privkey_format(priv) return True - except: + except Exception: return False @@ -549,7 +555,7 @@ def is_pubkey(pubkey): try: get_pubkey_format(pubkey) return True - except: + except Exception: return False @@ -677,8 +683,9 @@ def subtract(p1, p2): def magicbyte_to_prefix(magicbyte): + # Always return a 2-tuple of the low/high address prefix characters. + # Callers only test membership over these, so a repeated character when + # first == last is harmless and keeps the return shape consistent. first = bin_to_b58check(hash160Low, magicbyte=magicbyte)[0] last = bin_to_b58check(hash160High, magicbyte=magicbyte)[0] - if first == last: - return (first,) return (first, last) diff --git a/cryptnox_cli/lib/cryptos/mnemonic.py b/cryptnox_cli/lib/cryptos/mnemonic.py index e773055..acf784b 100644 --- a/cryptnox_cli/lib/cryptos/mnemonic.py +++ b/cryptnox_cli/lib/cryptos/mnemonic.py @@ -16,8 +16,8 @@ from .specials import * from .wallet_utils import is_new_seed -wordlist_english = [word.strip() for word in - list(open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'english.txt'), 'r'))] +with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'english.txt'), 'r') as _wordlist_file: + wordlist_english = [word.strip() for word in _wordlist_file] ELECTRUM_VERSION = '3.0.5' # version of the client package PROTOCOL_VERSION = '1.1' # protocol version requested @@ -226,6 +226,7 @@ def seed_prefix(seed_type): return SEED_PREFIX_SW elif seed_type == '2fa': return SEED_PREFIX_2FA + return None def seed_type(x): diff --git a/cryptnox_cli/lib/cryptos/ripemd.py b/cryptnox_cli/lib/cryptos/ripemd.py index 86c0b6b..8415a3c 100644 --- a/cryptnox_cli/lib/cryptos/ripemd.py +++ b/cryptnox_cli/lib/cryptos/ripemd.py @@ -52,7 +52,8 @@ try: range = xrange -except: +except NameError: + # Python 3: xrange does not exist; the built-in range is already lazy. pass class RIPEMD160: @@ -164,7 +165,6 @@ def R(a, b, c, d, e, Fj, Kj, sj, rj, X): import struct def RMD160Transform(state, block): #uint32 state[5], uchar block[64] - x = [0]*16 if sys.byteorder == 'little': if is_python2: x = struct.unpack('<16L', ''.join([chr(x) for x in block[0:64]])) @@ -369,8 +369,6 @@ def RMD160Transform(state, block): #uint32 state[5], uchar block[64] state[4] = (state[0] + bb + c) % 0x100000000; state[0] = t % 0x100000000; - pass - def RMD160Update(ctx, inp, inplen): if type(inp) == str: diff --git a/cryptnox_cli/lib/cryptos/stealth.py b/cryptnox_cli/lib/cryptos/stealth.py index ca769d7..6a6c0c2 100644 --- a/cryptnox_cli/lib/cryptos/stealth.py +++ b/cryptnox_cli/lib/cryptos/stealth.py @@ -83,6 +83,9 @@ def mk_stealth_tx_outputs(stealth_addr, value, ephem_privkey, nonce, network='bt raise Exception('Invalid testnet stealth address: ' + stealth_addr) magic_byte_addr = 111 + else: + raise Exception('Unknown network: ' + str(network)) + ephem_pubkey = main.privkey_to_pubkey(ephem_privkey) output0 = {'script': mk_stealth_metadata_script(ephem_pubkey, nonce), 'value': 0} diff --git a/cryptnox_cli/lib/cryptos/transaction.py b/cryptnox_cli/lib/cryptos/transaction.py index 35da75d..e442ad2 100644 --- a/cryptnox_cli/lib/cryptos/transaction.py +++ b/cryptnox_cli/lib/cryptos/transaction.py @@ -78,7 +78,7 @@ def deserialize(tx): if isinstance(tx, str) and re.match('^[0-9a-fA-F]*$', tx): # tx = bytes(bytearray.fromhex(tx)) return json_changebase(deserialize(binascii.unhexlify(tx)), - lambda x: safe_hexlify(x)) + safe_hexlify) # http://stackoverflow.com/questions/4851463/python-closure-write-to-variable-in-parent-scope # Python's scoping rules are demented, requiring me to make pos an object # so that it is call-by-reference @@ -148,7 +148,7 @@ def serialize(txobj, include_witness=True): txobj = bytes_to_hex_string(txobj) o = [] if json_is_base(txobj, 16): - json_changedbase = json_changebase(txobj, lambda x: binascii.unhexlify(x)) + json_changedbase = json_changebase(txobj, binascii.unhexlify) hexlified = safe_hexlify(serialize(json_changedbase, include_witness=include_witness)) return hexlified o.append(encode_4_bytes(txobj["version"])) @@ -178,7 +178,7 @@ def uahf_digest(txobj, i): o = [] if json_is_base(txobj, 16): - txobj = json_changebase(txobj, lambda x: binascii.unhexlify(x)) + txobj = json_changebase(txobj, binascii.unhexlify) o.append(encode(txobj["version"], 256, 4)[::-1]) serialized_ins = [] @@ -373,7 +373,7 @@ def p2wpkh_nested_script(pubkey): def deserialize_script(script): if isinstance(script, str) and re.match('^[0-9a-fA-F]*$', script): return json_changebase(deserialize_script(binascii.unhexlify(script)), - lambda x: safe_hexlify(x)) + safe_hexlify) out, pos = [], 0 while pos < len(script): code = from_byte_to_int(script[pos]) @@ -420,13 +420,13 @@ def serialize_script_unit(unit): def serialize_script(script): if json_is_base(script, 16): return binascii.hexlify(serialize_script(json_changebase(script, - lambda x: binascii.unhexlify(x)))) + binascii.unhexlify))) return ''.join(map(serialize_script_unit, script)) else: def serialize_script(script): if json_is_base(script, 16): return safe_hexlify(serialize_script(json_changebase(script, - lambda x: binascii.unhexlify(x)))) + binascii.unhexlify))) result = bytes() for b in map(serialize_script_unit, script): result += b if isinstance(b, bytes) else bytes(b, 'utf-8') @@ -507,6 +507,4 @@ def select(unspent, value): i += 1 if tv < value: raise Exception("Not enough funds") - unspents = low[:i] - actual_value = sum(unspent['value'] for unspent in unspents) return low[:i] diff --git a/cryptnox_cli/lib/cryptos/wallet.py b/cryptnox_cli/lib/cryptos/wallet.py index 3a8e104..a509642 100644 --- a/cryptnox_cli/lib/cryptos/wallet.py +++ b/cryptnox_cli/lib/cryptos/wallet.py @@ -28,7 +28,7 @@ def __init__(self, keystore, num_addresses=0, last_receiving_index=0, last_chang def privkey(self, address, formt="wif_compressed", password=None): if self.is_watching_only: - return + return None try: addr_derivation = self.addresses[address] except KeyError: @@ -39,7 +39,7 @@ def privkey(self, address, formt="wif_compressed", password=None): def export_privkeys(self, password=None): if self.is_watching_only: - return + return None return { 'receiving': {addr: self.privkey(addr, password=password) for addr in self.receiving_addresses}, 'change': {addr: self.privkey(addr, password=password) for addr in self.change_addresses} @@ -58,6 +58,7 @@ def pubtoaddr(self, pubkey): return self.coin.pubtosegwit(pubkey) elif self.keystore.xtype == "p2wpkh-p2sh": return self.coin.pubtop2w(pubkey) + return None def receiving_address(self, index): pubkey = self.pubkey_receiving(index) @@ -149,4 +150,4 @@ def details(self, password=None): 'xchange': (), 'receiving': [self.account(a, password=password) for a in self.receiving_addresses], 'change': [self.account(a, password=password) for a in self.change_addresses] - } \ No newline at end of file + } diff --git a/cryptnox_cli/lib/cryptos/wallet_utils.py b/cryptnox_cli/lib/cryptos/wallet_utils.py index 4e2579e..f046919 100644 --- a/cryptnox_cli/lib/cryptos/wallet_utils.py +++ b/cryptnox_cli/lib/cryptos/wallet_utils.py @@ -78,7 +78,7 @@ def __str__(self): try: from Cryptodome.Cipher import AES -except: +except ImportError: AES = None diff --git a/cryptnox_cli/wallet/btc.py b/cryptnox_cli/wallet/btc.py index 3a060df..11e57ee 100644 --- a/cryptnox_cli/wallet/btc.py +++ b/cryptnox_cli/wallet/btc.py @@ -6,7 +6,6 @@ import json import re import urllib.parse -import urllib.request import requests from enum import Enum from typing import Union, List, Dict @@ -85,13 +84,15 @@ def get_data(self, endpoint: str, params: Dict = None, data: bytes = None) \ if not parsed.hostname or 'blockcypher.com' not in parsed.hostname: raise ValueError("Invalid URL: must be blockcypher.com domain") - req = urllib.request.Request( - full_url, - headers={'User-Agent': 'Mozilla/5.0'}, - data=data - ) - self.web_rsc = urllib.request.urlopen(req, timeout=30) - self.js_res = json.load(self.web_rsc) + # Use 'requests' (validated allow-listed https URL) instead of urllib, + # which would also honour file:// and other local schemes. + headers = {'User-Agent': 'Mozilla/5.0'} + if data is None: + response = requests.get(full_url, headers=headers, timeout=30) + else: + response = requests.post(full_url, headers=headers, data=data, timeout=30) + response.raise_for_status() + self.js_res = response.json() self.web_rsc = None except Exception as ex: print(ex) @@ -237,19 +238,20 @@ def get_data(self, endpoint: str, params: Dict = None, data: bytes = None) \ headers = {'User-Agent': 'Mozilla/5.0'} if self.api_key: headers['x-token'] = self.api_key - req = urllib.request.Request( - full_url, - headers=headers, - data=data - ) - self.web_rsc = urllib.request.urlopen(req, timeout=30) - b_rep = self.web_rsc.read() + # Use 'requests' (validated allow-listed https URL) instead of urllib, + # which would also honour file:// and other local schemes. + if data is None: + response = requests.get(full_url, headers=headers, timeout=30) + else: + response = requests.post(full_url, headers=headers, data=data, timeout=30) + response.raise_for_status() + b_rep = response.content if len(b_rep) == 64 and b_rep[0] != ord('{'): b_rep = b'{"txid":"' + b_rep + b'"}' self.js_res = json.loads(b_rep) - except urllib.error.HTTPError as error: - raise IOError(f"Error while processing request:\n{error.code} - " - f"{error.read().decode('utf8')}") from error + except requests.exceptions.HTTPError as error: + raise IOError(f"Error while processing request:\n{error.response.status_code} - " + f"{error.response.text}") from error except Exception as error: raise IOError(f"Error while processing request:\n{self.url}{endpoint}?params_enc\n" f"{error}") from error diff --git a/cryptnox_cli/wallet/eth/api.py b/cryptnox_cli/wallet/eth/api.py index 631d3ca..6f85483 100644 --- a/cryptnox_cli/wallet/eth/api.py +++ b/cryptnox_cli/wallet/eth/api.py @@ -80,6 +80,7 @@ def transaction_hash(self, transaction: Dict[str, Any], vrs: bool = False): del transaction["maxFeePerGas"] del transaction["maxPriorityFeePerGas"] except KeyError: + # EIP-1559 fee fields absent (legacy transaction); nothing to remove pass unsigned_transaction = serializable_unsigned_transaction_from_dict(transaction) encoded_transaction = encode_transaction(unsigned_transaction, (self._chain_id, 0, 0)) diff --git a/dev-requirements.txt b/dev-requirements.txt index c0d3069..ec683d3 100644 Binary files a/dev-requirements.txt and b/dev-requirements.txt differ diff --git a/requirements.txt b/requirements.txt index 0f54754..815dd6d 100644 Binary files a/requirements.txt and b/requirements.txt differ