Exemple #1
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
        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 abort_and_push, the_ux
            from qrs import QRDisplaySingle

            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 = QRDisplaySingle([qr], False, sidebar=(picked, 4))
            abort_and_push(o)

            picked = ''

        return picked
Exemple #2
0
    def capture_xpub(self):
        # track my xpubkey fingerprint & value in settings (not sensitive really)
        # - we share these on any USB connection
        from nvstore import settings

        # Implicit in the values is the BIP-39 encryption passphrase,
        # which we might not want to actually store.
        xfp = swab32(self.node.my_fp())
        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'))
Exemple #3
0
 async def pick_multisig(self, _1, menu_idx, item):
     ms_wallet = item.arg
     settings.put('axi', menu_idx)       # update last clicked address
     await self.show_n_addresses(None, None, ms_wallet)
Exemple #4
0
 async def pick_single(self, _1, menu_idx, item):
     settings.put('axi', menu_idx)       # update last clicked address
     path, addr_fmt = item.arg
     await self.show_n_addresses(path, addr_fmt, None)
Exemple #5
0
 def delete(cls, username):
     # remove a user. simple. no checking
     u = cls.get()
     u.pop(username, None)
     settings.put(KEY, u)