diff options
| author | kali <kali@leap.se> | 2013-01-25 01:55:04 +0900 | 
|---|---|---|
| committer | kali <kali@leap.se> | 2013-01-25 01:55:04 +0900 | 
| commit | b9cba4bc7b88420e0ee46a6f03dd4aa2fb1edd1e (patch) | |
| tree | 136fcde8955f00ac42ca2054a3108bd4bc0de064 | |
| parent | b093b632049e1cf4c61d714c025831fb8d373ed7 (diff) | |
| parent | d02402a147bbae945618befdb8a1a260a91ce7a6 (diff) | |
Merge branch 'develop' of ssh://leap.se/leap_client into develop
| -rw-r--r-- | pkg/test-requirements.pip | 1 | ||||
| -rw-r--r-- | src/leap/base/config.py | 9 | ||||
| -rw-r--r-- | src/leap/soledad/__init__.py | 4 | ||||
| -rw-r--r-- | src/leap/soledad/backends/leap_backend.py | 25 | ||||
| -rw-r--r-- | src/leap/soledad/backends/sqlcipher.py | 26 | ||||
| -rw-r--r-- | src/leap/soledad/tests/test_sqlcipher.py | 42 | ||||
| -rw-r--r-- | src/leap/soledad/util.py | 6 | 
7 files changed, 88 insertions, 25 deletions
| diff --git a/pkg/test-requirements.pip b/pkg/test-requirements.pip index edd53b16..d60439ea 100644 --- a/pkg/test-requirements.pip +++ b/pkg/test-requirements.pip @@ -6,6 +6,7 @@ nose  pep8==1.1  sphinx>=1.1.2  nose-exclude +tox  # for soledad * to be splitted *  nose2 diff --git a/src/leap/base/config.py b/src/leap/base/config.py index e235e5c3..7021cb0f 100644 --- a/src/leap/base/config.py +++ b/src/leap/base/config.py @@ -333,7 +333,14 @@ def validate_ip(ip_str):  def get_username(): -    return os.getlogin() +    try: +        return os.getlogin() +    except OSError as e: +        if e.message == "[Errno 22] Invalid argument": +            import pwd +            return pwd.getpwuid(os.getuid())[0] +        else: +            raise OSError(e.message)  def get_groupname(): diff --git a/src/leap/soledad/__init__.py b/src/leap/soledad/__init__.py index faacd70c..c83627f0 100644 --- a/src/leap/soledad/__init__.py +++ b/src/leap/soledad/__init__.py @@ -46,10 +46,6 @@ class Soledad(object):      # Management of secret for symmetric encryption      #------------------------------------------------------------------------- -    #------------------------------------------------------------------------- -    # Management of secret for symmetric encryption -    #------------------------------------------------------------------------- -      def _has_secret(self):          """          Verify if secret for symmetric encryption exists on local encrypted diff --git a/src/leap/soledad/backends/leap_backend.py b/src/leap/soledad/backends/leap_backend.py index 7e98dd45..ec26dca4 100644 --- a/src/leap/soledad/backends/leap_backend.py +++ b/src/leap/soledad/backends/leap_backend.py @@ -8,7 +8,6 @@ from u1db.remote import utils  from u1db.remote.http_target import HTTPSyncTarget  from u1db.remote.http_database import HTTPDatabase  from u1db.errors import BrokenSyncStream -from leap.soledad.util import GPGWrapper  import uuid @@ -29,9 +28,10 @@ class LeapDocument(Document):      """      def __init__(self, doc_id=None, rev=None, json='{}', has_conflicts=False, -                 encrypted_json=None, soledad=None): +                 encrypted_json=None, soledad=None, syncable=True):          super(LeapDocument, self).__init__(doc_id, rev, json, has_conflicts)          self._soledad = soledad +        self._syncable = syncable          if encrypted_json:              self.set_encrypted_json(encrypted_json) @@ -55,6 +55,18 @@ class LeapDocument(Document):          plaintext = self._soledad.decrypt_symmetric(self.doc_id, ciphertext)          return self.set_json(plaintext) +    def _get_syncable(self): +        return self._syncable + +    def _set_syncable(self, syncable=True): +        self._syncable = syncable + +    syncable = property( +        _get_syncable, +        _set_syncable, +        doc="Determine if document should be synced with server." +    ) +  class LeapDatabase(HTTPDatabase):      """Implement the HTTP remote database API to a Leap server.""" @@ -168,10 +180,11 @@ class LeapSyncTarget(HTTPSyncTarget):              ensure=ensure_callback is not None)          comma = ','          for doc, gen, trans_id in docs_by_generations: -            # encrypt before sending to server. -            size += prepare(id=doc.doc_id, rev=doc.rev, -                            content=doc.get_encrypted_json(), -                            gen=gen, trans_id=trans_id) +            if doc.syncable: +                # encrypt before sending to server. +                size += prepare(id=doc.doc_id, rev=doc.rev, +                                content=doc.get_encrypted_json(), +                                gen=gen, trans_id=trans_id)          entries.append('\r\n]')          size += len(entries[-1])          self._conn.putheader('content-length', str(size)) diff --git a/src/leap/soledad/backends/sqlcipher.py b/src/leap/soledad/backends/sqlcipher.py index 08b4df43..6cebcf7d 100644 --- a/src/leap/soledad/backends/sqlcipher.py +++ b/src/leap/soledad/backends/sqlcipher.py @@ -25,10 +25,11 @@ from u1db.backends.sqlite_backend import (      SQLitePartialExpandDatabase,  )  from u1db import ( -    Document,      errors,  ) +from leap.soledad.backends.leap_backend import LeapDocument +  def open(path, password, create=True, document_factory=None):      """Open a database at the given location. @@ -70,7 +71,7 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):          SQLCipherDatabase.set_pragma_key(self._db_handle, password)          self._real_replica_uid = None          self._ensure_schema() -        self._factory = document_factory or Document +        self._factory = document_factory or LeapDocument      def _check_if_db_is_encrypted(self, sqlite_file):          if not os.path.exists(sqlite_file): @@ -133,5 +134,26 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):          return Synchronizer(self, LeapSyncTarget(url, creds=creds),                              soledad=self._soledad).sync(autocreate=autocreate) +    def _extra_schema_init(self, c): +        c.execute( +            'ALTER TABLE document ' +            'ADD COLUMN syncable BOOL NOT NULL DEFAULT TRUE') + +    def _put_and_update_indexes(self, old_doc, doc): +        super(SQLCipherDatabase, self)._put_and_update_indexes(old_doc, doc) +        c = self._db_handle.cursor() +        c.execute('UPDATE document SET syncable=? WHERE doc_id=?', +                  (doc.syncable, doc.doc_id)) + +    def _get_doc(self, doc_id, check_for_conflicts=False): +        doc = super(SQLCipherDatabase, self)._get_doc(doc_id, +                                                      check_for_conflicts) +        if doc: +            c = self._db_handle.cursor() +            c.execute('SELECT syncable FROM document WHERE doc_id=?', +                      (doc.doc_id,)) +            doc.syncable = bool(c.fetchone()[0]) +        return doc +  SQLiteDatabase.register_implementation(SQLCipherDatabase) diff --git a/src/leap/soledad/tests/test_sqlcipher.py b/src/leap/soledad/tests/test_sqlcipher.py index d2fe0b11..a3ab35b6 100644 --- a/src/leap/soledad/tests/test_sqlcipher.py +++ b/src/leap/soledad/tests/test_sqlcipher.py @@ -20,6 +20,7 @@ from leap.soledad.backends.sqlcipher import (      DatabaseIsNotEncrypted,  )  from leap.soledad.backends.sqlcipher import open as u1db_open +from leap.soledad.backends.leap_backend import LeapDocument  # u1db tests stuff.  from leap.soledad.tests import u1db_tests as tests @@ -75,10 +76,14 @@ def copy_sqlcipher_database_for_test(test, db):      return new_db +def make_document_for_test(test, doc_id, rev, content, has_conflicts=False): +    return LeapDocument(doc_id, rev, content, has_conflicts=has_conflicts) + +  SQLCIPHER_SCENARIOS = [      ('sqlcipher', {'make_database_for_test': make_sqlcipher_database_for_test,                     'copy_database_for_test': copy_sqlcipher_database_for_test, -                   'make_document_for_test': tests.make_document_for_test, }), +                   'make_document_for_test': make_document_for_test, }),  ] @@ -161,6 +166,10 @@ class TestSQLCipherDatabase(test_sqlite_backend.TestSQLiteDatabase):          self.assertTrue(db2._is_initialized(db1._get_sqlite_handle().cursor())) +class TestAlternativeDocument(LeapDocument): +    """A (not very) alternative implementation of Document.""" + +  class TestSQLCipherPartialExpandDatabase(          test_sqlite_backend.TestSQLitePartialExpandDatabase): @@ -223,8 +232,8 @@ class TestSQLCipherPartialExpandDatabase(          SQLCipherDatabase(path, PASSWORD)          db2 = SQLCipherDatabase._open_database(              path, PASSWORD, -            document_factory=test_backends.TestAlternativeDocument) -        self.assertEqual(test_backends.TestAlternativeDocument, db2._factory) +            document_factory=TestAlternativeDocument) +        self.assertEqual(TestAlternativeDocument, db2._factory)      def test_open_database_existing(self):          temp_dir = self.createTempDir(prefix='u1db-test-') @@ -239,8 +248,8 @@ class TestSQLCipherPartialExpandDatabase(          SQLCipherDatabase(path, PASSWORD)          db2 = SQLCipherDatabase.open_database(              path, PASSWORD, create=False, -            document_factory=test_backends.TestAlternativeDocument) -        self.assertEqual(test_backends.TestAlternativeDocument, db2._factory) +            document_factory=TestAlternativeDocument) +        self.assertEqual(TestAlternativeDocument, db2._factory)      def test_create_database_initializes_schema(self):          # This test had to be cloned because our implementation of SQLCipher @@ -255,6 +264,19 @@ class TestSQLCipherPartialExpandDatabase(                            'index_storage': 'expand referenced encrypted'},                           config) +    def test_store_syncable(self): +        doc = self.db.create_doc_from_json(tests.simple_doc) +        # assert that docs are syncable by default +        self.assertEqual(True, doc.syncable) +        # assert that we can store syncable = False +        doc.syncable = False +        self.db.put_doc(doc) +        self.assertEqual(False, self.db.get_doc(doc.doc_id).syncable) +        # assert that we can store syncable = True +        doc.syncable = True +        self.db.put_doc(doc) +        self.assertEqual(True, self.db.get_doc(doc.doc_id).syncable) +  #-----------------------------------------------------------------------------  # The following tests come from `u1db.tests.test_open`. @@ -277,9 +299,9 @@ class SQLCipherOpen(test_open.TestU1DBOpen):      def test_open_with_factory(self):          db = u1db_open(self.db_path, password=PASSWORD, create=True, -                       document_factory=test_backends.TestAlternativeDocument) +                       document_factory=TestAlternativeDocument)          self.addCleanup(db.close) -        self.assertEqual(test_backends.TestAlternativeDocument, db._factory) +        self.assertEqual(TestAlternativeDocument, db._factory)      def test_open_existing(self):          db = SQLCipherDatabase(self.db_path, PASSWORD) @@ -325,7 +347,8 @@ class SQLCipherEncryptionTest(unittest.TestCase):          try:              # trying to open an encrypted database with the regular u1db              # backend should raise a DatabaseError exception. -            SQLitePartialExpandDatabase(self.DB_FILE) +            SQLitePartialExpandDatabase(self.DB_FILE, +                                        document_factory=LeapDocument)              raise DatabaseIsNotEncrypted()          except DatabaseError:              # at this point we know that the regular U1DB sqlcipher backend @@ -337,7 +360,8 @@ class SQLCipherEncryptionTest(unittest.TestCase):                               'decrypted content mismatch')      def test_try_to_open_raw_db_with_sqlcipher_backend(self): -        db = SQLitePartialExpandDatabase(self.DB_FILE) +        db = SQLitePartialExpandDatabase(self.DB_FILE, +                                         document_factory=LeapDocument)          db.create_doc_from_json(tests.simple_doc)          db.close()          try: diff --git a/src/leap/soledad/util.py b/src/leap/soledad/util.py index 00625e86..4bc4d2c9 100644 --- a/src/leap/soledad/util.py +++ b/src/leap/soledad/util.py @@ -45,11 +45,11 @@ class GPGWrapper(gnupg.GPG):          Send keys to a keyserver          """          result = self.result_map['list'](self) -        logger.debug('send_keys: %r', keyids) -        data = _make_binary_stream("", self.encoding) +        gnupg.logger.debug('send_keys: %r', keyids) +        data = gnupg._make_binary_stream("", self.encoding)          args = ['--keyserver', keyserver, '--send-keys']          args.extend(keyids)          self._handle_io(args, data, result, binary=True) -        logger.debug('send_keys result: %r', result.__dict__) +        gnupg.logger.debug('send_keys result: %r', result.__dict__)          data.close()          return result | 
