def parse_new_wallet(s): show_main() gui.update(30) # wallet format: # name&descriptor arr = s.split("&") if len(arr) != 2: gui.error("Invalid wallet format") return w = keystore.check_new_wallet(*arr) keys_str = [] for key in w.keys: k = ("%r" % key).replace("]", "]\n") if keystore.owns_key(key): keys_str.append("#7ED321 My key: # %s" % k) else: keys_str.append("#F5A623 External key: # %s" % k) keys = "\n\n".join(keys_str) if w.script_type not in SUPPORTED_SCRIPTS.keys(): raise ValueError("Script type \"%s\" is not supported" % w.script_type) sc = w.script_type msg = "Policy: %s\nScript: %s\n%s\n\n%s" % (w.policy, SUPPORTED_SCRIPTS[w.script_type], sc, keys) scr = popups.prompt("Add wallet \"%s\"?" % arr[0], msg, ok=cb_with_args(new_wallet_confirm, name=arr[0], descriptor=arr[1])) scr.message.set_recolor(True)
def cb(*args, **kwargs): try: return fn(*args, **kwargs) except Exception as e: b = BytesIO() sys.print_exception(e, b) gui.error("Something bad happened...\n\n%s" % b.getvalue().decode())
def cb(): try: select_network(name) show_main() except Exception as e: print(e) gui.error("%r" % e)
def parse_transaction(b64_tx, success_callback=None, error_callback=None): # we will go to main afterwards show_main() try: raw = a2b_base64(b64_tx) tx = psbt.PSBT.parse(raw) except: gui.error("Failed at transaction parsing") if error_callback is not None: error_callback("invalid argument") return # blue wallet trick - if the fingerprint is 0 we use our fingerprint for scope in [tx.inputs, tx.outputs]: for el in scope: for der in el.bip32_derivations: if el.bip32_derivations[ der].fingerprint == b'\x00\x00\x00\x00': el.bip32_derivations[ der].fingerprint = keystore.fingerprint try: data = keystore.check_psbt(tx) except Exception as e: gui.error("Problem with the transaction: %r" % e) if error_callback is not None: error_callback("invalid argument") return title = "Spending %u\nfrom %s" % (data["spending"], data["wallet"].name) popups.prompt_tx(title, data, ok=cb_with_args(sign_psbt, wallet=data["wallet"], tx=tx, success_callback=success_callback), cancel=cb_with_args(error_callback, "user cancel"))
def save_entropy_plain(): obj = {"entropy": hexlify(entropy).decode('utf-8')} with open(reckless_fname, "w") as f: f.write(json.dumps(obj)) with open(reckless_fname, "r") as f: d = json.loads(f.read()) if "entropy" in d and d["entropy"] == hexlify(entropy).decode('utf-8'): gui.alert("Success!", "Your key is saved in the memory now") else: gui.error("Something went wrong")
def parse_transaction(b64_tx, success_callback=None, error_callback=None): # we will go to main afterwards show_main() try: raw = a2b_base64(b64_tx) tx = psbt.PSBT.parse(raw) except: gui.error("Failed at transaction parsing") if error_callback is not None: error_callback("invalid argument") return # blue wallet trick - if the fingerprint is 0 we use our fingerprint for scope in [tx.inputs, tx.outputs]: for el in scope: for der in el.bip32_derivations: if el.bip32_derivations[der].fingerprint == b'\x00\x00\x00\x00': el.bip32_derivations[der].fingerprint = keystore.fingerprint try: data = keystore.check_psbt(tx) except Exception as e: gui.error("Problem with the transaction: %r" % e) if error_callback is not None: error_callback("invalid argument") return # check for address gap limit gap_limit = False w = data["wallet"] wallet_key = b"\xfc\xca\x01" + data["wallet"].fingerprint for el in tx.inputs + tx.outputs: if el.bip32_derivations: # full PSBT for der in el.bip32_derivations: drv = el.bip32_derivations[der].derivation if drv[-1] > w.gap_limit + (w.last_chg_idx if drv[-2] else w.last_rcv_idx): gap_limit = True elif wallet_key in el.unknown: # compressed PSBT idxs = el.unknown[wallet_key] chg = int.from_bytes(idxs[0:4], 'little') idx = int.from_bytes(idxs[4:8], 'little') if idx > w.gap_limit + (w.last_chg_idx if chg else w.last_rcv_idx): gap_limit = True if gap_limit: data["warning"] = ("#ff0000 Possible gap limit exceeded with some#\n" "#ff0000 addresses. Your funds may get locked. #\n " "#ff0000 Proceed at your own risk!#") title = "Spending %u\nfrom %s" % (data["spending"], data["wallet"].name) popups.prompt_tx(title, data, ok=cb_with_args(sign_psbt, wallet=data["wallet"], tx=tx, success_callback=success_callback), cancel=cb_with_args(error_callback, "user cancel") )
def load_key(): global entropy with open(reckless_fname, "r") as f: d = json.loads(f.read()) entropy = unhexlify(d["entropy"]) if "hmac" in d: hmac_calc = hmac_sha512(Key.key, entropy) if unhexlify(d["hmac"]) != hmac_calc: raise ValueError('Hmac does not match!') Key.iv = unhexlify(d["iv"]) entropy = entropy_decrypt(entropy) if entropy is not None: ask_for_password() else: gui.error("Failed to load your recovery phrase.")
def show_xpub(name, derivation, xpub=None): xpubs_menu() gui.update(30) try: if xpub is None: xpub = keystore.get_xpub(derivation) prefix = "[%s]" % bip32.path_to_str(bip32.parse_path(derivation), fingerprint=keystore.fingerprint) except: gui.error("Derivation path \"%s\" doesn't look right..." % derivation) return xpub_str = xpub.to_base58(network["xpub"]) slip132 = xpub.to_base58() if slip132 == xpub_str: slip132 = None popups.show_xpub(name, xpub_str, slip132=slip132, prefix=prefix)
def load_key(): global entropy try: with open(reckless_fname, "r") as f: d = json.loads(f.read()) entropy = unhexlify(d["entropy"]) if "hmac" in d: hmac_calc = hmac_sha512(Key.key, entropy) if unhexlify(d["hmac"]) != hmac_calc: raise ValueError('Hmac does not match!') Key.iv = unhexlify(d["iv"]) entropy = entropy_decrypt(entropy) ask_for_password() except: gui.error("Something went wrong, sorry")
def confirm_new_wallet(s): show_main() gui.update(30) # wallet format: # name&descriptor arr = s.split("&") if len(arr) != 2: gui.error("Invalid wallet format") return try: keystore.check_new_wallet(*arr) except Exception as e: gui.error("%r" % e) return popups.prompt("Add wallet \"%s\"?" % arr[0], arr[1], ok=cb_with_args(new_wallet_confirm, name=arr[0], descriptor=arr[1]))
def save_entropy_encrypted(): try: Key.iv = get_random_bytes(16) entropy_encrypted = entropy_encrypt(entropy) hmac_entropy_encrypted = hmac_sha512(Key.key, entropy_encrypted) obj = { "entropy": hexlify(entropy_encrypted).decode('utf-8'), "iv": hexlify(Key.iv).decode('utf-8'), "hmac": hexlify(hmac_entropy_encrypted).decode('utf-8') } with open(reckless_fname, "w") as f: f.write(json.dumps(obj)) with open(reckless_fname, "r") as f: d = json.loads(f.read()) if "entropy" in d and d["entropy"] == hexlify(entropy_encrypted).decode('utf-8') and \ unhexlify(d["hmac"]) == hmac_entropy_encrypted and entropy == entropy_decrypt(entropy_encrypted): gui.alert("Success!", "Your encrypted key is saved in the memory now") else: gui.error("Something went wrong") except Exception as e: gui.error("Fail: %r" % e)
def verify_address(s): # we will go to main afterwards show_main() # verifies address in the form [bitcoin:]addr?index=i s = s.replace("bitcoin:", "") arr = s.split("?") index = None addr = None # check that ?index= is there if len(arr) > 1: addr = arr[0] meta_arr = arr[1].split("&") # search for `index=` for meta in meta_arr: if meta.startswith("index="): try: index = int(meta.split("=")[1]) except: gui.error("Index is not an integer...") return if index is None or addr is None: # where we will go next gui.error( "No derivation index in the address metadata - can't verify.") return for w in keystore.wallets: if w.address(index) == addr: popups.qr_alert("Address #%d from wallet\n\"%s\"" % (index + 1, w.name), "bitcoin:%s" % addr, message_text=addr) return gui.error("Address doesn't belong to any wallet. Wrong device or network?")
def save_settings(config): try: if USB_ENABLED and not config["usb"]: os.remove("%s/%s" % (storage_root, "USB_ENABLED")) if not USB_ENABLED and config["usb"]: with open("%s/%s" % (storage_root, "USB_ENABLED"), "w") as f: f.write("dummy") # should be hmac instead if DEV_ENABLED and not config["developer"]: os.remove("%s/%s" % (storage_root, "DEV_ENABLED")) if not DEV_ENABLED and config["developer"]: with open("%s/%s" % (storage_root, "DEV_ENABLED"), "w") as f: f.write("dummy") # should be hmac instead time.sleep_ms(100) if simulator: # meh... kinda doesn't work on unixport sys.exit() else: import pyb pyb.hard_reset() except Exception as e: gui.error("Failed to update settings!\n%r" % e) print(config)
def verify_address(s): # we will go to main afterwards show_main() # verifies address in the form [bitcoin:]addr?index=i s = s.replace("bitcoin:", "") arr = s.split("?") index = None addr = None # check that ?index= is there if len(arr) > 1: addr = arr[0] meta_arr = arr[1].split("&") # search for `index=` for meta in meta_arr: if meta.startswith("index="): try: index = int(meta.split("=")[1]) except: gui.error("Index is not an integer...") return if index is None or addr is None: # where we will go next gui.error("No derivation index in the address metadata - can't verify.") return for w in keystore.wallets: if w.address(index) == addr: warning = "" if index > w.last_rcv_idx + w.gap_limit: warning = ("\n\n #ff0000 Possible gap limit. Using this address# " "#ff0000 may lead to locking of your funds!#") elif index <= w.last_rcv_idx: warning = ("\n\n #ff0000 This address may have been used before.#\n" "#ff0000 Reusing it would diminish your privacy!#") popups.qr_alert("Address #%d from wallet\n\"%s\"" % (index, w.name), "bitcoin:%s"%addr, message_text=addr + warning) return gui.error("Address doesn't belong to any wallet. Wrong device or network?")
def qr_scanner_error(msg): cancel_scan() gui.error(msg)
def delete_entropy(): try: os.remove(reckless_fname) gui.alert("Success!", "Your key is deleted") except: gui.error("Failed to delete the key")