def wipe_flash_filesystem(): # erase and re-format the flash filesystem (/flash/) import ckcc, pyb from main import dis, settings dis.fullscreen('Erasing...') os.umount('/flash') # from extmod/vfs.h BP_IOCTL_SEC_COUNT = (4) BP_IOCTL_SEC_SIZE = (5) # block-level erase fl = pyb.Flash() bsize = fl.ioctl(BP_IOCTL_SEC_SIZE, 0) assert bsize == 512 bcount = fl.ioctl(BP_IOCTL_SEC_COUNT, 0) blk = bytearray(bsize) ckcc.rng_bytes(blk) # trickiness: actual flash blocks are offset by 0x100 (FLASH_PART1_START_BLOCK) # so fake MBR can be inserted. Count also inflated by 2X, but not from ioctl above. for n in range(bcount): fl.writeblocks(n + 0x100, blk) ckcc.rng_bytes(blk) dis.progress_bar_show(n * 2 / bcount) # rebuild and mount /flash dis.fullscreen('Rebuilding...') ckcc.wipe_fs() # re-store settings settings.save()
def commit(self): # data to save # - important that this fails immediately when nvram overflows from main import settings obj = self.serialize() v = settings.get('multisig', []) orig = v.copy() if not v or self.storage_idx == -1: # create self.storage_idx = len(v) v.append(obj) else: # update: no provision for changing fingerprints assert sorted(k for k, v in v[self.storage_idx][2]) == self.xfps v[self.storage_idx] = obj settings.set('multisig', v) # save now, rather than in background, so we can recover # from out-of-space situation try: settings.save() except: # back out change; no longer sure of NVRAM state try: settings.set('multisig', orig) settings.save() except: pass # give up on recovery raise MultisigOutOfSpace
async def accept_terms(*a): # do nothing if they have accepted the terms once (ever), otherwise # force them to read message... if settings.get('terms_ok'): return while 1: ch = await ux_show_story("""\ By using this product, you are accepting our Terms of Sale and Use. Read the full document at: https:// coldcardwallet .com/legal Press OK to accept terms and continue.""", escape='7') if ch == 'y': break await show_bag_number() # Note fact they accepted the terms. Annoying to do more than once. settings.set('terms_ok', 1) settings.save()
async def start_selftest(*args): if len(args) and not version.is_factory_mode(): # called from inside menu, not directly if not await ux_confirm('''Selftest destroys settings on other profiles (not seeds). Requires MicroSD card and might have other consequences. Recommended only for factory.'''): return await ux_aborted() with imported('selftest') as st: await st.start_selftest() settings.save()
async def convert_bip39_to_bip32(*a): if not await ux_confirm( '''This operation computes the extended master private key using your BIP39 seed words and passphrase, and then saves the resulting value (xprv) as the wallet secret. The seed words themselves are erased forever, but effectively there is no other change. If a BIP39 passphrase is currently in effect, its value is captured during this process and will be 'in effect' going forward, but the passphrase itself is erased and unrecoverable. The resulting wallet cannot be used with any other passphrase. A reboot is part of this process. PIN code, and funds are not affected. '''): return await ux_aborted() import seed await seed.remember_bip39_passphrase() settings.save() await login_now()
def delete(self): # remove saved entry # - important: not expecting more than one instance of this class in memory from main import settings assert self.storage_idx >= 0 # safety check expect_idx = self.find_match(self.M, self.N, self.xfps) assert expect_idx == self.storage_idx lst = settings.get('multisig', []) del lst[self.storage_idx] settings.set('multisig', lst) settings.save() self.storage_idx = -1
def clear(cls): # user action in danger zone menu cls.runtime_cache.clear() cls._cache_loaded = True settings.remove_key(cls.KEY) settings.save()
def _flush_data(): try: from main import settings settings.save() except: pass
async def restore_from_dict(vals): # Restore from a dict of values. Already JSON decoded. # Reboot on success, return string on failure from main import pa, dis, settings from pincodes import AE_SECRET_LEN #print("Restoring from: %r" % vals) # step1: the private key # - prefer raw_secret over other values # - TODO: fail back to other values try: chain = chains.get_chain(vals.get('chain', 'BTC')) assert 'raw_secret' in vals raw = bytearray(AE_SECRET_LEN) rs = vals.pop('raw_secret') if len(rs) % 2: rs += '0' x = a2b_hex(rs) raw[0:len(x)] = x # check we can decode this right (might be different firmare) opmode, bits, node = stash.SecretStash.decode(raw) assert node # verify against xprv value (if we have it) if 'xprv' in vals: check_xprv = chain.serialize_private(node) assert check_xprv == vals['xprv'], 'xprv mismatch' except Exception as e: return ('Unable to decode raw_secret and ' 'restore the seed value!\n\n\n' + str(e)) ls = None if ('long_secret' in vals) and version.has_608: try: ls = a2b_hex(vals.pop('long_secret')) except Exception as exc: sys.print_exception(exc) # but keep going. dis.fullscreen("Saving...") dis.progress_bar_show(.25) # clear (in-memory) settings and change also nvram key # - also captures xfp, xpub at this point pa.change(new_secret=raw) # force the right chain pa.new_main_secret(raw, chain) # updates xfp/xpub # NOTE: don't fail after this point... they can muddle thru w/ just right seed if ls is not None: try: pa.ls_change(ls) except Exception as exc: sys.print_exception(exc) # but keep going # restore settings from backup file for idx, k in enumerate(vals): dis.progress_bar_show(idx / len(vals)) if not k.startswith('setting.'): continue if k == 'xfp' or k == 'xpub': continue settings.set(k[8:], vals[k]) # write out settings.save() if version.has_fatram and ('hsm_policy' in vals): import hsm hsm.restore_backup(vals['hsm_policy']) await ux_show_story( 'Everything has been successfully restored. ' 'We must now reboot to install the ' 'updated settings and/or seed.', title='Success!') from machine import reset reset()
from ubinascii import unhexlify as a2b_hex import tcc, ustruct from main import settings, sf from nvstore import SLOTS # reset whatever's there sf.chip_erase() settings.load() for v in [123, 'hello', 34.56, dict(a=45)]: settings.set('abc', v) assert settings.get('abc') == v a = settings.get('_age', -1) settings.save() assert settings.get('_age') >= a + 1, [settings.get('_age'), a + 1] chk = dict(settings.current) settings.load() # some minor differences in values: bytes vs. strings, so just check keys assert sorted(list(chk)) == sorted(list(settings.current)), \ 'readback fail: \n%r != \n%r' % (chk, settings.current) if 1: # fill it up covered = set() for x in range(256): settings.nvram_key = ustruct.pack('I', x + 47) + bytes(32 - 4) settings.load()