Exemplo n.º 1
0
    def delete(cls, username):
        # remove a user. simple. no checking
        from main import settings

        u = cls.get()
        u.pop(username, None)
        settings.put(KEY, u)
Exemplo n.º 2
0
    def create(cls, username, auth_mode, secret):
        # create new user:
        # - username must be unique
        # - if secret is empty, we pick it and return choice
        # - show QR of secret (for TOTP/HOTP) if
        from main import settings

        qr_mode = bool(auth_mode & USER_AUTH_SHOW_QR)
        if qr_mode:
            auth_mode &= ~USER_AUTH_SHOW_QR
            assert not secret

        assert auth_mode in {USER_AUTH_TOTP, USER_AUTH_HOTP, USER_AUTH_HMAC}

        # validate username;
        assert 1 < len(username) <= MAX_USERNAME_LEN, 'badlen'
        assert username[0] != '_', 'reserved'

        # We don't care if it exists, because then it's an update?
        # - but can safely let them reset the counter/totp level??
        # - not sure, so force them to delete on-device first
        # - this check does not allow brute-force search for names (because
        existing = cls.lookup(username)
        assert not existing, "exists"

        if not secret:
            secret, picked = cls.pick_secret(auth_mode)
        else:
            picked = ''
            if auth_mode == USER_AUTH_HMAC:
                assert len(secret) == 32
            else:
                assert len(secret) in {10, 20}

        # save
        u = cls.get()
        assert len(u) < MAX_NUMBER_USERS, 'too many'
        u[username] = [auth_mode, b32encode(secret), 0]
        settings.put(KEY, u)

        if qr_mode:
            # can only show up to 42 chars, and secret is 16, required overhead is 23 => 39 min
            # - can't fit any meta data, like username or our serial # in there
            # - HOTP not compliant because 'counter=0' not included (works in FreeOTP)
            from ux import QRDisplay, abort_and_push, the_ux

            if auth_mode == USER_AUTH_HMAC:
                qr = picked
            else:
                qr = 'otpauth://{m}otp/CC?secret={s}'.format(
                    s=picked, m=('t' if auth_mode == USER_AUTH_TOTP else 'h'))

            o = QRDisplay([qr], False, sidebar=(picked, 4))
            abort_and_push(o)

            picked = ''

        return picked
Exemplo n.º 3
0
async def choose_first_address(*a):
    # Choose from a truncated list of index 0 common addresses, remember
    # the last address the user selected and use it as the default
    from main import settings, dis
    chain = chains.current_chain()

    dis.fullscreen('Wait...')

    with stash.SensitiveValues() as sv:

        def truncate_address(addr):
            # Truncates address to width of screen, replacing middle chars
            middle = "-"
            leftover = SCREEN_CHAR_WIDTH - len(middle)
            start = addr[0:(leftover + 1) // 2]
            end = addr[len(addr) - (leftover // 2):]
            return start + middle + end

        # Create list of choices (address_index_0, path, addr_fmt)
        choices = []
        for name, path, addr_fmt in chains.CommonDerivations:
            if '{coin_type}' in path:
                path = path.replace('{coin_type}', str(chain.b44_cointype))
            subpath = path.format(account=0, change=0, idx=0)
            node = sv.derive_path(subpath, register=False)
            address = chain.address(node, addr_fmt)
            choices.append((truncate_address(address), path, addr_fmt))

            dis.progress_bar_show(len(choices) / len(chains.CommonDerivations))

        stash.blank_object(node)

    picked = None

    async def clicked(_1, _2, item):
        if picked is None:
            picked = item.arg
        the_ux.pop()

    items = [
        MenuItem(address, f=clicked, arg=i)
        for i, (address, path, addr_fmt) in enumerate(choices)
    ]
    menu = MenuSystem(items)
    menu.goto_idx(settings.get('axi', 0))
    the_ux.push(menu)

    await menu.interact()

    if picked is None:
        return None

    # update last clicked address
    settings.put('axi', picked)
    address, path, addr_fmt = choices[picked]

    return (path, addr_fmt)
Exemplo n.º 4
0
    def capture_xpub(self):
        # track my xpubkey fingerprint & value in settings (not sensitive really)
        # - we share these on any USB connection
        from main import settings

        # Implicit in the values is the BIP39 encryption passphrase,
        # which we might not want to actually store.
        xfp = self.node.my_fingerprint()
        xpub = self.chain.serialize_public(self.node)

        if self._bip39pw:
            settings.put_volatile('xfp', xfp)
            settings.put_volatile('xpub', xpub)
        else:
            settings.overrides.clear()
            settings.put('xfp', xfp)
            settings.put('xpub', xpub)

        settings.put('chain', self.chain.ctype)
        settings.put('words', (self.mode == 'words'))
Exemplo n.º 5
0
 async def pick_multisig(self, _1, menu_idx, item):
     from main import settings
     ms_wallet = item.arg
     settings.put('axi', menu_idx)       # update last clicked address
     await self.show_n_addresses(None, None, ms_wallet)
Exemplo n.º 6
0
 async def pick_single(self, _1, menu_idx, item):
     from main import settings
     settings.put('axi', menu_idx)       # update last clicked address
     path, addr_fmt = item.arg
     await self.show_n_addresses(path, addr_fmt, None)