summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/src/leap/soledad/client/secrets.py122
-rw-r--r--client/src/leap/soledad/client/shared_db.py30
-rw-r--r--common/src/leap/soledad/common/errors.py61
3 files changed, 49 insertions, 164 deletions
diff --git a/client/src/leap/soledad/client/secrets.py b/client/src/leap/soledad/client/secrets.py
index e2a5a1d7..a72aac0d 100644
--- a/client/src/leap/soledad/client/secrets.py
+++ b/client/src/leap/soledad/client/secrets.py
@@ -33,7 +33,6 @@ from hashlib import sha256
from leap.soledad.common import soledad_assert
from leap.soledad.common import soledad_assert_type
from leap.soledad.common import document
-from leap.soledad.common import errors
from leap.soledad.client import events
from leap.soledad.client.crypto import encrypt_sym, decrypt_sym
@@ -81,6 +80,7 @@ class BootstrapSequenceError(SecretsException):
# Secrets handler
#
+
class SoledadSecrets(object):
"""
@@ -162,17 +162,12 @@ class SoledadSecrets(object):
:param shared_db: The shared database that stores user secrets.
:type shared_db: leap.soledad.client.shared_db.SoledadSharedDatabase
"""
- # XXX removed since not in use
- # We will pick the first secret available.
- # param secret_id: The id of the storage secret to be used.
-
self._uuid = uuid
self._userid = userid
self._passphrase = passphrase
self._secrets_path = secrets_path
self._shared_db = shared_db
self._secrets = {}
-
self._secret_id = None
def bootstrap(self):
@@ -197,47 +192,19 @@ class SoledadSecrets(object):
# STAGE 1 - verify if secrets exist locally
if not self._has_secret(): # try to load from local storage.
- # STAGE 2 - there are no secrets in local storage, so try to fetch
- # encrypted secrets from server.
- logger.info(
- 'Trying to fetch cryptographic secrets from shared recovery '
- 'database...')
-
- # --- start of atomic operation in shared db ---
-
- # obtain lock on shared db
- token = timeout = None
- try:
- token, timeout = self._shared_db.lock()
- except errors.AlreadyLockedError:
- raise BootstrapSequenceError('Database is already locked.')
- except errors.LockTimedOutError:
- raise BootstrapSequenceError('Lock operation timed out.')
+ # STAGE 2 - there are no secrets in local storage and this is the
+ # first time we are running soledad with the specified
+ # secrets_path. Try to fetch encrypted secrets from
+ # server.
+ self._download_crypto_secrets()
- self._get_or_gen_crypto_secrets()
+ if not self._has_secret():
- # release the lock on shared db
- try:
- self._shared_db.unlock(token)
- self._shared_db.close()
- except errors.NotLockedError:
- # for some reason the lock expired. Despite that, secret
- # loading or generation/storage must have been executed
- # successfully, so we pass.
- pass
- except errors.InvalidTokenError:
- # here, our lock has not only expired but also some other
- # client application has obtained a new lock and is currently
- # doing its thing in the shared database. Using the same
- # reasoning as above, we assume everything went smooth and
- # pass.
- pass
- except Exception as e:
- logger.error("Unhandled exception when unlocking shared "
- "database.")
- logger.exception(e)
-
- # --- end of atomic operation in shared db ---
+ # STAGE 3 - there are no secrets in server also, so we want to
+ # generate the secrets and store them in the remote
+ # db.
+ self._gen_crypto_secrets()
+ self._upload_crypto_secrets()
def _has_secret(self):
"""
@@ -295,13 +262,14 @@ class SoledadSecrets(object):
self._store_secrets()
self._put_secrets_in_shared_db()
- def _get_or_gen_crypto_secrets(self):
+ def _download_crypto_secrets(self):
"""
- Retrieves or generates the crypto secrets.
-
- :raises BootstrapSequenceError: Raised when unable to store secrets in
- shared database.
+ Downloads the crypto secrets.
"""
+ logger.info(
+ 'Trying to fetch cryptographic secrets from shared recovery '
+ 'database...')
+
if self._shared_db.syncable:
doc = self._get_secrets_from_shared_db()
else:
@@ -314,31 +282,39 @@ class SoledadSecrets(object):
_, active_secret = self._import_recovery_document(doc.content)
self._maybe_set_active_secret(active_secret)
self._store_secrets() # save new secrets in local file
- else:
- # STAGE 3 - there are no secrets in server also, so
- # generate a secret and store it in remote db.
- logger.info(
- 'No cryptographic secrets found, creating new '
- ' secrets...')
- self.set_secret_id(self._gen_secret())
- if self._shared_db.syncable:
+ def _gen_crypto_secrets(self):
+ """
+ Generate the crypto secrets.
+ """
+ logger.info('No cryptographic secrets found, creating new secrets...')
+ secret_id = self._gen_secret()
+ self.set_secret_id(secret_id)
+
+ def _upload_crypto_secrets(self):
+ """
+ Send crypto secrets to shared db.
+
+ :raises BootstrapSequenceError: Raised when unable to store secrets in
+ shared database.
+ """
+ if self._shared_db.syncable:
+ try:
+ self._put_secrets_in_shared_db()
+ except Exception as ex:
+ # storing generated secret in shared db failed for
+ # some reason, so we erase the generated secret and
+ # raise.
try:
- self._put_secrets_in_shared_db()
- except Exception as ex:
- # storing generated secret in shared db failed for
- # some reason, so we erase the generated secret and
- # raise.
- try:
- os.unlink(self._secrets_path)
- except OSError as e:
- if e.errno != errno.ENOENT:
- # no such file or directory
- logger.exception(e)
- logger.exception(ex)
- raise BootstrapSequenceError(
- 'Could not store generated secret in the shared '
- 'database, bailing out...')
+ os.unlink(self._secrets_path)
+ except OSError as e:
+ if e.errno != errno.ENOENT:
+ # no such file or directory
+ logger.exception(e)
+ logger.exception(ex)
+ raise BootstrapSequenceError(
+ 'Could not store generated secret in the shared '
+ 'database, bailing out...')
#
# Shared DB related methods
diff --git a/client/src/leap/soledad/client/shared_db.py b/client/src/leap/soledad/client/shared_db.py
index 6abf8ea3..a1d95fbe 100644
--- a/client/src/leap/soledad/client/shared_db.py
+++ b/client/src/leap/soledad/client/shared_db.py
@@ -151,33 +151,3 @@ class SoledadSharedDatabase(http_database.HTTPDatabase, TokenBasedAuth):
http_database.HTTPDatabase.__init__(self, url, document_factory,
creds)
self._uuid = uuid
-
- def lock(self):
- """
- Obtain a lock on document with id C{doc_id}.
-
- :return: A tuple containing the token to unlock and the timeout until
- lock expiration.
- :rtype: (str, float)
-
- :raise HTTPError: Raised if any HTTP error occurs.
- """
- if self.syncable:
- res, headers = self._request_json(
- 'PUT', ['lock', self._uuid], body={})
- return res['token'], res['timeout']
- else:
- return None, None
-
- def unlock(self, token):
- """
- Release the lock on shared database.
-
- :param token: The token returned by a previous call to lock().
- :type token: str
-
- :raise HTTPError:
- """
- if self.syncable:
- _, _ = self._request_json(
- 'DELETE', ['lock', self._uuid], params={'token': token})
diff --git a/common/src/leap/soledad/common/errors.py b/common/src/leap/soledad/common/errors.py
index 0b6bb4e6..76a7240d 100644
--- a/common/src/leap/soledad/common/errors.py
+++ b/common/src/leap/soledad/common/errors.py
@@ -71,67 +71,6 @@ class InvalidAuthTokenError(errors.Unauthorized):
#
-# LockResource errors
-#
-
-@register_exception
-class InvalidTokenError(SoledadError):
-
- """
- Exception raised when trying to unlock shared database with invalid token.
- """
-
- wire_description = "unlock unauthorized"
- status = 401
-
-
-@register_exception
-class NotLockedError(SoledadError):
-
- """
- Exception raised when trying to unlock shared database when it is not
- locked.
- """
-
- wire_description = "lock not found"
- status = 404
-
-
-@register_exception
-class AlreadyLockedError(SoledadError):
-
- """
- Exception raised when trying to lock shared database but it is already
- locked.
- """
-
- wire_description = "lock is locked"
- status = 403
-
-
-@register_exception
-class LockTimedOutError(SoledadError):
-
- """
- Exception raised when timing out while trying to lock the shared database.
- """
-
- wire_description = "lock timed out"
- status = 408
-
-
-@register_exception
-class CouldNotObtainLockError(SoledadError):
-
- """
- Exception raised when timing out while trying to lock the shared database.
- """
-
- wire_description = "error obtaining lock"
- status = 500
-
-
-#
# SoledadBackend errors
# u1db error statuses also have to be updated
http_errors.ERROR_STATUSES = set(