summaryrefslogtreecommitdiff
path: root/src/leap/bitmask
diff options
context:
space:
mode:
authorKali Kaneko (leap communications) <kali@leap.se>2016-10-03 17:40:09 -0400
committerKali Kaneko (leap communications) <kali@leap.se>2016-10-04 11:48:30 -0400
commitaf27100e35f30f91f3c8f3eb4b8fcef978d11eae (patch)
tree92e1bdb9ebdb8e00aa84dbfefbda1b75e6cb883c /src/leap/bitmask
parentff3ed1e9418eab21fd42bb5ddd96a3851a25801c (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
Diffstat (limited to 'src/leap/bitmask')
-rw-r--r--src/leap/bitmask/bonafide/_protocol.py8
-rw-r--r--src/leap/bitmask/bonafide/_srp.py24
-rw-r--r--src/leap/bitmask/bonafide/service.py5
-rw-r--r--src/leap/bitmask/bonafide/session.py4
-rw-r--r--src/leap/bitmask/cli/user.py39
-rw-r--r--src/leap/bitmask/core/dispatcher.py13
6 files changed, 73 insertions, 20 deletions
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):