示例#1
0
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()
示例#2
0
async def address_explore(*a):
    # explore addresses based on derivation path chosen
    # by proxy external index=0 address
    from main import settings

    while not settings.get('axskip', False):
        ch = await ux_show_story('''\
The following menu lists the first payment address \
produced by various common wallet systems.

Choose the address that your desktop or mobile wallet \
has shown you as the first receive address.

WARNING: Please understand that exceeding the gap limit \
of your wallet, or choosing the wrong address on the next screen \
may make it very difficult to recover your funds.

Press 4 to start or 6 to hide this message forever.''', escape='46')

        if ch == '4': break
        if ch == '6':
            settings.set('axskip', True)
            break
        if ch == 'x': return

    m = AddressListMenu()
    await m.render()        # slow

    the_ux.push(m)
示例#3
0
async def start_b39_pw(menu, label, item):
    if not settings.get('b39skip', False):
        ch = await ux_show_story('''\
You may add a passphrase to your BIP39 seed words. \
This creates an entirely new wallet, for every possible passphrase.

By default, the Coldcard uses an empty string as the passphrase.

On the next menu, you can enter a passphrase by selecting \
individual lettters, choosing from the word list (recommended), \
or by typing numbers.

Please write down the fingerprint of all your wallets, so you can \
confirm when you've got the right passphrase. (If you are writing down \
the passphrase as well, it's okay to put them together.) There is no way for \
the Coldcard to know if your password is correct, and if you have it wrong, \
you will be looking at an empty wallet.

Limitations: 100 characters max length, ASCII \
characters 32-126 (0x20-0x7e) only.

OK to start.
X to go back. Or press 2 to hide this message forever.
''',
                                 escape='2')
        if ch == '2':
            settings.set('b39skip', True)
        if ch == 'x':
            return

    import seed
    return seed.PassphraseMenu()
示例#4
0
    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
示例#5
0
async def test_7z():
    # test full 7z round-trip
    # Altho cleartext mode is not for real, if the code is written, I must test it.
    from backups import write_complete_backup, restore_complete_doit
    from sffile import SFFile
    import tcc
    from main import settings, sf, numpad

    today = tcc.random.uniform(1000000)

    import machine
    machine.reset = lambda: None

    for chain in ['BTC', 'XTN']:
        for words in ([], ['abc', 'def']):
            settings.set('check', today)
            settings.set('chain', chain)

            ll, sha = await write_complete_backup(words, None, True)

            result = SFFile(0, ll).read()

            if words:
                #open('debug.7z', 'wb').write(result)
                assert ll > 800
                assert len(sha) == 32
                assert result[0:6] == b"7z\xbc\xaf'\x1c"
                assert tcc.sha256(result).digest() == sha
                assert len(set(result)) >= 240  # encrypted
            else:
                sr = str(result, 'ascii')
                print("Backup contents:\n" + sr)
                assert sr[0] == '#', result
                assert 'Coldcard' in sr
                assert len(set(sr)) < 100  # cleartext, english
                assert ('chain = "%s"' % chain) in result

            # test restore
            # - cant wipe flash, since the backup file is there
            # - cant wipe all settings becuase PIN and stuff is simulated there
            del settings.current['check']

            with SFFile(0, ll) as fd:
                numpad.inject('y')  # for 'success' message
                await restore_complete_doit(fd, words)

                assert settings.get('check') == today, \
                            (settings.get('check'), '!=',  today)
                assert settings.get('chain') == chain, \
                            (settings.get('chain'), '!=',  chain)

            today += 3

            import ux
            ux.restore_menu()
示例#6
0
    def set_chain(idx, text):
        val = ch[idx][0]
        assert ch[idx][1] == text
        settings.set('chain', val)

        try:
            # update xpub stored in settings
            import stash
            with stash.SensitiveValues() as sv:
                sv.capture_xpub()
        except ValueError:
            # no secrets yet, not an error
            pass
示例#7
0
    def set_it(idx, text):
        value = ch[idx][0]
        settings.set('sens', value)
        numpad.sensitivity = value

        # save also for next login time.
        from main import pa
        from nvstore import SettingsObject

        if not pa.is_secondary:
            tmp = SettingsObject()
            tmp.set('sens', value)
            tmp.save()
            del tmp
示例#8
0
    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
示例#9
0
async def start_selftest():

    try:
        await test_oled()
        await test_microsd()
        await test_numpad()
        await test_sflash()
        await test_secure_element()
        await test_sd_active()

        # add more tests here

        settings.set('tested', True)
        await ux_show_story("Selftest complete", 'PASS')

    except (RuntimeError, AssertionError) as e:
        await ux_show_story("Test failed:\n" + str(e), 'FAIL')
示例#10
0
async def start_selftest():
    import version

    try:
        await test_oled()
        await test_microsd()
        await test_numpad()
        await test_sflash()
        await test_ae508a()

        if version.is_mark2():
            await test_sd_active()

        # add more tests here

        settings.set('tested', True)
        await ux_show_story("Selftest complete", 'PASS')

    except (RuntimeError, AssertionError) as e:
        await ux_show_story("Test failed:\n" + str(e), 'FAIL')
示例#11
0
async def start_selftest():

    try:
        await test_oled()
        await test_microsd()
        await test_touch()
        await test_sflash()
        #await test_dfu_button()        # no need
        await test_ae508a()

        # TODO:
        # - PIN diode

        # add more tests here

        settings.set('tested', True)
        await ux_show_story("Selftest complete", 'PASS')

    except (RuntimeError, AssertionError) as e:
        await ux_show_story("Test failed:\n" + str(e), 'FAIL')
示例#12
0
    def add(cls, prevout, amount):
        # protect privacy, compress a little, and save it.
        # - we know it's not yet in our lists
        key = cls.encode_key(prevout)

        # memory management: can't store very much, so trim as needed
        depth = HISTORY_SAVED
        if settings.capacity > 0.8:
            depth //= 2

        # also limit in-memory use
        cls.load_cache()
        if len(cls.runtime_cache) >= HISTORY_MAX_MEM:
            del cls.runtime_cache[0]

        # save new addition
        assert len(key) == ENCKEY_LEN
        assert amount > 0
        entry = key + cls.encode_value(prevout, amount)
        cls.runtime_cache.append(entry)

        # update what we're going to save long-term
        settings.set(cls.KEY, cls.runtime_cache[-depth:])
示例#13
0
    def capture_xpub(self):
        # track my xpubkey fingerprint & value in settings (not sensitive really)
        # - we share this on any USB connection
        from main import settings

        #print("capture xfp/xpub/chain")
        settings.set('xfp', self.node.my_fingerprint())
        settings.set('xpub', self.chain.serialize_public(self.node))
        settings.set('chain', self.chain.ctype)
示例#14
0
 def set_it(idx, text):
     settings.set('sens', idx)
     numpad.sensitivity = idx
示例#15
0
    xfp = sys.argv[sys.argv.index('--xfp') + 1]
    sim_defaults['xfp'] = unpack("<I", a2b_hex(xfp))[0]
    print("Override XFP: " + xfp2str(sim_defaults['xfp']))

if '--seed' in sys.argv:
    # --xfp aabbccdd   => pretend we know that key (won't be able to sign)
    from ustruct import unpack
    from utils import xfp2str
    from seed import set_seed_value
    from main import pa, settings

    words = sys.argv[sys.argv.index('--seed') + 1].split(' ')
    assert len(words) == 24, "Expected 24 space-separated words: add some quotes"
    pa.pin = b'12-12'
    set_seed_value(words)
    settings.set('terms_ok', 1)
    settings.set('_skip_pin', '12-12')
    settings.set('chain', 'XTN')
    print("Seed phrase set, resulting XFP: " + xfp2str(settings.get('xfp')))

if '-g' in sys.argv:
    # do login
    sim_defaults.pop('_skip_pin', 0)

if '--nick' in sys.argv:
    nick = sys.argv[sys.argv.index('--nick') + 1]
    sim_defaults['nick'] = nick
    sim_defaults['terms_ok'] = 1
    sim_defaults.pop('_skip_pin', 0)

if '--delay' in sys.argv:
示例#16
0
# load up the simulator w/ indicated list of seed words
import tcc, main
from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from main import settings, pa
import stash
from seed import set_seed_value
from utils import xfp2str

tn = chains.BitcoinTestnet

if 1:
    stash.bip39_passphrase = ''
    settings.current = sim_defaults
    settings.overrides.clear()
    settings.set('chain', 'XTN')
    settings.set('words', True)
    settings.set('terms_ok', True)
    settings.set('idle_to', 3600)

    set_seed_value(main.WORDS)

    print("New key in effect: %s" % settings.get('xpub', 'MISSING'))
    print("Fingerprint: %s" % xfp2str(settings.get('xfp', 0)))

示例#17
0
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()
示例#18
0
 def set_idle_timeout(idx, text):
     settings.set('idle_to', va[idx])
示例#19
0
# run manually with:
#   execfile('../../testing/devtest/nvram.py')

from ubinascii import hexlify as b2a_hex
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
示例#20
0
 def set(idx, text):
     settings.set('fee_limit', va[idx])
示例#21
0
 def set_del_psbt(idx, text):
     settings.set('del', idx)
示例#22
0
 def xset(idx, text):
     from main import settings
     settings.set('pms', idx)
示例#23
0
 def set_login_countdown(idx, text):
     settings.set('lgto', va[idx])
示例#24
0
# load up the simulator w/ indicated list of seed words
import tcc, main
from sim_settings import sim_defaults
import stash, chains
from h import b2a_hex
from main import settings, pa
from stash import SecretStash, SensitiveValues
from seed import set_seed_value

tn = chains.BitcoinTestnet

if 1:
    settings.current = sim_defaults
    settings.set('chain', 'XTN')

    set_seed_value(main.WORDS)

    print("New key in effect: %s" % settings.get('xpub', 'MISSING'))
    print("Fingerprint: 0x%08x" % settings.get('xfp', 0))

    #assert settings.get('xfp', 0) == node.my_fingerprint()