diff options
| author | Kali Kaneko (leap communications) <kali@leap.se> | 2016-10-03 17:40:09 -0400 | 
|---|---|---|
| committer | Kali Kaneko (leap communications) <kali@leap.se> | 2016-10-04 11:48:30 -0400 | 
| commit | af27100e35f30f91f3c8f3eb4b8fcef978d11eae (patch) | |
| tree | 92e1bdb9ebdb8e00aa84dbfefbda1b75e6cb883c | |
| parent | ff3ed1e9418eab21fd42bb5ddd96a3851a25801c (diff) | |
[feature] handle invite codes
In the command line, --invitecode is a new optional parameter to
the command "user create".
bonafide service handles the invite codes.
javascript library should be updated accordingly
- Resolves: #7550
| -rw-r--r-- | docs/changelog-next.rst | 1 | ||||
| -rw-r--r-- | src/leap/bitmask/bonafide/_protocol.py | 8 | ||||
| -rw-r--r-- | src/leap/bitmask/bonafide/_srp.py | 24 | ||||
| -rw-r--r-- | src/leap/bitmask/bonafide/service.py | 5 | ||||
| -rw-r--r-- | src/leap/bitmask/bonafide/session.py | 4 | ||||
| -rw-r--r-- | src/leap/bitmask/cli/user.py | 39 | ||||
| -rw-r--r-- | src/leap/bitmask/core/dispatcher.py | 13 | 
7 files changed, 74 insertions, 20 deletions
| diff --git a/docs/changelog-next.rst b/docs/changelog-next.rst index 41414d8..2337df5 100644 --- a/docs/changelog-next.rst +++ b/docs/changelog-next.rst @@ -10,6 +10,7 @@ I've added a new category `Misc` so we can track doc/style/packaging stuff.  Features  ~~~~~~~~ +- `#7550 <https://leap.se/code/issues/7550>`_: Add ability to use invite codes during signup  - `#7965 <https://leap.se/code/issues/7965>`_: Add basic keymanagement to the cli.  - `#8265 <https://leap.se/code/issues/8265>`_: Add a REST API and bitmask.js library for it.  - `#8400 <https://leap.se/code/issues/8400>`_: Add manual provider registration. diff --git a/src/leap/bitmask/bonafide/_protocol.py b/src/leap/bitmask/bonafide/_protocol.py index 3572cbf..1112550 100644 --- a/src/leap/bitmask/bonafide/_protocol.py +++ b/src/leap/bitmask/bonafide/_protocol.py @@ -77,16 +77,16 @@ class BonafideProtocol(object):      # Service public methods -    def do_signup(self, full_id, password, autoconf=False): +    def do_signup(self, full_id, password, invite=None, autoconf=False):          log.msg('SIGNUP for %s' % full_id)          _, provider_id = config.get_username_and_provider(full_id)          provider = config.Provider(provider_id, autoconf=autoconf)          d = provider.callWhenReady( -            self._do_signup, provider, full_id, password) +            self._do_signup, provider, full_id, password, invite)          return d -    def _do_signup(self, provider, full_id, password): +    def _do_signup(self, provider, full_id, password, invite):          # XXX check it's unauthenticated          def return_user(result, _session): @@ -97,7 +97,7 @@ class BonafideProtocol(object):          username, _ = config.get_username_and_provider(full_id)          # XXX get deferred?          session = self._get_session(provider, full_id, password) -        d = session.signup(username, password) +        d = session.signup(username, password, invite)          d.addCallback(return_user, session)          d.addErrback(self._del_session_errback, full_id)          return d diff --git a/src/leap/bitmask/bonafide/_srp.py b/src/leap/bitmask/bonafide/_srp.py index 34a75a5..3f69b33 100644 --- a/src/leap/bitmask/bonafide/_srp.py +++ b/src/leap/bitmask/bonafide/_srp.py @@ -19,12 +19,17 @@  SRP Authentication.  """ +from twisted.logger import Logger +  import binascii  import json  import srp +log = Logger() + +  class SRPAuthMechanism(object):      """ @@ -100,19 +105,34 @@ class SRPSignupMechanism(object):      Implement a protocol-agnostic SRP Registration mechanism.      """ -    def get_signup_params(self, username, password): +    def get_signup_params(self, username, password, invite=None):          salt, verifier = _get_salt_verifier(username, password)          user_data = {              'user[login]': username,              'user[password_salt]': binascii.hexlify(salt),              'user[password_verifier]': binascii.hexlify(verifier)} +        if invite is not None: +            user_data.update({'user[invite_code]': invite})          return user_data      def process_signup(self, signup_response):          signup = json.loads(signup_response)          errors = signup.get('errors')          if errors: -            msg = 'username ' + errors.get('login')[0] +            errmsg = json.dumps(errors) +            log.error('Oops! Errors during signup: {data!r}', data=errmsg) +            msg = errors.get('invite_code') +            if msg: +                msg = msg[0] +            else: +                msg = errors.get('login') +                if msg: +                    # there is a bug  https://leap.se/code/issues/8504 +                    # the server tells us 'has already been taken' several +                    # times +                    msg = 'username ' + msg[0] +                else: +                    msg = 'unknown signup error'              raise SRPRegistrationError(msg)          else:              username = signup.get('login') diff --git a/src/leap/bitmask/bonafide/service.py b/src/leap/bitmask/bonafide/service.py index fbe6846..4e25172 100644 --- a/src/leap/bitmask/bonafide/service.py +++ b/src/leap/bitmask/bonafide/service.py @@ -85,8 +85,9 @@ class BonafideService(HookableService):              'srp_token': response[0], 'uuid': response[1]})          return d -    def do_signup(self, username, password, autoconf=False): -        d = self._bonafide.do_signup(username, password, autoconf) +    def do_signup(self, username, password, invite=None, autoconf=False): +        d = self._bonafide.do_signup( +            username, password, invite=invite, autoconf=autoconf)          d.addCallback(lambda response: {'signup': 'ok', 'user': response})          return d diff --git a/src/leap/bitmask/bonafide/session.py b/src/leap/bitmask/bonafide/session.py index abb697a..213e773 100644 --- a/src/leap/bitmask/bonafide/session.py +++ b/src/leap/bitmask/bonafide/session.py @@ -162,13 +162,13 @@ class Session(object):      # User management      @defer.inlineCallbacks -    def signup(self, username, password): +    def signup(self, username, password, invite=None):          # XXX should check that it_IS_NOT_authenticated          provider.validate_username(username)          uri = self._api.get_signup_uri()          met = self._api.get_signup_method()          params = self._srp_signup.get_signup_params( -            username, password) +            username, password, invite)          signup = yield self._request(self._agent, uri, values=params,                                       method=met) diff --git a/src/leap/bitmask/cli/user.py b/src/leap/bitmask/cli/user.py index 8d3484c..d1014ee 100644 --- a/src/leap/bitmask/cli/user.py +++ b/src/leap/bitmask/cli/user.py @@ -20,6 +20,7 @@ Bitmask Command Line interface: user  import argparse  import getpass  import sys +from copy import copy  from colorama import Fore @@ -50,9 +51,27 @@ SUBCOMMANDS:          self.data.append('user')      def create(self, raw_args): -        username = self.username(raw_args) -        passwd = self._getpass_twice() -        self.data += ['create', username, passwd, 'true'] +        args = tuple([command.appname] + sys.argv[1:4]) +        parser = argparse.ArgumentParser( +            description='Bitmask user', +            prog='%s %s %s  %s' % args) +        parser.add_argument('--invitecode', **_invitecode_kw) +        parser.add_argument('username', **_username_kw) + +        subargs = parser.parse_args(raw_args) + +        # username parsing is factored out, but won't +        # accept the optional parameters. so strip them. +        args = copy(raw_args) +        for (index, item) in enumerate(args): +            if item.startswith('--'): +                args.pop(index + 1) +                args.pop(index) + +        username = self.username(args) +        passwd = self.getpass_twice() +        self.data += ['create', username, passwd, +                      subargs.invite, 'true']          return self._send(printer=command.default_dict_printer)      def auth(self, raw_args): @@ -82,11 +101,10 @@ SUBCOMMANDS:          parser = argparse.ArgumentParser(              description='Bitmask user',              prog='%s %s %s' % args) -        parser.add_argument('username', nargs=1, -                            help='username ID, in the form <user@example.org>') +        parser.add_argument('username', **_username_kw)          subargs = parser.parse_args(raw_args) -        username = subargs.username[0] +        username = subargs.username          if not username:              self._error("Missing username ID but needed for this command")          if '@' not in username: @@ -110,3 +128,12 @@ SUBCOMMANDS:              if u['authenticated']:                  color = Fore.GREEN              print(color + u['userid'] + Fore.RESET) + +_username_kw = { +    'nargs': '?', +    'help': 'username ID, in the form <user@example.org>'} + +_invitecode_kw = { +    'dest': 'invite', +    'default': 'none', 'action': 'store', 'nargs': '?', 'type': str, +    'help': 'invite code, if needed to register with this provider'} diff --git a/src/leap/bitmask/core/dispatcher.py b/src/leap/bitmask/core/dispatcher.py index a2fd638..5b7b836 100644 --- a/src/leap/bitmask/core/dispatcher.py +++ b/src/leap/bitmask/core/dispatcher.py @@ -107,12 +107,17 @@ class UserCmd(SubCommand):      @register_method("{'signup': 'ok', 'user': str}")      def do_CREATE(self, bonafide, *parts): -        user, password = parts[2], parts[3] +        # params are: [user, create, full_id, password, invite, autoconf] +        user, password, invite = parts[2], parts[3], parts[4] + +        # TODO factor out null/bool conversion to a util function. +        if invite == 'none': +            invite = None          autoconf = False -        if len(parts) > 4: -            if parts[4] == 'true': +        if len(parts) > 5: +            if parts[5] == 'true':                  autoconf = True -        return bonafide.do_signup(user, password, autoconf) +        return bonafide.do_signup(user, password, invite, autoconf)      @register_method("{'logout': 'ok'}")      def do_LOGOUT(self, bonafide, *parts): | 
