summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/leap/bitmask/bonafide/_srp.py16
-rw-r--r--src/leap/bitmask/bonafide/session.py12
-rw-r--r--tests/unit/bonafide/test_users.py34
3 files changed, 61 insertions, 1 deletions
diff --git a/src/leap/bitmask/bonafide/_srp.py b/src/leap/bitmask/bonafide/_srp.py
index 3939c5a..1ec40d8 100644
--- a/src/leap/bitmask/bonafide/_srp.py
+++ b/src/leap/bitmask/bonafide/_srp.py
@@ -144,7 +144,7 @@ class SRPSignupMechanism(object):
class SRPPasswordChangeMechanism(object):
"""
- Implement a protocol-agnostic SRP passord change mechanism.
+ Implement a protocol-agnostic SRP password change mechanism.
"""
def get_password_params(self, username, password):
@@ -155,6 +155,20 @@ class SRPPasswordChangeMechanism(object):
return user_data
+class SRPRecoveryCodeUpdateMechanism(object):
+
+ """
+ Implement a protocol-agnostic SRP recovery code update mechanism.
+ """
+
+ def get_recovery_code_params(self, username, recovery_code):
+ salt, verifier = _get_salt_verifier(username, recovery_code)
+ user_data = {
+ 'user[recovery_code_salt]': binascii.hexlify(salt),
+ 'user[recovery_code_verifier]': binascii.hexlify(verifier)}
+ return user_data
+
+
def _get_salt_verifier(username, password):
return srp.create_salted_verification_key(bytes(username), bytes(password),
srp.SHA256, srp.NG_1024)
diff --git a/src/leap/bitmask/bonafide/session.py b/src/leap/bitmask/bonafide/session.py
index 5a743e9..732afe5 100644
--- a/src/leap/bitmask/bonafide/session.py
+++ b/src/leap/bitmask/bonafide/session.py
@@ -69,6 +69,7 @@ class Session(object):
self._srp_auth = _srp.SRPAuthMechanism(username, password)
self._srp_signup = _srp.SRPSignupMechanism()
self._srp_password = _srp.SRPPasswordChangeMechanism()
+ self._srp_recovery_code = _srp.SRPRecoveryCodeUpdateMechanism()
self._token = None
self._uuid = None
@@ -139,6 +140,17 @@ class Session(object):
self._srp_auth = _srp.SRPAuthMechanism(self.username, password)
defer.returnValue(OK)
+ @_auth_required
+ @defer.inlineCallbacks
+ def update_recovery_code(self, recovery_code):
+ uri = self._api.get_update_user_uri(uid=self._uuid)
+ met = self._api.get_update_user_method()
+ params = self._srp_recovery_code.get_recovery_code_params(
+ self.username, recovery_code)
+ update = yield self._request(self._agent, uri, values=params,
+ method=met)
+ defer.returnValue(update)
+
# User certificates
def get_vpn_cert(self):
diff --git a/tests/unit/bonafide/test_users.py b/tests/unit/bonafide/test_users.py
new file mode 100644
index 0000000..952e73d
--- /dev/null
+++ b/tests/unit/bonafide/test_users.py
@@ -0,0 +1,34 @@
+from mock import patch, ANY
+
+from twisted.internet import defer
+from twisted.trial import unittest
+from twisted.cred.credentials import UsernamePassword
+
+from leap.bitmask.bonafide.provider import Api
+from leap.bitmask.bonafide.session import Session
+
+
+class UsersTest(unittest.TestCase):
+
+ @patch('leap.bitmask.bonafide.session.Session.is_authenticated')
+ @patch('leap.bitmask.bonafide.session.cookieAgentFactory')
+ @patch('leap.bitmask.bonafide.session.httpRequest')
+ @defer.inlineCallbacks
+ def test_recovery_code_creation(self,
+ mock_http_request,
+ mock_cookie_agent,
+ mock_is_authenticated):
+ api = Api('https://api.test:4430')
+ credentials = UsernamePassword('username', 'password')
+
+ mock_is_authenticated.return_value = True
+ session = Session(credentials, api, 'fake path')
+ session._uuid = '123'
+
+ response = yield session.update_recovery_code('RECOVERY_CODE')
+ mock_http_request.assert_called_with(
+ ANY, 'https://api.test:4430/1/users/123',
+ method='PUT',
+ token=None,
+ values={'user[recovery_code_salt]': ANY,
+ 'user[recovery_code_verifier]': ANY})