diff options
| author | drebs <drebs@leap.se> | 2013-03-07 17:23:05 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2013-03-07 17:23:05 -0300 | 
| commit | d89c1849d551de68d26a1f56798ee5084dca6556 (patch) | |
| tree | 25a54c87b22fca5ac494621a0ccbcca9e181cf76 /soledad/backends/sqlcipher.py | |
| parent | 1b1def113e6ed9b8af6897e16f0d9b4c96bbfa6b (diff) | |
Move source files to proper subdirectory.
Diffstat (limited to 'soledad/backends/sqlcipher.py')
| -rw-r--r-- | soledad/backends/sqlcipher.py | 163 | 
1 files changed, 0 insertions, 163 deletions
diff --git a/soledad/backends/sqlcipher.py b/soledad/backends/sqlcipher.py deleted file mode 100644 index 5d2569bf..00000000 --- a/soledad/backends/sqlcipher.py +++ /dev/null @@ -1,163 +0,0 @@ -"""A U1DB backend that uses SQLCipher as its persistence layer.""" - -import os -from pysqlcipher import dbapi2 -import time - -from leap import util -from u1db.backends import sqlite_backend -util.logger.debug( -    "Monkey-patching u1db.backends.sqlite_backend with pysqlcipher.dbapi2..." -) -sqlite_backend.dbapi2 = dbapi2 - -from u1db import ( -    errors, -) - -from leap.soledad.backends.leap_backend import LeapDocument - - -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 -    database does not already exist. - -    :param path: The filesystem path for the database to open. -    :param create: True/False, should the database be created if it doesn't -        already exist? -    :param document_factory: A function that will be called with the same -        parameters as Document.__init__. -    :return: An instance of Database. -    """ -    return SQLCipherDatabase.open_database( -        path, password, create=create, document_factory=document_factory, -        soledad=soledad) - - -class DatabaseIsNotEncrypted(Exception): -    """ -    Exception raised when trying to open non-encrypted databases. -    """ -    pass - - -class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase): -    """A U1DB implementation that uses SQLCipher as its persistence layer.""" - -    _index_storage_value = 'expand referenced encrypted' - -    @classmethod -    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, -                 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._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): -            return -        else: -            try: -                # try to open an encrypted database with the regular u1db -                # backend should raise a DatabaseError exception. -                sqlite_backend.SQLitePartialExpandDatabase(sqlite_file) -                raise DatabaseIsNotEncrypted() -            except dbapi2.DatabaseError: -                pass - -    @classmethod -    def _open_database(cls, sqlite_file, password, document_factory=None, -                       soledad=None): -        if not os.path.isfile(sqlite_file): -            raise errors.DatabaseDoesNotExist() -        tries = 2 -        while True: -            # Note: There seems to be a bug in sqlite 3.5.9 (with python2.6) -            #       where without re-opening the database on Windows, it -            #       doesn't see the transaction that was just committed -            db_handle = dbapi2.connect(sqlite_file) -            SQLCipherDatabase.set_pragma_key(db_handle, password) -            c = db_handle.cursor() -            v, err = cls._which_index_storage(c) -            db_handle.close() -            if v is not None: -                break -            # possibly another process is initializing it, wait for it to be -            # done -            if tries == 0: -                raise err  # go for the richest error? -            tries -= 1 -            time.sleep(cls.WAIT_FOR_PARALLEL_INIT_HALF_INTERVAL) -        return SQLCipherDatabase._sqlite_registry[v]( -            sqlite_file, password, document_factory=document_factory, -            soledad=soledad) - -    @classmethod -    def open_database(cls, sqlite_file, password, create, backend_cls=None, -                      document_factory=None, soledad=None): -        """Open U1DB database using SQLCipher as backend.""" -        try: -            return cls._open_database(sqlite_file, password, -                                      document_factory=document_factory, -                                      soledad=soledad) -        except errors.DatabaseDoesNotExist: -            if not create: -                raise -            if backend_cls is None: -                # default is SQLCipherPartialExpandDatabase -                backend_cls = SQLCipherDatabase -            return backend_cls(sqlite_file, password, -                               document_factory=document_factory, -                               soledad=soledad) - -    def sync(self, url, creds=None, autocreate=True): -        """ -        Synchronize encrypted documents with remote replica exposed at url. -        """ -        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) - -    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 - -sqlite_backend.SQLiteDatabase.register_implementation(SQLCipherDatabase)  | 
