Exemplo n.º 1
0
    def make_menu(self):
        from menu import MenuItem, MenuSystem
        from actions import goto_top_menu
        from ux import ux_show_story
        from seed import set_bip39_passphrase
        import pyb

        # Very quick check for card not present case.
        if not pyb.SDCard().present():
            return None

        # Read file, decrypt and make a menu to show; OR return None
        # if any error hit.
        try:
            with CardSlot() as card:

                self._calc_key(card)
                if not self.key: return None

                data = self._read(card)

                if not data: return None

        except CardMissingError:
            # not an error: they just aren't using feature
            return None

        # We have a list of xfp+pw fields. Make a menu.

        # Challenge: we need to hint at which is which, but don't want to
        # show the password on-screen.
        # - simple algo:
        #   - show either first N or last N chars only
        #   - pick which set which is all-unique, if neither, try N+1
        #
        pws = []
        for i in data:
            p = i.get('pw')
            if p not in pws:
                pws.append(p)

        for N in range(1, 8):
            parts = [
                i[0:N] + ('*' * (len(i) - N if len(i) > N else 0)) for i in pws
            ]
            if len(set(parts)) == len(pws): break
            parts = [('*' * (len(i) - N if len(i) > N else 0)) + i[-N:]
                     for i in pws]
            if len(set(parts)) == len(pws): break
        else:
            # give up: show it all!
            parts = pws

        async def doit(menu, idx, item):
            # apply the password immediately and drop them at top menu
            set_bip39_passphrase(data[idx]['pw'])

            from main import settings
            from utils import xfp2str
            xfp = settings.get('xfp')

            # verification step; I don't see any way for this to go wrong
            assert xfp == data[idx]['xfp']

            # feedback that it worked
            await ux_show_story("Passphrase restored.",
                                title="[%s]" % xfp2str(xfp))

            goto_top_menu()

        return MenuSystem(
            (MenuItem(label or '(empty)', f=doit) for label in parts))
Exemplo n.º 2
0
async def file_picker(msg,
                      suffix=None,
                      min_size=1,
                      max_size=1000000,
                      taster=None,
                      choices=None,
                      escape=None,
                      none_msg=None):
    # present a menu w/ a list of files... to be read
    # - optionally, enforce a max size, and provide a "tasting" function
    # - if msg==None, don't prompt, just do the search and return list
    # - if choices is provided; skip search process
    # - escape: allow these chars to skip picking process
    from menu import MenuSystem, MenuItem
    import uos
    from utils import get_filesize

    if choices is None:
        choices = []
        try:
            with CardSlot() as card:
                sofar = set()

                for path in card.get_paths():
                    for fn, ftype, *var in uos.ilistdir(path):
                        if ftype == 0x4000:
                            # ignore subdirs
                            continue

                        if suffix and not fn.lower().endswith(suffix):
                            # wrong suffix
                            continue

                        if fn[0] == '.': continue

                        full_fname = path + '/' + fn

                        # Conside file size
                        # sigh, OS/filesystem variations
                        file_size = var[1] if len(var) == 2 else get_filesize(
                            full_fname)

                        if not (min_size <= file_size <= max_size):
                            continue

                        if taster is not None:
                            try:
                                yummy = taster(full_fname)
                            except IOError:
                                #print("fail: %s" % full_fname)
                                yummy = False

                            if not yummy:
                                continue

                        label = fn
                        while label in sofar:
                            # just the file name isn't unique enough sometimes?
                            # - shouldn't happen anymore now that we dno't support internal FS
                            # - unless we do muliple paths
                            label += path.split('/')[-1] + '/' + fn

                        sofar.add(label)
                        choices.append((label, path, fn))

        except CardMissingError:
            # don't show anything if we're just gathering data
            if msg is not None:
                await needs_microsd()
            return None

    if msg is None:
        return choices

    if not choices:
        msg = none_msg or 'Unable to find any suitable files for this operation. '

        if not none_msg:
            if suffix:
                msg += 'The filename must end in "%s". ' % suffix

            msg += '\n\nMaybe insert (another) SD card and try again?'

        await ux_show_story(msg)
        return

    # tell them they need to pick; can quit here too, but that's obvious.
    if len(choices) != 1:
        msg += '\n\nThere are %d files to pick from.' % len(choices)
    else:
        msg += '\n\nThere is only one file to pick from.'

    ch = await ux_show_story(msg, escape=escape)
    if escape and ch in escape: return ch
    if ch == 'x': return

    picked = []

    async def clicked(_1, _2, item):
        picked.append('/'.join(item.arg))
        the_ux.pop()

    items = [
        MenuItem(label, f=clicked, arg=(path, fn))
        for label, path, fn in choices
    ]

    if 0:
        # don't like; and now showing count on previous page
        if len(choices) == 1:
            # if only one choice, we could make the choice for them ... except very confusing
            items.append(MenuItem('  (one file)', f=None))
        else:
            items.append(MenuItem('  (%d files)' % len(choices), f=None))

    menu = MenuSystem(items)
    the_ux.push(menu)

    await menu.interact()

    return picked[0] if picked else None
Exemplo n.º 3
0
async def initial_pin_setup(*a):
    # First time they select a PIN of any type.
    from login import LoginUX
    lll = LoginUX()
    title = 'Choose PIN'

    ch = await ux_show_story('''\
Pick the main wallet's PIN code now. Be more clever, but an example:

123-4567

It has two parts: prefix (123-) and suffix (-4567). \
Each part must between 2 to 6 digits long. Total length \
can be as long as 12 digits.

The prefix part determines the anti-phishing words you will \
see each time you login.

Your new PIN protects access to \
this Coldcard device and is not a factor in the wallet's \
seed words or private keys.

THERE IS ABSOLUTELY NO WAY TO RECOVER A FORGOTTEN PIN! Write it down.
''', title=title)
    if ch != 'y': return

    while 1:
        ch = await ux_show_story('''\
There is ABSOLUTELY NO WAY to 'reset the PIN' or 'factory reset' the Coldcard if you forget the PIN.

DO NOT FORGET THE PIN CODE.
 
Press 6 to prove you read to the end of this message.''', title='WARNING', escape='6')

        if ch == 'x': return
        if ch == '6': break

    # do the actual picking
    pin = await lll.get_new_pin(title)
    del lll

    if pin is None: return

    # A new pin is to be set!
    from main import pa, dis, settings, loop
    dis.fullscreen("Saving...")

    try:
        assert pa.is_blank()

        pa.change(new_pin=pin)

        # check it? kinda, but also get object into normal "logged in" state
        pa.setup(pin)
        ok = pa.login()
        assert ok

        # must re-read settings after login, because they are encrypted
        # with a key derived from the main secret.
        settings.set_key()
        settings.load()
    except Exception as e:
        print("Exception: %s" % e)

    # Allow USB protocol, now that we are auth'ed
    from usb import enable_usb
    enable_usb(loop, False)

    from menu import MenuSystem
    from flow import EmptyWallet
    return MenuSystem(EmptyWallet)