diff options
author | drebs <drebs@leap.se> | 2013-01-24 12:03:45 -0200 |
---|---|---|
committer | drebs <drebs@leap.se> | 2013-01-24 12:03:45 -0200 |
commit | e1494639f57cafddfd433c62adaa52a21f104e10 (patch) | |
tree | b9e6b700db7ab9d9b3f927222eb0f780e7c851d8 /src/leap/soledad/backends | |
parent | 19da34c598ce6db172c1e1a8978bf031fc6db89b (diff) | |
parent | 1dec55b5c5054a4c42534c0f7e9b8bad5b82c27c (diff) |
Merge branch 'feature/soledad-api' into develop
Conflicts:
src/leap/soledad/util.py
Diffstat (limited to 'src/leap/soledad/backends')
-rw-r--r-- | src/leap/soledad/backends/couch.py | 49 | ||||
-rw-r--r-- | src/leap/soledad/backends/leap_backend.py | 8 | ||||
-rw-r--r-- | src/leap/soledad/backends/objectstore.py | 22 | ||||
-rw-r--r-- | src/leap/soledad/backends/openstack.py | 14 | ||||
-rw-r--r-- | src/leap/soledad/backends/sqlcipher.py | 16 |
5 files changed, 52 insertions, 57 deletions
diff --git a/src/leap/soledad/backends/couch.py b/src/leap/soledad/backends/couch.py index 78026af8..8ba42d78 100644 --- a/src/leap/soledad/backends/couch.py +++ b/src/leap/soledad/backends/couch.py @@ -1,7 +1,5 @@ -import sys import uuid from base64 import b64encode, b64decode -from u1db import errors from u1db.sync import LocalSyncTarget from couchdb.client import Server, Document as CouchDocument from couchdb.http import ResourceNotFound @@ -17,7 +15,8 @@ except ImportError: class CouchDatabase(ObjectStore): """A U1DB implementation that uses Couch as its persistence layer.""" - def __init__(self, url, database, replica_uid=None, full_commit=True, session=None): + def __init__(self, url, database, replica_uid=None, full_commit=True, + session=None): """Create a new Couch data container.""" self._url = url self._full_commit = full_commit @@ -54,8 +53,9 @@ class CouchDatabase(ObjectStore): doc_id=doc_id, rev=cdoc['u1db_rev'], has_conflicts=has_conflicts) - if cdoc['u1db_json'] is not None: - doc.content = json.loads(cdoc['u1db_json']) + contents = self._database.get_attachment(cdoc, 'u1db_json') + if contents: + doc.content = json.loads(contents.getvalue()) else: doc.make_tombstone() return doc @@ -83,13 +83,14 @@ class CouchDatabase(ObjectStore): cdoc['_rev'] = old_cdoc['_rev'] # store u1db's rev cdoc['u1db_rev'] = doc.rev + # save doc in db + self._database.save(cdoc) # store u1db's content as json string if not doc.is_tombstone(): - cdoc['u1db_json'] = doc.get_json() + self._database.put_attachment(cdoc, doc.get_json(), + filename='u1db_json') else: - cdoc['u1db_json'] = None - # save doc in db - self._database.save(cdoc) + self._database.delete_attachment(cdoc, 'u1db_json') def get_sync_target(self): return CouchSyncTarget(self) @@ -103,7 +104,6 @@ class CouchDatabase(ObjectStore): #self._server = None self._database = None return True - def sync(self, url, creds=None, autocreate=True): from u1db.sync import Synchronizer @@ -114,15 +114,16 @@ class CouchDatabase(ObjectStore): if self._replica_uid is None: self._replica_uid = uuid.uuid4().hex doc = self._factory(doc_id=self.U1DB_DATA_DOC_ID) - doc.content = { 'sync_log' : [], - 'transaction_log' : [], - 'conflict_log' : b64encode(json.dumps([])), - 'replica_uid' : self._replica_uid } + doc.content = {'sync_log': [], + 'transaction_log': [], + 'conflict_log': b64encode(json.dumps([])), + 'replica_uid': self._replica_uid} self._put_doc(doc) def _get_u1db_data(self): cdoc = self._database.get(self.U1DB_DATA_DOC_ID) - content = json.loads(cdoc['u1db_json']) + jsonstr = self._database.get_attachment(cdoc, 'u1db_json').getvalue() + content = json.loads(jsonstr) self._sync_log.log = content['sync_log'] self._transaction_log.log = content['transaction_log'] self._conflict_log.log = json.loads(b64decode(content['conflict_log'])) @@ -131,14 +132,15 @@ class CouchDatabase(ObjectStore): def _set_u1db_data(self): doc = self._factory(doc_id=self.U1DB_DATA_DOC_ID) - doc.content = { 'sync_log' : self._sync_log.log, - 'transaction_log' : self._transaction_log.log, - # Here, the b64 encode ensures that document content - # does not cause strange behaviour in couchdb because - # of encoding. - 'conflict_log' : b64encode(json.dumps(self._conflict_log.log)), - 'replica_uid' : self._replica_uid, - '_rev' : self._couch_rev} + doc.content = { + 'sync_log': self._sync_log.log, + 'transaction_log': self._transaction_log.log, + # Here, the b64 encode ensures that document content + # does not cause strange behaviour in couchdb because + # of encoding. + 'conflict_log': b64encode(json.dumps(self._conflict_log.log)), + 'replica_uid': self._replica_uid, + '_rev': self._couch_rev} self._put_doc(doc) #------------------------------------------------------------------------- @@ -166,4 +168,3 @@ class CouchSyncTarget(LocalSyncTarget): self._db._set_replica_gen_and_trans_id( source_replica_uid, source_replica_generation, source_replica_transaction_id) - diff --git a/src/leap/soledad/backends/leap_backend.py b/src/leap/soledad/backends/leap_backend.py index 3e859f7c..7e98dd45 100644 --- a/src/leap/soledad/backends/leap_backend.py +++ b/src/leap/soledad/backends/leap_backend.py @@ -41,8 +41,9 @@ class LeapDocument(Document): """ if not self._soledad: raise NoSoledadInstance() - ciphertext = self._soledad.encrypt_symmetric(self.doc_id, self.get_json()) - return json.dumps({'_encrypted_json' : ciphertext}) + ciphertext = self._soledad.encrypt_symmetric(self.doc_id, + self.get_json()) + return json.dumps({'_encrypted_json': ciphertext}) def set_encrypted_json(self, encrypted_json): """ @@ -89,7 +90,8 @@ class LeapDatabase(HTTPDatabase): 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) + new_doc = self._factory(doc_id, res['rev'], content, + soledad=self._soledad) return new_doc diff --git a/src/leap/soledad/backends/objectstore.py b/src/leap/soledad/backends/objectstore.py index b6523336..d72a2ecc 100644 --- a/src/leap/soledad/backends/objectstore.py +++ b/src/leap/soledad/backends/objectstore.py @@ -1,6 +1,7 @@ from u1db.backends import CommonBackend from u1db import errors, Document, vectorclock + class ObjectStore(CommonBackend): """ A backend for storing u1db data in an object store. @@ -139,12 +140,13 @@ class ObjectStore(CommonBackend): def _set_replica_gen_and_trans_id(self, other_replica_uid, other_generation, other_transaction_id): return self._do_set_replica_gen_and_trans_id( - other_replica_uid, - other_generation, - other_transaction_id) + other_replica_uid, + other_generation, + other_transaction_id) def _do_set_replica_gen_and_trans_id(self, other_replica_uid, - other_generation, other_transaction_id): + other_generation, + other_transaction_id): self._sync_log.set_replica_gen_and_trans_id(other_replica_uid, other_generation, other_transaction_id) @@ -201,7 +203,6 @@ class ObjectStore(CommonBackend): """ Verify if u1db data exists in store. """ - doc = self._get_doc(self.U1DB_DATA_DOC_ID) if not self._get_doc(self.U1DB_DATA_DOC_ID): return False return True @@ -234,7 +235,6 @@ class ObjectStore(CommonBackend): replica_uid = property( _get_replica_uid, _set_replica_uid, doc="Replica UID of the database") - #------------------------------------------------------------------------- # The methods below were cloned from u1db sqlite backend. They should at # least exist and raise a NotImplementedError exception in CommonBackend @@ -387,12 +387,12 @@ class TransactionLog(SimpleLog): return cur_gen, newest_trans_id, changes - def get_transaction_log(self): """ Return only a list of (doc_id, transaction_id) """ - return map(lambda x: (x[1], x[2]), sorted(self._get_log(reverse=False))) + return map(lambda x: (x[1], x[2]), + sorted(self._get_log(reverse=False))) class SyncLog(SimpleLog): @@ -416,7 +416,7 @@ class SyncLog(SimpleLog): return (info[1], info[2]) def set_replica_gen_and_trans_id(self, other_replica_uid, - other_generation, other_transaction_id): + other_generation, other_transaction_id): """ Set the last-known generation and transaction id for the other database replica. @@ -425,6 +425,7 @@ class SyncLog(SimpleLog): self.append((other_replica_uid, other_generation, other_transaction_id)) + class ConflictLog(SimpleLog): """ A list of (doc_id, my_doc_rev, my_content) tuples. @@ -433,7 +434,7 @@ class ConflictLog(SimpleLog): def __init__(self, factory): super(ConflictLog, self).__init__() self._factory = factory - + def delete_conflicts(self, conflicts): for conflict in conflicts: self._set_log(self.filter(lambda x: @@ -448,4 +449,3 @@ class ConflictLog(SimpleLog): def has_conflicts(self, doc_id): return bool(self.filter(lambda x: x[0] == doc_id)) - diff --git a/src/leap/soledad/backends/openstack.py b/src/leap/soledad/backends/openstack.py index c027231c..a9615736 100644 --- a/src/leap/soledad/backends/openstack.py +++ b/src/leap/soledad/backends/openstack.py @@ -1,6 +1,6 @@ -from u1db import errors +# TODO: this backend is not tested yet. from u1db.remote.http_target import HTTPSyncTarget -from swiftclient import client +import swiftclient from soledad.backends.objectstore import ObjectStore @@ -25,12 +25,13 @@ class OpenStackDatabase(ObjectStore): def _get_doc(self, doc_id, check_for_conflicts=False): """Get just the document content, without fancy handling. - + Conflicts do not happen on server side, so there's no need to check for them. """ try: - response, contents = self._connection.get_object(self._container, doc_id) + response, contents = self._connection.get_object(self._container, + doc_id) # TODO: change revision to be a dictionary element? rev = response['x-object-meta-rev'] return self._factory(doc_id, rev, contents) @@ -53,7 +54,7 @@ class OpenStackDatabase(ObjectStore): def _put_doc(self, doc, new_rev): new_rev = self._allocate_doc_rev(doc.rev) # TODO: change revision to be a dictionary element? - headers = { 'X-Object-Meta-Rev' : new_rev } + headers = {'X-Object-Meta-Rev': new_rev} self._connection.put_object(self._container, doc_id, doc.get_json(), headers=headers) @@ -77,6 +78,7 @@ class OpenStackDatabase(ObjectStore): self._url, self._auth_token = self._connection.get_auth() return self._url, self.auth_token + class OpenStackSyncTarget(HTTPSyncTarget): def get_sync_info(self, source_replica_uid): @@ -94,5 +96,3 @@ class OpenStackSyncTarget(HTTPSyncTarget): self._db._set_replica_gen_and_trans_id( source_replica_uid, source_replica_generation, source_replica_transaction_id) - - diff --git a/src/leap/soledad/backends/sqlcipher.py b/src/leap/soledad/backends/sqlcipher.py index 3d03449e..08b4df43 100644 --- a/src/leap/soledad/backends/sqlcipher.py +++ b/src/leap/soledad/backends/sqlcipher.py @@ -59,11 +59,9 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase): _index_storage_value = 'expand referenced encrypted' - @classmethod def set_pragma_key(cls, db_handle, key): - db_handle.cursor().execute("PRAGMA key = '%s'" % key) - + db_handle.cursor().execute("PRAGMA key = '%s'" % key) def __init__(self, sqlite_file, password, document_factory=None): """Create a new sqlcipher file.""" @@ -74,20 +72,18 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase): self._ensure_schema() self._factory = document_factory or Document - def _check_if_db_is_encrypted(self, sqlite_file): if not os.path.exists(sqlite_file): return else: try: - # try to open an encrypted database with the regular u1db backend - # should raise a DatabaseError exception. + # try to open an encrypted database with the regular u1db + # backend should raise a DatabaseError exception. SQLitePartialExpandDatabase(sqlite_file) raise DatabaseIsNotEncrypted() except DatabaseError: pass - @classmethod def _open_database(cls, sqlite_file, password, document_factory=None): if not os.path.isfile(sqlite_file): @@ -113,7 +109,6 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase): return SQLCipherDatabase._sqlite_registry[v]( sqlite_file, password, document_factory=document_factory) - @classmethod def open_database(cls, sqlite_file, password, create, backend_cls=None, document_factory=None): @@ -129,7 +124,6 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase): return backend_cls(sqlite_file, password, document_factory=document_factory) - def sync(self, url, creds=None, autocreate=True, soledad=None): """ Synchronize encrypted documents with remote replica exposed at url. @@ -137,9 +131,7 @@ class SQLCipherDatabase(SQLitePartialExpandDatabase): from u1db.sync import Synchronizer from leap.soledad.backends.leap_backend import LeapSyncTarget return Synchronizer(self, LeapSyncTarget(url, creds=creds), - soledad=self._soledad).sync( - autocreate=autocreate) + soledad=self._soledad).sync(autocreate=autocreate) SQLiteDatabase.register_implementation(SQLCipherDatabase) - |