async def import_xprv(*A): # read an XPRV from a text file and use it. import tcc, chains, ure from main import pa from stash import SecretStash from ubinascii import hexlify as b2a_hex from backups import restore_from_dict assert pa.is_secret_blank() # "must not have secret" def contains_xprv(fname): # just check if likely to be valid; not full check try: with open(fname, 'rt') as fd: for ln in fd: # match tprv and xprv, plus y/zprv etc if 'prv' in ln: return True return False except OSError: # directories? return False # pick a likely-looking file. fn = await file_picker('Select file containing the XPRV to be imported.', min_size=50, max_size=2000, taster=contains_xprv) if not fn: return node, chain, addr_fmt = None, None, None # open file and do it pat = ure.compile(r'.prv[A-Za-z0-9]+') with CardSlot() as card: with open(fn, 'rt') as fd: for ln in fd.readlines(): if 'prv' not in ln: continue found = pat.search(ln) if not found: continue found = found.group(0) for ch in chains.AllChains: for kk in ch.slip132: if found[0] == ch.slip132[kk].hint: try: node = tcc.bip32.deserialize( found, ch.slip132[kk].pub, ch.slip132[kk].priv) chain = ch addr_fmt = kk break except ValueError: pass if node: break if not node: # unable await ux_show_story('''\ Sorry, wasn't able to find an extended private key to import. It should be at \ the start of a line, and probably starts with "xprv".''', title="FAILED") return # encode it in our style d = dict(chain=chain.ctype, raw_secret=b2a_hex(SecretStash.encode(xprv=node))) node.blank() # TODO: capture the address format implied by SLIP32 version bytes #addr_fmt = # restore as if it was a backup (code reuse) await restore_from_dict(d)
async def microsd_upgrade(*a): # Upgrade vis MicroSD card # - search for a particular file # - verify it lightly # - erase serial flash # - copy it over (slow) # - reboot into bootloader, which finishes install fn = await file_picker('Pick firmware image to use (.DFU)', suffix='.dfu', min_size=0x7800) if not fn: return failed = None with CardSlot() as card: with open(fn, 'rb') as fp: from main import sf, dis from files import dfu_parse from ustruct import unpack_from offset, size = dfu_parse(fp) # get a copy of special signed heaer at the end of the flash as well from sigheader import FW_HEADER_OFFSET, FW_HEADER_SIZE, FW_HEADER_MAGIC, FWH_PY_FORMAT hdr = bytearray(FW_HEADER_SIZE) fp.seek(offset + FW_HEADER_OFFSET) # basic checks only: for confused customers, not attackers. try: rv = fp.readinto(hdr) assert rv == FW_HEADER_SIZE magic_value, timestamp, version_string, pk, fw_size = \ unpack_from(FWH_PY_FORMAT, hdr)[0:5] assert magic_value == FW_HEADER_MAGIC assert fw_size == size # TODO: maybe show the version string? Warn them that downgrade doesn't work? except Exception as exc: failed = "Sorry! That does not look like a firmware " \ "file we would want to use.\n\n\n%s" % exc if not failed: # copy binary into serial flash fp.seek(offset) buf = bytearray(256) # must be flash page size pos = 0 dis.fullscreen("Loading...") while pos <= size + FW_HEADER_SIZE: dis.progress_bar_show(pos / size) if pos == size: # save an extra copy of the header (also means we got done) buf = hdr else: here = fp.readinto(buf) if not here: break if pos % 4096 == 0: # erase here sf.sector_erase(pos) while sf.is_busy(): await sleep_ms(10) sf.write(pos, buf) # full page write: 0.6 to 3ms while sf.is_busy(): await sleep_ms(1) pos += here if failed: await ux_show_story(failed, title='Corrupt') return # continue process... import machine machine.reset()