From 8a887bb41c56da368fb1410c63da117566374858 Mon Sep 17 00:00:00 2001
From: drebs <drebs@leap.se>
Date: Sat, 9 Feb 2013 22:09:03 -0200
Subject: SQLCipher backend can sync with remote Leap HTTP target.

---
 src/leap/soledad/__init__.py              |  5 +++--
 src/leap/soledad/backends/leap_backend.py | 19 ++++++++---------
 src/leap/soledad/backends/sqlcipher.py    | 34 ++++++++++++++++++++++---------
 src/leap/soledad/tests/test_sqlcipher.py  |  9 +++++---
 4 files changed, 42 insertions(+), 25 deletions(-)

(limited to 'src')

diff --git a/src/leap/soledad/__init__.py b/src/leap/soledad/__init__.py
index 6893c7a8..e11b8319 100644
--- a/src/leap/soledad/__init__.py
+++ b/src/leap/soledad/__init__.py
@@ -43,7 +43,8 @@ class Soledad(object):
         # instantiate u1db
         # TODO: verify if secret for sqlcipher should be the same as the one
         # for symmetric encryption.
-        self._db = sqlcipher.open(self.LOCAL_DB_PATH, True, self._secret)
+        self._db = sqlcipher.open(self.LOCAL_DB_PATH, True, self._secret,
+                                  soledad=self)
 
     def close(self):
         self._db.close()
@@ -213,6 +214,6 @@ class Soledad(object):
         Synchronize the local encrypted database with LEAP server.
         """
         # TODO: create authentication scheme for sync with server.
-        return self._db.sync(url, creds=None, autocreate=True, soledad=self)
+        return self._db.sync(url, creds=None, autocreate=True)
 
 __all__ = ['util']
diff --git a/src/leap/soledad/backends/leap_backend.py b/src/leap/soledad/backends/leap_backend.py
index d3ae6db6..a2208404 100644
--- a/src/leap/soledad/backends/leap_backend.py
+++ b/src/leap/soledad/backends/leap_backend.py
@@ -92,7 +92,15 @@ class LeapDatabase(HTTPDatabase):
     def __init__(self, url, document_factory=None, creds=None, soledad=None):
         super(LeapDatabase, self).__init__(url, creds=creds)
         self._soledad = soledad
-        self._factory = LeapDocument
+
+        # wrap soledad in factory
+        def factory(doc_id=None, rev=None, json='{}', has_conflicts=False,
+                    encrypted_json=None, syncable=True):
+            return LeapDocument(doc_id=doc_id, rev=rev, json=json,
+                                has_conflicts=has_conflicts,
+                                encrypted_json=encrypted_json,
+                                syncable=syncable, soledad=self._soledad)
+        self.set_document_factory(factory)
 
     @staticmethod
     def open_database(url, create):
@@ -115,15 +123,6 @@ class LeapDatabase(HTTPDatabase):
         st._creds = self._creds
         return st
 
-    def create_doc_from_json(self, content, doc_id=None):
-        if doc_id is None:
-            doc_id = self._allocate_doc_id()
-        res, headers = self._request_json('PUT', ['doc', doc_id], {},
-                                          content, 'application/json')
-        new_doc = self._factory(doc_id, res['rev'], content,
-                                soledad=self._soledad)
-        return new_doc
-
 
 class LeapSyncTarget(HTTPSyncTarget):
     """
diff --git a/src/leap/soledad/backends/sqlcipher.py b/src/leap/soledad/backends/sqlcipher.py
index 354fcd31..9108f73a 100644
--- a/src/leap/soledad/backends/sqlcipher.py
+++ b/src/leap/soledad/backends/sqlcipher.py
@@ -31,7 +31,7 @@ from u1db import (
 from leap.soledad.backends.leap_backend import LeapDocument
 
 
-def open(path, password, create=True, document_factory=None):
+def open(path, password, create=True, document_factory=None, soledad=None):
     """Open a database at the given location.
 
     Will raise u1db.errors.DatabaseDoesNotExist if create=False and the
@@ -45,7 +45,8 @@ def open(path, password, create=True, document_factory=None):
     :return: An instance of Database.
     """
     return SQLCipherDatabase.open_database(
-        path, password, create=create, document_factory=document_factory)
+        path, password, create=create, document_factory=document_factory,
+        soledad=soledad)
 
 
 class DatabaseIsNotEncrypted(Exception):
@@ -64,14 +65,23 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):
     def set_pragma_key(cls, db_handle, key):
         db_handle.cursor().execute("PRAGMA key = '%s'" % key)
 
-    def __init__(self, sqlite_file, password, document_factory=None):
+    def __init__(self, sqlite_file, password, document_factory=None,
+                 soledad=None):
         """Create a new sqlcipher file."""
         self._check_if_db_is_encrypted(sqlite_file)
         self._db_handle = dbapi2.connect(sqlite_file)
         SQLCipherDatabase.set_pragma_key(self._db_handle, password)
         self._real_replica_uid = None
         self._ensure_schema()
-        self._factory = document_factory or LeapDocument
+        self._soledad = soledad
+
+        def factory(doc_id=None, rev=None, json='{}', has_conflicts=False,
+                    encrypted_json=None, syncable=True):
+            return LeapDocument(doc_id=doc_id, rev=rev, json=json,
+                                has_conflicts=has_conflicts,
+                                encrypted_json=encrypted_json,
+                                syncable=syncable, soledad=self._soledad)
+        self.set_document_factory(factory)
 
     def _check_if_db_is_encrypted(self, sqlite_file):
         if not os.path.exists(sqlite_file):
@@ -86,7 +96,8 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):
                 pass
 
     @classmethod
-    def _open_database(cls, sqlite_file, password, document_factory=None):
+    def _open_database(cls, sqlite_file, password, document_factory=None,
+                       soledad=None):
         if not os.path.isfile(sqlite_file):
             raise errors.DatabaseDoesNotExist()
         tries = 2
@@ -108,14 +119,16 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):
             tries -= 1
             time.sleep(cls.WAIT_FOR_PARALLEL_INIT_HALF_INTERVAL)
         return SQLCipherDatabase._sqlite_registry[v](
-            sqlite_file, password, document_factory=document_factory)
+            sqlite_file, password, document_factory=document_factory,
+            soledad=soledad)
 
     @classmethod
     def open_database(cls, sqlite_file, password, create, backend_cls=None,
-                      document_factory=None):
+                      document_factory=None, soledad=None):
         try:
             return cls._open_database(sqlite_file, password,
-                                      document_factory=document_factory)
+                                      document_factory=document_factory,
+                                      soledad=soledad)
         except errors.DatabaseDoesNotExist:
             if not create:
                 raise
@@ -123,9 +136,10 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase):
                 # default is SQLCipherPartialExpandDatabase
                 backend_cls = SQLCipherDatabase
             return backend_cls(sqlite_file, password,
-                               document_factory=document_factory)
+                               document_factory=document_factory,
+                               soledad=soledad)
 
-    def sync(self, url, creds=None, autocreate=True, soledad=None):
+    def sync(self, url, creds=None, autocreate=True):
         """
         Synchronize encrypted documents with remote replica exposed at url.
         """
diff --git a/src/leap/soledad/tests/test_sqlcipher.py b/src/leap/soledad/tests/test_sqlcipher.py
index 38ad09ed..09b76b82 100644
--- a/src/leap/soledad/tests/test_sqlcipher.py
+++ b/src/leap/soledad/tests/test_sqlcipher.py
@@ -236,7 +236,8 @@ class TestSQLCipherPartialExpandDatabase(
         db2 = SQLCipherDatabase._open_database(
             path, PASSWORD,
             document_factory=TestAlternativeDocument)
-        self.assertEqual(TestAlternativeDocument, db2._factory)
+        doc = db2.create_doc({})
+        self.assertTrue(isinstance(doc, LeapDocument))
 
     def test_open_database_existing(self):
         temp_dir = self.createTempDir(prefix='u1db-test-')
@@ -252,7 +253,8 @@ class TestSQLCipherPartialExpandDatabase(
         db2 = SQLCipherDatabase.open_database(
             path, PASSWORD, create=False,
             document_factory=TestAlternativeDocument)
-        self.assertEqual(TestAlternativeDocument, db2._factory)
+        doc = db2.create_doc({})
+        self.assertTrue(isinstance(doc, LeapDocument))
 
     def test_create_database_initializes_schema(self):
         # This test had to be cloned because our implementation of SQLCipher
@@ -304,7 +306,8 @@ class SQLCipherOpen(test_open.TestU1DBOpen):
         db = u1db_open(self.db_path, password=PASSWORD, create=True,
                        document_factory=TestAlternativeDocument)
         self.addCleanup(db.close)
-        self.assertEqual(TestAlternativeDocument, db._factory)
+        doc = db.create_doc({})
+        self.assertTrue(isinstance(doc, LeapDocument))
 
     def test_open_existing(self):
         db = SQLCipherDatabase(self.db_path, PASSWORD)
-- 
cgit v1.2.3