From 6c1b204938109de29fa53cc4e445b822f622826d Mon Sep 17 00:00:00 2001 From: drebs Date: Tue, 21 May 2013 20:33:48 -0300 Subject: Improve _has_secret() logic and tests. --- src/leap/soledad/__init__.py | 39 +++++++++++++++++------------- src/leap/soledad/tests/__init__.py | 5 ++-- src/leap/soledad/tests/test_crypto.py | 43 ++++++++++++++++++++++++++++++++++ src/leap/soledad/tests/test_soledad.py | 15 ++++++++---- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/src/leap/soledad/__init__.py b/src/leap/soledad/__init__.py index ab8c03b4..b0acb91a 100644 --- a/src/leap/soledad/__init__.py +++ b/src/leap/soledad/__init__.py @@ -131,6 +131,11 @@ class Soledad(object): finished synchronizing with remote replica. """ + LOCAL_DATABASE_FILE_NAME = 'soledad.u1db' + """ + The name of the local SQLCipher U1DB database file. + """ + STORAGE_SECRETS_FILE_NAME = "soledad.json" """ The name of the file where the storage secrets will be stored. @@ -187,7 +192,7 @@ class Soledad(object): """ def __init__(self, uuid, passphrase, secrets_path, local_db_path, - server_url, cert_file, auth_token=None): + server_url, cert_file, auth_token=None, secret_id=None): """ Initialize configuration, cryptographic keys and dbs. @@ -216,7 +221,7 @@ class Soledad(object): self._passphrase = passphrase # init crypto variables self._secrets = {} - self._secret_id = None + self._secret_id = secret_id # init config (possibly with default values) self._init_config(secrets_path, local_db_path, server_url) self._set_token(auth_token) @@ -239,7 +244,7 @@ class Soledad(object): self._local_db_path = local_db_path if self._local_db_path is None: self._local_db_path = os.path.join( - self.DEFAULT_PREFIX, 'soledad.u1db') + self.DEFAULT_PREFIX, self.LOCAL_DATABASE_FILE_NAME) # initialize server_url self._server_url = server_url leap_assert( @@ -399,9 +404,6 @@ class Soledad(object): } } } - - @raise leap.common.keymanager.errors.DecryptionFailed: Raised if could - not decrypt the secret with the given passphrase. """ # does the file exist in disk? if not os.path.isfile(self._secrets_path): @@ -422,18 +424,16 @@ class Soledad(object): @return: Whether there's a storage secret for symmetric encryption. @rtype: bool """ - # if the secret is already loaded, return true - if self._secret_id is not None and self._secret_id in self._secrets: - return True - # try to load from disk + if self._secret_id is None or self._secret_id not in self._secrets: + try: + self._load_secrets() # try to load from disk + except IOError, e: + logger.error('IOError: %s' % str(e)) try: - self._load_secrets() + self._get_storage_secret() return True - except DecryptionFailed: - logger.error('Could not decrypt storage secret.') - except IOError, e: - logger.error('IOError: %s' % str(e)) - return False + except: + return False def _gen_secret(self): """ @@ -954,6 +954,13 @@ class Soledad(object): uuid = property(_get_uuid, doc='The user uuid.') + def _get_secret_id(self): + return self._secret_id + + secret_id = property( + _get_secret_id, + doc='The active secret id.') + def _get_secrets_path(self): return self._secrets_path diff --git a/src/leap/soledad/tests/__init__.py b/src/leap/soledad/tests/__init__.py index 79ee69c4..00de687b 100644 --- a/src/leap/soledad/tests/__init__.py +++ b/src/leap/soledad/tests/__init__.py @@ -48,7 +48,7 @@ class BaseSoledadTest(BaseLeapTest): prefix='', secrets_path=Soledad.STORAGE_SECRETS_FILE_NAME, local_db_path='/soledad.u1db', server_url='', - cert_file=None): + cert_file=None, secret_id=None): def _put_doc_side_effect(doc): self._doc_put = doc @@ -68,7 +68,8 @@ class BaseSoledadTest(BaseLeapTest): secrets_path=self.tempdir+prefix+secrets_path, local_db_path=self.tempdir+prefix+local_db_path, server_url=server_url, # Soledad will fail if not given an url. - cert_file=cert_file) + cert_file=cert_file, + secret_id=secret_id) def assertGetEncryptedDoc( self, db, doc_id, doc_rev, content, has_conflicts): diff --git a/src/leap/soledad/tests/test_crypto.py b/src/leap/soledad/tests/test_crypto.py index 4c57e023..7b8f756a 100644 --- a/src/leap/soledad/tests/test_crypto.py +++ b/src/leap/soledad/tests/test_crypto.py @@ -27,6 +27,7 @@ try: import simplejson as json except ImportError: import json # noqa +import hashlib from leap.soledad.backends.leap_backend import ( @@ -204,9 +205,51 @@ class RecoveryDocumentTestCase(BaseSoledadTest): class CryptoMethodsTestCase(BaseSoledadTest): def test__gen_secret(self): + # instantiate and save secret_id + sol = self._soledad_instance(user='user@leap.se') + self.assertTrue(len(sol._secrets) == 1) + secret_id_1 = sol.secret_id + # assert id is hash of secret + self.assertTrue( + secret_id_1 == hashlib.sha256(sol.storage_secret).hexdigest()) + # generate new secret + secret_id_2 = sol._gen_secret() + self.assertTrue(secret_id_1 != secret_id_2) + # re-instantiate + sol = self._soledad_instance( + user='user@leap.se', + secret_id=secret_id_1) + # assert ids are valid + self.assertTrue(len(sol._secrets) == 2) + self.assertTrue(secret_id_1 in sol._secrets) + self.assertTrue(secret_id_2 in sol._secrets) + # assert format of secret 1 + self.assertTrue(sol.storage_secret is not None) + self.assertIsInstance(sol.storage_secret, str) + self.assertTrue(len(sol.storage_secret) == sol.GENERATED_SECRET_LENGTH) + # assert format of secret 2 + sol._set_secret_id(secret_id_2) + self.assertTrue(sol.storage_secret is not None) + self.assertIsInstance(sol.storage_secret, str) + self.assertTrue(len(sol.storage_secret) == sol.GENERATED_SECRET_LENGTH) + # assert id is hash of new secret + self.assertTrue( + secret_id_2 == hashlib.sha256(sol.storage_secret).hexdigest()) + + + def test__has_secret(self): sol = self._soledad_instance(user='user@leap.se', prefix='/3') self.assertTrue(sol._has_secret(), "Should have a secret at " "this point") + # setting secret id to None should not interfere in the fact we have a + # secret. + sol._set_secret_id(None) + self.assertTrue(sol._has_secret(), "Should have a secret at " + "this point") + # but not being able to decrypt correctly should + sol._secrets[sol.secret_id][sol.SECRET_KEY] = None + self.assertFalse(sol._has_secret()) + class MacAuthTestCase(BaseSoledadTest): diff --git a/src/leap/soledad/tests/test_soledad.py b/src/leap/soledad/tests/test_soledad.py index 6a4261c0..45cd7eb2 100644 --- a/src/leap/soledad/tests/test_soledad.py +++ b/src/leap/soledad/tests/test_soledad.py @@ -64,14 +64,21 @@ class AuxMethodsTestCase(BaseSoledadTest): """ Test if configuration defaults point to the correct place. """ - sol = Soledad( - 'leap@leap.se', passphrase='123', - secrets_path=None, local_db_path=None, - server_url='', cert_file=None) # otherwise Soledad will fail. + + class SoledadMock(Soledad): + + def __init__(self): + pass + + # instantiate without initializing so we just test _init_config() + sol = SoledadMock() + Soledad._init_config(sol, None, None, '') + # assert value of secrets_path self.assertEquals( os.path.join( sol.DEFAULT_PREFIX, Soledad.STORAGE_SECRETS_FILE_NAME), sol.secrets_path) + # assert value of local_db_path self.assertEquals( os.path.join(sol.DEFAULT_PREFIX, 'soledad.u1db'), sol.local_db_path) -- cgit v1.2.3