diff options
| author | drebs <drebs@leap.se> | 2013-06-16 21:45:16 -0300 | 
|---|---|---|
| committer | drebs <drebs@leap.se> | 2013-06-20 15:19:50 -0300 | 
| commit | dbe5e37ef742617c93c7975a612582a77c7724a8 (patch) | |
| tree | 30efb7b027cda6992753df27833b6bb6f2d091b9 | |
| parent | 0deaa2070a88404779ae9a8dab88ee11521c5032 (diff) | |
Split client and server in two different packages and refactor.
| -rw-r--r-- | soledad/setup.py (renamed from setup.py) | 18 | ||||
| -rw-r--r-- | soledad/src/leap/__init__.py (renamed from src/leap/__init__.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/__init__.py (renamed from src/leap/soledad/__init__.py) | 35 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/auth.py (renamed from src/leap/soledad/auth.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/backends/__init__.py | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/backends/leap_backend.py | 73 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/crypto.py (renamed from src/leap/soledad/crypto.py) | 2 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/document.py | 111 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/shared_db.py (renamed from src/leap/soledad/shared_db.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/sqlcipher.py (renamed from src/leap/soledad/backends/sqlcipher.py) | 8 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/target.py (renamed from src/leap/soledad/backends/leap_backend.py) | 103 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/__init__.py (renamed from src/leap/soledad/tests/__init__.py) | 16 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/couchdb.ini.template (renamed from src/leap/soledad/tests/couchdb.ini.template) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_couch.py (renamed from src/leap/soledad/tests/test_couch.py) | 8 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_crypto.py (renamed from src/leap/soledad/tests/test_crypto.py) | 54 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_server.py (renamed from src/leap/soledad/tests/test_server.py) | 22 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_soledad.py (renamed from src/leap/soledad/tests/test_soledad.py) | 12 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_sqlcipher.py (renamed from src/leap/soledad/tests/test_sqlcipher.py) | 28 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/test_target.py (renamed from src/leap/soledad/tests/test_leap_backend.py) | 62 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/README (renamed from src/leap/soledad/tests/u1db_tests/README) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/__init__.py (renamed from src/leap/soledad/tests/u1db_tests/__init__.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_backends.py (renamed from src/leap/soledad/tests/u1db_tests/test_backends.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_document.py (renamed from src/leap/soledad/tests/u1db_tests/test_document.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py (renamed from src/leap/soledad/tests/u1db_tests/test_http_app.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py (renamed from src/leap/soledad/tests/u1db_tests/test_http_client.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py (renamed from src/leap/soledad/tests/u1db_tests/test_http_database.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_https.py (renamed from src/leap/soledad/tests/u1db_tests/test_https.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_open.py (renamed from src/leap/soledad/tests/u1db_tests/test_open.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py (renamed from src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py (renamed from src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/test_sync.py (renamed from src/leap/soledad/tests/u1db_tests/test_sync.py) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile (renamed from src/leap/soledad/tests/u1db_tests/testing-certs/Makefile) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem (renamed from src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert (renamed from src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert) | 0 | ||||
| -rw-r--r-- | soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key (renamed from src/leap/soledad/tests/u1db_tests/testing-certs/testing.key) | 0 | ||||
| -rw-r--r-- | soledad_server/pkg/soledad (renamed from pkg/soledad) | 0 | ||||
| -rw-r--r-- | soledad_server/setup.py | 79 | ||||
| -rw-r--r-- | soledad_server/src/leap/__init__.py | 6 | ||||
| -rw-r--r-- | soledad_server/src/leap/soledad_server/__init__.py (renamed from src/leap/soledad/server.py) | 11 | ||||
| -rw-r--r-- | soledad_server/src/leap/soledad_server/couch.py (renamed from src/leap/soledad/backends/couch.py) | 8 | ||||
| -rw-r--r-- | soledad_server/src/leap/soledad_server/objectstore.py (renamed from src/leap/soledad/backends/objectstore.py) | 0 | ||||
| -rw-r--r-- | src/leap/soledad/backends/__init__.py | 21 | 
42 files changed, 408 insertions, 269 deletions
| diff --git a/setup.py b/soledad/setup.py index b989f48a..51ab0b2b 100644 --- a/setup.py +++ b/soledad/setup.py @@ -16,7 +16,6 @@  # along with this program. If not, see <http://www.gnu.org/licenses/>. -import os  from setuptools import (      setup,      find_packages @@ -24,18 +23,13 @@ from setuptools import (  install_requirements = [ -    'configparser', -    'couchdb',      'pysqlcipher',      'simplejson', -    'twisted>=12.0.0',  # TODO: maybe we just want twisted-web?      'oauth',  # this is not strictly needed by us, but we need it                # until u1db adds it to its release as a dep.      'u1db', -    'requests',      'six==1.1.0',      'scrypt', -    'routes',      'pyxdg',      'pycrypto',  ] @@ -46,15 +40,10 @@ tests_requirements = [      'nose2',      'testscenarios',      'leap.common', +    'leap.soledad_server',  ] -if os.environ.get('VIRTUAL_ENV', None): -    data_files = None -else: -    # XXX this should go only for linux/mac -    data_files = [("/etc/init.d/", ["pkg/soledad"])] -  trove_classifiers = (      "Development Status :: 3 - Alpha",      "Intended Audience :: Developers", @@ -88,9 +77,6 @@ setup(      test_suite='leap.soledad.tests',      install_requires=install_requirements,      tests_require=tests_requirements, -    data_files=data_files,      classifiers=trove_classifiers, -    extras_require={ -        'signaling': ['leap.common'], -    } +    extras_require={'signaling': ['leap.common']},  ) diff --git a/src/leap/__init__.py b/soledad/src/leap/__init__.py index f48ad105..f48ad105 100644 --- a/src/leap/__init__.py +++ b/soledad/src/leap/__init__.py diff --git a/src/leap/soledad/__init__.py b/soledad/src/leap/soledad/__init__.py index 21457caf..2e1155f9 100644 --- a/src/leap/soledad/__init__.py +++ b/soledad/src/leap/soledad/__init__.py @@ -134,13 +134,12 @@ except ImportError:      pass -from leap.soledad.backends import sqlcipher -from leap.soledad.backends.leap_backend import ( -    LeapDocument, -    LeapSyncTarget, +from leap.soledad.document import SoledadDocument +from leap.soledad.sqlcipher import ( +    open as sqlcipher_open, +    SQLCipherDatabase,  ) - -from leap.soledad import shared_db +from leap.soledad.target import SoledadSyncTarget  from leap.soledad.shared_db import SoledadSharedDatabase  from leap.soledad.crypto import SoledadCrypto @@ -418,11 +417,11 @@ class Soledad(object):              secret[salt_start:salt_end],  # the salt              buflen=32,  # we need a key with 256 bits (32 bytes)          ) -        self._db = sqlcipher.open( +        self._db = sqlcipher_open(              self._local_db_path,              binascii.b2a_hex(key),  # sqlcipher only accepts the hex version              create=True, -            document_factory=LeapDocument, +            document_factory=SoledadDocument,              crypto=self._crypto,              raw_key=True) @@ -432,7 +431,7 @@ class Soledad(object):          """          if hasattr(self, '_db') and isinstance(                  self._db, -                sqlcipher.SQLCipherDatabase): +                SQLCipherDatabase):              self._db.close()      def __del__(self): @@ -634,7 +633,7 @@ class Soledad(object):          database.          @return: a document with encrypted key material in its contents -        @rtype: LeapDocument +        @rtype: SoledadDocument          """          signal(SOLEDAD_DOWNLOADING_KEYS, self._uuid)          db = self._shared_db() @@ -661,7 +660,7 @@ class Soledad(object):          # try to get secrets doc from server, otherwise create it          doc = self._get_secrets_from_shared_db()          if doc is None: -            doc = LeapDocument(doc_id=self._uuid_hash()) +            doc = SoledadDocument(doc_id=self._uuid_hash())          # fill doc with encrypted secrets          doc.content = self.export_recovery_document(include_uuid=False)          # upload secrets to server @@ -682,7 +681,7 @@ class Soledad(object):          Update a document in the local encrypted database.          @param doc: the document to update -        @type doc: LeapDocument +        @type doc: SoledadDocument          @return: the new revision identifier for the document          @rtype: str @@ -694,7 +693,7 @@ class Soledad(object):          Delete a document from the local encrypted database.          @param doc: the document to delete -        @type doc: LeapDocument +        @type doc: SoledadDocument          @return: the new revision identifier for the document          @rtype: str @@ -713,7 +712,7 @@ class Soledad(object):          @type include_deleted: bool          @return: the document object or None -        @rtype: LeapDocument +        @rtype: SoledadDocument          """          return self._db.get_doc(doc_id, include_deleted=include_deleted) @@ -758,7 +757,7 @@ class Soledad(object):          @type doc_id: str          @return: the new document -        @rtype: LeapDocument +        @rtype: SoledadDocument          """          return self._db.create_doc(content, doc_id=doc_id) @@ -777,7 +776,7 @@ class Soledad(object):          @param doc_id: An optional identifier specifying the document id.          @type doc_id:          @return: The new cocument -        @rtype: LeapDocument +        @rtype: SoledadDocument          """          return self._db.create_doc_from_json(json, doc_id=doc_id) @@ -903,7 +902,7 @@ class Soledad(object):          Mark a document as no longer conflicted.          @param doc: a document with the new content to be inserted. -        @type doc: LeapDocument +        @type doc: SoledadDocument          @param conflicted_doc_revs: a list of revisions that the new content              supersedes.          @type conflicted_doc_revs: list @@ -937,7 +936,7 @@ class Soledad(object):          @return: Whether remote replica and local replica differ.          @rtype: bool          """ -        target = LeapSyncTarget(url, creds=self._creds, crypto=self._crypto) +        target = SoledadSyncTarget(url, creds=self._creds, crypto=self._crypto)          info = target.get_sync_info(self._db._get_replica_uid())          # compare source generation with target's last known source generation          if self._db._get_generation() != info[4]: diff --git a/src/leap/soledad/auth.py b/soledad/src/leap/soledad/auth.py index 8c093099..8c093099 100644 --- a/src/leap/soledad/auth.py +++ b/soledad/src/leap/soledad/auth.py diff --git a/soledad/src/leap/soledad/backends/__init__.py b/soledad/src/leap/soledad/backends/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/soledad/src/leap/soledad/backends/__init__.py diff --git a/soledad/src/leap/soledad/backends/leap_backend.py b/soledad/src/leap/soledad/backends/leap_backend.py new file mode 100644 index 00000000..a8d76b67 --- /dev/null +++ b/soledad/src/leap/soledad/backends/leap_backend.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +# leap_backend.py  +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +""" +This file exists to provide backwards compatibility with code that uses +Soledad before the refactor that removed the leap_backend module. +""" + + +import logging +import warnings + + +from leap.soledad import document +from leap.soledad import target + + +logger = logging.getLogger(name=__name__) + + +def warn(oldclass, newclass): +    """ +    Warns about deprecation of C{oldclass}, which must be substituted by +    C{newclass}. + +    @param oldclass: The class that is deprecated. +    @type oldclass: type +    @param newclass: The class that should be used instead. +    @type newclass: type +    """ +    message = \ +        "%s is deprecated and will be removed soon. Please use %s instead." \ +        % (str(oldclass), str(newclass)) +    print message +    logger.warning(message) +    warnings.warn(message, DeprecationWarning, stacklevel=2) + + +class LeapDocument(document.SoledadDocument): +    """ +    This class exists to provide backwards compatibility with code that still +    uses C{leap.soledad.backends.leap_backend.LeapDocument}. +    """ + +    def __init__(self, *args, **kwargs): +        warn(self.__class__, document.SoledadDocument) +        document.SoledadDocument.__init__(self, *args, **kwargs) + + +class EncryptionSchemes(target.EncryptionSchemes): +    """ +    This class exists to provide backwards compatibility with code that still +    uses C{leap.soledad.backends.leap_backend.EncryptionSchemes}. +    """ + +    def __init__(self, *args, **kwargs): +        warn(self.__class__, target.EncryptionSchemes) +        target.EncryptionSchemes.__init__(self, *args, **kwargs) diff --git a/src/leap/soledad/crypto.py b/soledad/src/leap/soledad/crypto.py index be83e4a2..bfad66d1 100644 --- a/src/leap/soledad/crypto.py +++ b/soledad/src/leap/soledad/crypto.py @@ -136,7 +136,7 @@ class SoledadCrypto(object):                  'Wrong key size: %s (must be 256 bits long).' % len(key))              soledad_assert(                  'iv' in kwargs, -                'AES-256-CTR needs an initial value given as.') +                'AES-256-CTR needs an initial value.')              ctr = Counter.new(64, prefix=binascii.a2b_base64(kwargs['iv']))              cipher = AES.new(key=key, mode=AES.MODE_CTR, counter=ctr)              return cipher.decrypt(data) diff --git a/soledad/src/leap/soledad/document.py b/soledad/src/leap/soledad/document.py new file mode 100644 index 00000000..cc24b53a --- /dev/null +++ b/soledad/src/leap/soledad/document.py @@ -0,0 +1,111 @@ +# -*- coding: utf-8 -*- +# document.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +""" +A Soledad Document is an u1db.Document with lasers. +""" + + +from u1db import Document + + +# +# SoledadDocument +# + +class SoledadDocument(Document): +    """ +    Encryptable and syncable document. + +    LEAP Documents can be flagged as syncable or not, so the replicas +    might not sync every document. +    """ + +    def __init__(self, doc_id=None, rev=None, json='{}', has_conflicts=False, +                 syncable=True): +        """ +        Container for handling an encryptable document. + +        @param doc_id: The unique document identifier. +        @type doc_id: str +        @param rev: The revision identifier of the document. +        @type rev: str +        @param json: The JSON string for this document. +        @type json: str +        @param has_conflicts: Boolean indicating if this document has conflicts +        @type has_conflicts: bool +        @param syncable: Should this document be synced with remote replicas? +        @type syncable: bool +        """ +        Document.__init__(self, doc_id, rev, json, has_conflicts) +        self._syncable = syncable + +    def _get_syncable(self): +        """ +        Return whether this document is syncable. + +        @return: Is this document syncable? +        @rtype: bool +        """ +        return self._syncable + +    def _set_syncable(self, syncable=True): +        """ +        Determine if this document should be synced with remote replicas. + +        @param syncable: Should this document be synced with remote replicas? +        @type syncable: bool +        """ +        self._syncable = syncable + +    syncable = property( +        _get_syncable, +        _set_syncable, +        doc="Determine if document should be synced with server." +    ) + +    def _get_rev(self): +        """ +        Get the document revision. + +        Returning the revision as string solves the following exception in +        Twisted web: +            exceptions.TypeError: Can only pass-through bytes on Python 2 + +        @return: The document revision. +        @rtype: str +        """ +        if self._rev is None: +            return None +        return str(self._rev) + +    def _set_rev(self, rev): +        """ +        Set document revision. + +        @param rev: The new document revision. +        @type rev: bytes +        """ +        self._rev = rev + +    rev = property( +        _get_rev, +        _set_rev, +        doc="Wrapper to ensure `doc.rev` is always returned as bytes.") + + diff --git a/src/leap/soledad/shared_db.py b/soledad/src/leap/soledad/shared_db.py index 33c5c484..33c5c484 100644 --- a/src/leap/soledad/shared_db.py +++ b/soledad/src/leap/soledad/shared_db.py diff --git a/src/leap/soledad/backends/sqlcipher.py b/soledad/src/leap/soledad/sqlcipher.py index d6d62f21..acbeabe6 100644 --- a/src/leap/soledad/backends/sqlcipher.py +++ b/soledad/src/leap/soledad/sqlcipher.py @@ -54,7 +54,7 @@ from pysqlcipher import dbapi2  from u1db import (      errors,  ) -from leap.soledad.backends.leap_backend import LeapDocument +from leap.soledad.document import SoledadDocument  # Monkey-patch u1db.backends.sqlite_backend with pysqlcipher.dbapi2 @@ -169,7 +169,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):          def factory(doc_id=None, rev=None, json='{}', has_conflicts=False,                      syncable=True): -            return LeapDocument(doc_id=doc_id, rev=rev, json=json, +            return SoledadDocument(doc_id=doc_id, rev=rev, json=json,                                  has_conflicts=has_conflicts,                                  syncable=syncable)          self.set_document_factory(factory) @@ -301,10 +301,10 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):          @rtype: int          """          from u1db.sync import Synchronizer -        from leap.soledad.backends.leap_backend import LeapSyncTarget +        from leap.soledad.target import SoledadSyncTarget          return Synchronizer(              self, -            LeapSyncTarget(url, +            SoledadSyncTarget(url,                             creds=creds,                             crypto=self._crypto)).sync(autocreate=autocreate) diff --git a/src/leap/soledad/backends/leap_backend.py b/soledad/src/leap/soledad/target.py index 4d92db37..8b7aa8c7 100644 --- a/src/leap/soledad/backends/leap_backend.py +++ b/soledad/src/leap/soledad/target.py @@ -1,5 +1,5 @@  # -*- coding: utf-8 -*- -# leap_backend.py +# target.py  # Copyright (C) 2013 LEAP  #  # This program is free software: you can redistribute it and/or modify @@ -27,13 +27,13 @@ import hmac  import binascii -from u1db import Document  from u1db.remote import utils  from u1db.errors import BrokenSyncStream  from u1db.remote.http_target import HTTPSyncTarget  from leap.soledad import soledad_assert +from leap.soledad.document import SoledadDocument  from leap.soledad.crypto import (      EncryptionMethods,      UnknownEncryptionMethod, @@ -96,7 +96,7 @@ class MacMethods(object):  # -# Crypto utilities for a LeapDocument. +# Crypto utilities for a SoledadDocument.  #  ENC_JSON_KEY = '_enc_json' @@ -159,7 +159,7 @@ def encrypt_doc(crypto, doc):      @param crypto: A SoledadCryto instance used to perform the encryption.      @type crypto: leap.soledad.crypto.SoledadCrypto      @param doc: The document with contents to be encrypted. -    @type doc: LeapDocument +    @type doc: SoledadDocument      @return: The JSON serialization of the dict representing the encrypted          content. @@ -213,7 +213,7 @@ def decrypt_doc(crypto, doc):      @param crypto: A SoledadCryto instance to perform the encryption.      @type crypto: leap.soledad.crypto.SoledadCrypto      @param doc: The document to be decrypted. -    @type doc: LeapDocument +    @type doc: SoledadDocument      @return: The JSON serialization of the decrypted content.      @rtype: str @@ -252,92 +252,11 @@ def decrypt_doc(crypto, doc):      return plainjson -class LeapDocument(Document): -    """ -    Encryptable and syncable document. - -    LEAP Documents can be flagged as syncable or not, so the replicas -    might not sync every document. -    """ - -    def __init__(self, doc_id=None, rev=None, json='{}', has_conflicts=False, -                 syncable=True): -        """ -        Container for handling an encryptable document. - -        @param doc_id: The unique document identifier. -        @type doc_id: str -        @param rev: The revision identifier of the document. -        @type rev: str -        @param json: The JSON string for this document. -        @type json: str -        @param has_conflicts: Boolean indicating if this document has conflicts -        @type has_conflicts: bool -        @param syncable: Should this document be synced with remote replicas? -        @type syncable: bool -        """ -        Document.__init__(self, doc_id, rev, json, has_conflicts) -        self._syncable = syncable - -    def _get_syncable(self): -        """ -        Return whether this document is syncable. - -        @return: Is this document syncable? -        @rtype: bool -        """ -        return self._syncable - -    def _set_syncable(self, syncable=True): -        """ -        Determine if this document should be synced with remote replicas. - -        @param syncable: Should this document be synced with remote replicas? -        @type syncable: bool -        """ -        self._syncable = syncable - -    syncable = property( -        _get_syncable, -        _set_syncable, -        doc="Determine if document should be synced with server." -    ) - -    def _get_rev(self): -        """ -        Get the document revision. - -        Returning the revision as string solves the following exception in -        Twisted web: -            exceptions.TypeError: Can only pass-through bytes on Python 2 - -        @return: The document revision. -        @rtype: str -        """ -        if self._rev is None: -            return None -        return str(self._rev) - -    def _set_rev(self, rev): -        """ -        Set document revision. - -        @param rev: The new document revision. -        @type rev: bytes -        """ -        self._rev = rev - -    rev = property( -        _get_rev, -        _set_rev, -        doc="Wrapper to ensure `doc.rev` is always returned as bytes.") - -  # -# LeapSyncTarget +# SoledadSyncTarget  # -class LeapSyncTarget(HTTPSyncTarget, TokenBasedAuth): +class SoledadSyncTarget(HTTPSyncTarget, TokenBasedAuth):      """      A SyncTarget that encrypts data before sending and decrypts data after      receiving. @@ -380,11 +299,11 @@ class LeapSyncTarget(HTTPSyncTarget, TokenBasedAuth):      @staticmethod      def connect(url, crypto=None): -        return LeapSyncTarget(url, crypto=crypto) +        return SoledadSyncTarget(url, crypto=crypto)      def __init__(self, url, creds=None, crypto=None):          """ -        Initialize the LeapSyncTarget. +        Initialize the SoledadSyncTarget.          @param url: The url of the target replica to sync with.          @type url: str @@ -441,7 +360,7 @@ class LeapSyncTarget(HTTPSyncTarget, TokenBasedAuth):                  #-------------------------------------------------------------                  # if arriving content was symmetrically encrypted, we decrypt                  # it. -                doc = LeapDocument(entry['id'], entry['rev'], entry['content']) +                doc = SoledadDocument(entry['id'], entry['rev'], entry['content'])                  if doc.content and ENC_SCHEME_KEY in doc.content:                      if doc.content[ENC_SCHEME_KEY] == \                              EncryptionSchemes.SYMKEY: @@ -517,7 +436,7 @@ class LeapSyncTarget(HTTPSyncTarget, TokenBasedAuth):          comma = ','          for doc, gen, trans_id in docs_by_generations:              # skip non-syncable docs -            if isinstance(doc, LeapDocument) and not doc.syncable: +            if isinstance(doc, SoledadDocument) and not doc.syncable:                  continue              #-------------------------------------------------------------              # symmetric encryption of document's contents diff --git a/src/leap/soledad/tests/__init__.py b/soledad/src/leap/soledad/tests/__init__.py index 9fec5530..b33f866c 100644 --- a/src/leap/soledad/tests/__init__.py +++ b/soledad/src/leap/soledad/tests/__init__.py @@ -8,9 +8,9 @@ from mock import Mock  from leap.soledad import Soledad +from leap.soledad.document import SoledadDocument  from leap.soledad.crypto import SoledadCrypto -from leap.soledad.backends.leap_backend import ( -    LeapDocument, +from leap.soledad.target import (      decrypt_doc,      ENC_SCHEME_KEY,  ) @@ -37,9 +37,9 @@ class BaseSoledadTest(BaseLeapTest):          self.email = ADDRESS          # open test dbs          self._db1 = u1db.open(self.db1_file, create=True, -                              document_factory=LeapDocument) +                              document_factory=SoledadDocument)          self._db2 = u1db.open(self.db2_file, create=True, -                              document_factory=LeapDocument) +                              document_factory=SoledadDocument)          # initialize soledad by hand so we can control keys          self._soledad = self._soledad_instance(user=self.email) @@ -257,11 +257,3 @@ RZXoH+FTg9UAW87eqU610npOkT6cRaBxaMK/mDtGNdc=  =JTFu  -----END PGP PRIVATE KEY BLOCK-----  """ - -__all__ = [ -    'test_couch', -    'test_encrypted', -    'test_leap_backend', -    'test_sqlcipher', -    'u1db_tests', -] diff --git a/src/leap/soledad/tests/couchdb.ini.template b/soledad/src/leap/soledad/tests/couchdb.ini.template index 7d0316f0..7d0316f0 100644 --- a/src/leap/soledad/tests/couchdb.ini.template +++ b/soledad/src/leap/soledad/tests/couchdb.ini.template diff --git a/src/leap/soledad/tests/test_couch.py b/soledad/src/leap/soledad/tests/test_couch.py index 60a61b71..dcf4432d 100644 --- a/src/leap/soledad/tests/test_couch.py +++ b/soledad/src/leap/soledad/tests/test_couch.py @@ -27,14 +27,12 @@ from base64 import b64decode  from leap.common.files import mkdir_p -from leap.soledad.backends import couch +from leap.soledad_server import couch  from leap.soledad.tests import u1db_tests as tests  from leap.soledad.tests.u1db_tests import test_backends  from leap.soledad.tests.u1db_tests import test_sync  import simplejson as json -from leap.soledad.backends.leap_backend import ( -    LeapDocument, -) +from leap.soledad.document import SoledadDocument  #----------------------------------------------------------------------------- @@ -185,7 +183,7 @@ def copy_couch_database_for_test(test, db):  def make_document_for_test(test, doc_id, rev, content, has_conflicts=False): -    return LeapDocument(doc_id, rev, content, has_conflicts=has_conflicts) +    return SoledadDocument(doc_id, rev, content, has_conflicts=has_conflicts)  COUCH_SCENARIOS = [ diff --git a/src/leap/soledad/tests/test_crypto.py b/soledad/src/leap/soledad/tests/test_crypto.py index 59d20fa7..c727a2ff 100644 --- a/src/leap/soledad/tests/test_crypto.py +++ b/soledad/src/leap/soledad/tests/test_crypto.py @@ -33,10 +33,12 @@ from Crypto import Random  from leap.common.testing.basetest import BaseLeapTest -from leap.soledad import Soledad -from leap.soledad import crypto -from leap.soledad.backends import leap_backend -from leap.soledad.backends.couch import CouchDatabase +from leap.soledad import ( +    Soledad, +    crypto, +    target, +) +from leap.soledad.document import SoledadDocument  from leap.soledad.tests import (      BaseSoledadTest,      KEY_FINGERPRINT, @@ -49,12 +51,6 @@ from leap.soledad.tests.u1db_tests import (  ) -# These will be used in the future for EncryptedCouchSyncTestCase -#from leap.soledad.tests.test_couch import CouchDBTestCase -#from leap.soledad.tests.test_leap_backend import make_leap_document_for_test -#from leap.soledad.backends.couch import CouchServerState - -  class EncryptedSyncTestCase(BaseSoledadTest):      """      Tests that guarantee that data will always be encrypted when syncing. @@ -65,18 +61,18 @@ class EncryptedSyncTestCase(BaseSoledadTest):          Test encrypting and decrypting documents.          """          simpledoc = {'key': 'val'} -        doc1 = leap_backend.LeapDocument(doc_id='id') +        doc1 = SoledadDocument(doc_id='id')          doc1.content = simpledoc          # encrypt doc -        doc1.set_json(leap_backend.encrypt_doc(self._soledad._crypto, doc1)) +        doc1.set_json(target.encrypt_doc(self._soledad._crypto, doc1))          # assert content is different and includes keys          self.assertNotEqual(              simpledoc, doc1.content,              'incorrect document encryption') -        self.assertTrue(leap_backend.ENC_JSON_KEY in doc1.content) -        self.assertTrue(leap_backend.ENC_SCHEME_KEY in doc1.content) +        self.assertTrue(target.ENC_JSON_KEY in doc1.content) +        self.assertTrue(target.ENC_SCHEME_KEY in doc1.content)          # decrypt doc -        doc1.set_json(leap_backend.decrypt_doc(self._soledad._crypto, doc1)) +        doc1.set_json(target.decrypt_doc(self._soledad._crypto, doc1))          self.assertEqual(              simpledoc, doc1.content, 'incorrect document encryption') @@ -161,36 +157,36 @@ class MacAuthTestCase(BaseSoledadTest):          Trying to decrypt a document with wrong MAC should raise.          """          simpledoc = {'key': 'val'} -        doc = leap_backend.LeapDocument(doc_id='id') +        doc = SoledadDocument(doc_id='id')          doc.content = simpledoc          # encrypt doc -        doc.set_json(leap_backend.encrypt_doc(self._soledad._crypto, doc)) -        self.assertTrue(leap_backend.MAC_KEY in doc.content) -        self.assertTrue(leap_backend.MAC_METHOD_KEY in doc.content) +        doc.set_json(target.encrypt_doc(self._soledad._crypto, doc)) +        self.assertTrue(target.MAC_KEY in doc.content) +        self.assertTrue(target.MAC_METHOD_KEY in doc.content)          # mess with MAC -        doc.content[leap_backend.MAC_KEY] = '1234567890ABCDEF' +        doc.content[target.MAC_KEY] = '1234567890ABCDEF'          # try to decrypt doc          self.assertRaises( -            leap_backend.WrongMac, -            leap_backend.decrypt_doc, self._soledad._crypto, doc) +            target.WrongMac, +            target.decrypt_doc, self._soledad._crypto, doc)      def test_decrypt_with_unknown_mac_method_raises(self):          """          Trying to decrypt a document with unknown MAC method should raise.          """          simpledoc = {'key': 'val'} -        doc = leap_backend.LeapDocument(doc_id='id') +        doc = SoledadDocument(doc_id='id')          doc.content = simpledoc          # encrypt doc -        doc.set_json(leap_backend.encrypt_doc(self._soledad._crypto, doc)) -        self.assertTrue(leap_backend.MAC_KEY in doc.content) -        self.assertTrue(leap_backend.MAC_METHOD_KEY in doc.content) +        doc.set_json(target.encrypt_doc(self._soledad._crypto, doc)) +        self.assertTrue(target.MAC_KEY in doc.content) +        self.assertTrue(target.MAC_METHOD_KEY in doc.content)          # mess with MAC method -        doc.content[leap_backend.MAC_METHOD_KEY] = 'mymac' +        doc.content[target.MAC_METHOD_KEY] = 'mymac'          # try to decrypt doc          self.assertRaises( -            leap_backend.UnknownMacMethod, -            leap_backend.decrypt_doc, self._soledad._crypto, doc) +            target.UnknownMacMethod, +            target.decrypt_doc, self._soledad._crypto, doc)  class SoledadCryptoTestCase(BaseSoledadTest): diff --git a/src/leap/soledad/tests/test_server.py b/soledad/src/leap/soledad/tests/test_server.py index 02276d87..490d2fc8 100644 --- a/src/leap/soledad/tests/test_server.py +++ b/soledad/src/leap/soledad/tests/test_server.py @@ -29,16 +29,16 @@ import mock  from leap.soledad import Soledad -from leap.soledad.server import ( +from leap.soledad_server import (      SoledadApp,      SoledadAuthMiddleware,      URLToAuth,  ) -from leap.soledad.backends.couch import ( +from leap.soledad_server.couch import (      CouchServerState,      CouchDatabase,  ) -from leap.soledad.backends import leap_backend +from leap.soledad import target  from leap.common.testing.basetest import BaseLeapTest @@ -49,7 +49,7 @@ from leap.soledad.tests.u1db_tests import (      nested_doc,  )  from leap.soledad.tests.test_couch import CouchDBTestCase -from leap.soledad.tests.test_leap_backend import ( +from leap.soledad.tests.test_target import (      make_token_soledad_app,      make_leap_document_for_test,      token_leap_sync_target, @@ -336,7 +336,7 @@ class EncryptedSyncTestCase(          self.startServer()          # instantiate soledad and create a document          sol1 = self._soledad_instance( -            # token is verified in test_leap_backend.make_token_soledad_app +            # token is verified in test_target.make_token_soledad_app              auth_token='auth-token'          )          _, doclist = sol1.get_all_docs() @@ -358,12 +358,12 @@ class EncryptedSyncTestCase(          self.assertEqual(doc1.doc_id, couchdoc.doc_id)          self.assertEqual(doc1.rev, couchdoc.rev)          self.assertEqual(6, len(couchdoc.content)) -        self.assertTrue(leap_backend.ENC_JSON_KEY in couchdoc.content) -        self.assertTrue(leap_backend.ENC_SCHEME_KEY in couchdoc.content) -        self.assertTrue(leap_backend.ENC_METHOD_KEY in couchdoc.content) -        self.assertTrue(leap_backend.ENC_IV_KEY in couchdoc.content) -        self.assertTrue(leap_backend.MAC_KEY in couchdoc.content) -        self.assertTrue(leap_backend.MAC_METHOD_KEY in couchdoc.content) +        self.assertTrue(target.ENC_JSON_KEY in couchdoc.content) +        self.assertTrue(target.ENC_SCHEME_KEY in couchdoc.content) +        self.assertTrue(target.ENC_METHOD_KEY in couchdoc.content) +        self.assertTrue(target.ENC_IV_KEY in couchdoc.content) +        self.assertTrue(target.MAC_KEY in couchdoc.content) +        self.assertTrue(target.MAC_METHOD_KEY in couchdoc.content)          # instantiate soledad with empty db, but with same secrets path          sol2 = self._soledad_instance(prefix='x', auth_token='auth-token')          _, doclist = sol2.get_all_docs() diff --git a/src/leap/soledad/tests/test_soledad.py b/soledad/src/leap/soledad/tests/test_soledad.py index 8062a337..1a991bfb 100644 --- a/src/leap/soledad/tests/test_soledad.py +++ b/soledad/src/leap/soledad/tests/test_soledad.py @@ -36,12 +36,10 @@ from leap.soledad.tests import (  )  from leap import soledad  from leap.soledad import Soledad +from leap.soledad.document import SoledadDocument  from leap.soledad.crypto import SoledadCrypto  from leap.soledad.shared_db import SoledadSharedDatabase -from leap.soledad.backends.leap_backend import ( -    LeapDocument, -    LeapSyncTarget, -) +from leap.soledad.target import SoledadSyncTarget  class AuxMethodsTestCase(BaseSoledadTest): @@ -63,7 +61,7 @@ class AuxMethodsTestCase(BaseSoledadTest):              sol._gen_secret()          sol._load_secrets()          sol._init_db() -        from leap.soledad.backends.sqlcipher import SQLCipherDatabase +        from leap.soledad.sqlcipher import SQLCipherDatabase          self.assertIsInstance(sol._db, SQLCipherDatabase)      def test__init_config_defaults(self): @@ -117,7 +115,7 @@ class SoledadSharedDBTestCase(BaseSoledadTest):      def setUp(self):          BaseSoledadTest.setUp(self)          self._shared_db = SoledadSharedDatabase( -            'https://provider/', LeapDocument, None) +            'https://provider/', SoledadDocument, None)      def test__get_secrets_from_shared_db(self):          """ @@ -284,7 +282,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):          soledad.signal.reset_mock()          sol = self._soledad_instance()          # mock the sync target -        LeapSyncTarget.get_sync_info = Mock(return_value=[0, 0, 0, 0, 2]) +        SoledadSyncTarget.get_sync_info = Mock(return_value=[0, 0, 0, 0, 2])          # mock our generation so soledad thinks there's new data to sync          sol._db._get_generation = Mock(return_value=1)          # check for new data to sync diff --git a/src/leap/soledad/tests/test_sqlcipher.py b/soledad/src/leap/soledad/tests/test_sqlcipher.py index 9741bd4e..25d04861 100644 --- a/src/leap/soledad/tests/test_sqlcipher.py +++ b/soledad/src/leap/soledad/tests/test_sqlcipher.py @@ -43,13 +43,13 @@ from u1db.backends.sqlite_backend import SQLitePartialExpandDatabase  # soledad stuff. -from leap.soledad.backends.sqlcipher import ( +from leap.soledad.document import SoledadDocument +from leap.soledad.sqlcipher import (      SQLCipherDatabase,      DatabaseIsNotEncrypted, +    open as u1db_open,  ) -from leap.soledad.backends.sqlcipher import open as u1db_open -from leap.soledad.backends.leap_backend import ( -    LeapDocument, +from leap.soledad.target import (      EncryptionSchemes,      decrypt_doc,      ENC_JSON_KEY, @@ -63,7 +63,7 @@ from leap.soledad.tests.u1db_tests import test_sqlite_backend  from leap.soledad.tests.u1db_tests import test_backends  from leap.soledad.tests.u1db_tests import test_open  from leap.soledad.tests.u1db_tests import test_sync -from leap.soledad.backends.leap_backend import LeapSyncTarget +from leap.soledad.target import SoledadSyncTarget  from leap.common.testing.basetest import BaseLeapTest  PASSWORD = '123456' @@ -115,7 +115,7 @@ def copy_sqlcipher_database_for_test(test, db):  def make_document_for_test(test, doc_id, rev, content, has_conflicts=False): -    return LeapDocument(doc_id, rev, content, has_conflicts=has_conflicts) +    return SoledadDocument(doc_id, rev, content, has_conflicts=has_conflicts)  SQLCIPHER_SCENARIOS = [ @@ -205,7 +205,7 @@ class TestSQLCipherDatabase(test_sqlite_backend.TestSQLiteDatabase):          self.assertTrue(db2._is_initialized(db1._get_sqlite_handle().cursor())) -class TestAlternativeDocument(LeapDocument): +class TestAlternativeDocument(SoledadDocument):      """A (not very) alternative implementation of Document.""" @@ -272,7 +272,7 @@ class TestSQLCipherPartialExpandDatabase(              path, PASSWORD,              document_factory=TestAlternativeDocument)          doc = db2.create_doc({}) -        self.assertTrue(isinstance(doc, LeapDocument)) +        self.assertTrue(isinstance(doc, SoledadDocument))      def test__open_database_non_existent(self):          temp_dir = self.createTempDir(prefix='u1db-test-') @@ -341,7 +341,7 @@ class TestSQLCipherPartialExpandDatabase(              path, PASSWORD, create=False,              document_factory=TestAlternativeDocument)          doc = db2.create_doc({}) -        self.assertTrue(isinstance(doc, LeapDocument)) +        self.assertTrue(isinstance(doc, SoledadDocument))      def test_open_database_create(self):          temp_dir = self.createTempDir(prefix='u1db-test-') @@ -401,7 +401,7 @@ class SQLCipherOpen(test_open.TestU1DBOpen):                         document_factory=TestAlternativeDocument)          self.addCleanup(db.close)          doc = db.create_doc({}) -        self.assertTrue(isinstance(doc, LeapDocument)) +        self.assertTrue(isinstance(doc, SoledadDocument))      def test_open_existing(self):          db = SQLCipherDatabase(self.db_path, PASSWORD) @@ -438,7 +438,7 @@ def sync_via_synchronizer_and_leap(test, db_source, db_target,      if trace_hook:          test.skipTest("full trace hook unsupported over http")      path = test._http_at[db_target] -    target = LeapSyncTarget.connect(test.getURL(path), test._soledad._crypto) +    target = SoledadSyncTarget.connect(test.getURL(path), test._soledad._crypto)      target.set_token_credentials('user-uuid', 'auth-token')      if trace_hook_shallow:          target._set_trace_hook_shallow(trace_hook_shallow) @@ -662,7 +662,7 @@ class SQLCipherDatabaseSyncTests(  def _make_local_db_and_leap_target(test, path='test'):      test.startServer()      db = test.request_state._create_database(os.path.basename(path)) -    st = LeapSyncTarget.connect(test.getURL(path), test._soledad._crypto) +    st = SoledadSyncTarget.connect(test.getURL(path), test._soledad._crypto)      st.set_token_credentials('user-uuid', 'auth-token')      return db, st @@ -791,7 +791,7 @@ class SQLCipherEncryptionTest(BaseLeapTest):              # trying to open an encrypted database with the regular u1db              # backend should raise a DatabaseError exception.              SQLitePartialExpandDatabase(self.DB_FILE, -                                        document_factory=LeapDocument) +                                        document_factory=SoledadDocument)              raise DatabaseIsNotEncrypted()          except dbapi2.DatabaseError:              # at this point we know that the regular U1DB sqlcipher backend @@ -807,7 +807,7 @@ class SQLCipherEncryptionTest(BaseLeapTest):          SQLCipher backend should not succeed to open unencrypted databases.          """          db = SQLitePartialExpandDatabase(self.DB_FILE, -                                         document_factory=LeapDocument) +                                         document_factory=SoledadDocument)          db.create_doc_from_json(tests.simple_doc)          db.close()          try: diff --git a/src/leap/soledad/tests/test_leap_backend.py b/soledad/src/leap/soledad/tests/test_target.py index 6914e869..73c9fe68 100644 --- a/src/leap/soledad/tests/test_leap_backend.py +++ b/soledad/src/leap/soledad/tests/test_target.py @@ -1,5 +1,5 @@  # -*- coding: utf-8 -*- -# test_leap_backend.py +# test_target.py  # Copyright (C) 2013 LEAP  #  # This program is free software: you can redistribute it and/or modify @@ -33,15 +33,17 @@ from u1db.remote import (      http_database,      http_target,  ) -from routes.mapper import Mapper  from leap import soledad -from leap.soledad.backends import leap_backend -from leap.soledad.server import ( +from leap.soledad import ( +    target, +    auth, +) +from leap.soledad.document import SoledadDocument +from leap.soledad_server import (      SoledadApp,      SoledadAuthMiddleware,  ) -from leap.soledad import auth  from leap.soledad.tests import u1db_tests as tests @@ -61,7 +63,7 @@ from leap.soledad.tests.u1db_tests import test_sync  def make_leap_document_for_test(test, doc_id, rev, content,                                  has_conflicts=False): -    return leap_backend.LeapDocument( +    return SoledadDocument(          doc_id, rev, content, has_conflicts=has_conflicts) @@ -126,7 +128,7 @@ def copy_token_http_database_for_test(test, db):      return http_db -class LeapTests(test_backends.AllDatabaseTests, BaseSoledadTest): +class SoledadTests(test_backends.AllDatabaseTests, BaseSoledadTest):      scenarios = LEAP_SCENARIOS + [          ('token_http', {'make_database_for_test': @@ -143,7 +145,7 @@ class LeapTests(test_backends.AllDatabaseTests, BaseSoledadTest):  # The following tests come from `u1db.tests.test_http_client`.  #----------------------------------------------------------------------------- -class TestLeapClientBase(test_http_client.TestHTTPClientBase): +class TestSoledadClientBase(test_http_client.TestHTTPClientBase):      """      This class should be used to test Token auth.      """ @@ -230,13 +232,13 @@ class TestLeapClientBase(test_http_client.TestHTTPClientBase):  # The following tests come from `u1db.tests.test_document`.  #----------------------------------------------------------------------------- -class TestLeapDocument(test_document.TestDocument, BaseSoledadTest): +class TestSoledadDocument(test_document.TestDocument, BaseSoledadTest):      scenarios = ([(          'leap', {'make_document_for_test': make_leap_document_for_test})]) -class TestLeapPyDocument(test_document.TestPyDocument, BaseSoledadTest): +class TestSoledadPyDocument(test_document.TestPyDocument, BaseSoledadTest):      scenarios = ([(          'leap', {'make_document_for_test': make_leap_document_for_test})]) @@ -246,7 +248,7 @@ class TestLeapPyDocument(test_document.TestPyDocument, BaseSoledadTest):  # The following tests come from `u1db.tests.test_remote_sync_target`.  #----------------------------------------------------------------------------- -class TestLeapSyncTargetBasics( +class TestSoledadSyncTargetBasics(          test_remote_sync_target.TestHTTPSyncTargetBasics):      """      Some tests had to be copied to this class so we can instantiate our own @@ -254,14 +256,14 @@ class TestLeapSyncTargetBasics(      """      def test_parse_url(self): -        remote_target = leap_backend.LeapSyncTarget('http://127.0.0.1:12345/') +        remote_target = target.SoledadSyncTarget('http://127.0.0.1:12345/')          self.assertEqual('http', remote_target._url.scheme)          self.assertEqual('127.0.0.1', remote_target._url.hostname)          self.assertEqual(12345, remote_target._url.port)          self.assertEqual('/', remote_target._url.path) -class TestLeapParsingSyncStream( +class TestSoledadParsingSyncStream(          test_remote_sync_target.TestParsingSyncStream,          BaseSoledadTest):      """ @@ -281,10 +283,10 @@ class TestLeapParsingSyncStream(          """          Test adapted to use encrypted content.          """ -        doc = leap_backend.LeapDocument('i', rev='r') +        doc = SoledadDocument('i', rev='r')          doc.content = {} -        enc_json = leap_backend.encrypt_doc(self._soledad._crypto, doc) -        tgt = leap_backend.LeapSyncTarget( +        enc_json = target.encrypt_doc(self._soledad._crypto, doc) +        tgt = target.SoledadSyncTarget(              "http://foo/foo", crypto=self._soledad._crypto)          self.assertRaises(u1db.errors.BrokenSyncStream, @@ -297,7 +299,7 @@ class TestLeapParsingSyncStream(                            lambda doc, gen, trans_id: None)      def test_wrong_start(self): -        tgt = leap_backend.LeapSyncTarget("http://foo/foo") +        tgt = target.SoledadSyncTarget("http://foo/foo")          self.assertRaises(u1db.errors.BrokenSyncStream,                            tgt._parse_sync_stream, "{}\r\n]", None) @@ -309,7 +311,7 @@ class TestLeapParsingSyncStream(                            tgt._parse_sync_stream, "", None)      def test_wrong_end(self): -        tgt = leap_backend.LeapSyncTarget("http://foo/foo") +        tgt = target.SoledadSyncTarget("http://foo/foo")          self.assertRaises(u1db.errors.BrokenSyncStream,                            tgt._parse_sync_stream, "[\r\n{}", None) @@ -318,7 +320,7 @@ class TestLeapParsingSyncStream(                            tgt._parse_sync_stream, "[\r\n", None)      def test_missing_comma(self): -        tgt = leap_backend.LeapSyncTarget("http://foo/foo") +        tgt = target.SoledadSyncTarget("http://foo/foo")          self.assertRaises(u1db.errors.BrokenSyncStream,                            tgt._parse_sync_stream, @@ -326,13 +328,13 @@ class TestLeapParsingSyncStream(                            '"content": "c", "gen": 3}\r\n]', None)      def test_no_entries(self): -        tgt = leap_backend.LeapSyncTarget("http://foo/foo") +        tgt = target.SoledadSyncTarget("http://foo/foo")          self.assertRaises(u1db.errors.BrokenSyncStream,                            tgt._parse_sync_stream, "[\r\n]", None)      def test_error_in_stream(self): -        tgt = leap_backend.LeapSyncTarget("http://foo/foo") +        tgt = target.SoledadSyncTarget("http://foo/foo")          self.assertRaises(u1db.errors.Unavailable,                            tgt._parse_sync_stream, @@ -353,7 +355,7 @@ class TestLeapParsingSyncStream(  #  def leap_sync_target(test, path): -    return leap_backend.LeapSyncTarget( +    return target.SoledadSyncTarget(          test.getURL(path), crypto=test._soledad._crypto) @@ -363,7 +365,7 @@ def token_leap_sync_target(test, path):      return st -class TestLeapSyncTarget( +class TestSoledadSyncTarget(          test_remote_sync_target.TestRemoteSyncTargets, BaseSoledadTest):      scenarios = [ @@ -497,14 +499,14 @@ class TestLeapSyncTarget(  def token_leap_https_sync_target(test, host, path):      _, port = test.server.server_address -    st = leap_backend.LeapSyncTarget( +    st = target.SoledadSyncTarget(          'https://%s:%d/%s' % (host, port, path),          crypto=test._soledad._crypto)      st.set_token_credentials('user-uuid', 'auth-token')      return st -class TestLeapSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSupport, +class TestSoledadSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSupport,                                       BaseSoledadTest):      scenarios = [ @@ -598,7 +600,7 @@ class TestHTTPDatabaseWithCreds(  def _make_local_db_and_leap_target(test, path='test'):      test.startServer()      db = test.request_state._create_database(os.path.basename(path)) -    st = leap_backend.LeapSyncTarget.connect( +    st = target.SoledadSyncTarget.connect(          test.getURL(path), crypto=test._soledad._crypto)      return db, st @@ -616,7 +618,7 @@ target_scenarios = [  ] -class LeapDatabaseSyncTargetTests( +class SoledadDatabaseSyncTargetTests(          test_sync.DatabaseSyncTargetTests, BaseSoledadTest):      scenarios = ( @@ -702,7 +704,7 @@ class LeapDatabaseSyncTargetTests(                   [(doc.doc_id, doc.rev), (doc2.doc_id, doc2.rev)]}) -class TestLeapDbSync(test_sync.TestDbSync, BaseSoledadTest): +class TestSoledadDbSync(test_sync.TestDbSync, BaseSoledadTest):      """Test db.sync remote sync shortcut"""      scenarios = [ @@ -722,7 +724,7 @@ class TestLeapDbSync(test_sync.TestDbSync, BaseSoledadTest):      def do_sync(self, target_name):          """ -        Perform sync using LeapSyncTarget and Token auth. +        Perform sync using SoledadSyncTarget and Token auth.          """          if self.token:              extra = dict(creds={'token': { @@ -732,7 +734,7 @@ class TestLeapDbSync(test_sync.TestDbSync, BaseSoledadTest):              target_url = self.getURL(target_name)              return Synchronizer(                  self.db, -                leap_backend.LeapSyncTarget( +                target.SoledadSyncTarget(                      target_url,                      crypto=self._soledad._crypto,                      **extra)).sync(autocreate=True) diff --git a/src/leap/soledad/tests/u1db_tests/README b/soledad/src/leap/soledad/tests/u1db_tests/README index 605f01fa..605f01fa 100644 --- a/src/leap/soledad/tests/u1db_tests/README +++ b/soledad/src/leap/soledad/tests/u1db_tests/README diff --git a/src/leap/soledad/tests/u1db_tests/__init__.py b/soledad/src/leap/soledad/tests/u1db_tests/__init__.py index 43304b43..43304b43 100644 --- a/src/leap/soledad/tests/u1db_tests/__init__.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/__init__.py diff --git a/src/leap/soledad/tests/u1db_tests/test_backends.py b/soledad/src/leap/soledad/tests/u1db_tests/test_backends.py index a53b01ba..a53b01ba 100644 --- a/src/leap/soledad/tests/u1db_tests/test_backends.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_backends.py diff --git a/src/leap/soledad/tests/u1db_tests/test_document.py b/soledad/src/leap/soledad/tests/u1db_tests/test_document.py index e706e1a9..e706e1a9 100644 --- a/src/leap/soledad/tests/u1db_tests/test_document.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_document.py diff --git a/src/leap/soledad/tests/u1db_tests/test_http_app.py b/soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py index e0729aa2..e0729aa2 100644 --- a/src/leap/soledad/tests/u1db_tests/test_http_app.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py diff --git a/src/leap/soledad/tests/u1db_tests/test_http_client.py b/soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py index 42e98461..42e98461 100644 --- a/src/leap/soledad/tests/u1db_tests/test_http_client.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py diff --git a/src/leap/soledad/tests/u1db_tests/test_http_database.py b/soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py index f21e6da1..f21e6da1 100644 --- a/src/leap/soledad/tests/u1db_tests/test_http_database.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py diff --git a/src/leap/soledad/tests/u1db_tests/test_https.py b/soledad/src/leap/soledad/tests/u1db_tests/test_https.py index 62180f8c..62180f8c 100644 --- a/src/leap/soledad/tests/u1db_tests/test_https.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_https.py diff --git a/src/leap/soledad/tests/u1db_tests/test_open.py b/soledad/src/leap/soledad/tests/u1db_tests/test_open.py index 0ff307e8..0ff307e8 100644 --- a/src/leap/soledad/tests/u1db_tests/test_open.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_open.py diff --git a/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py b/soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py index 66d404d2..66d404d2 100644 --- a/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py diff --git a/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py b/soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py index 1380e4b1..1380e4b1 100644 --- a/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py diff --git a/src/leap/soledad/tests/u1db_tests/test_sync.py b/soledad/src/leap/soledad/tests/u1db_tests/test_sync.py index 96aa2736..96aa2736 100644 --- a/src/leap/soledad/tests/u1db_tests/test_sync.py +++ b/soledad/src/leap/soledad/tests/u1db_tests/test_sync.py diff --git a/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile index 2385e75b..2385e75b 100644 --- a/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile +++ b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile diff --git a/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem index c019a730..c019a730 100644 --- a/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem +++ b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem diff --git a/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert index 985684fb..985684fb 100644 --- a/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert +++ b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert diff --git a/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key index d83d4920..d83d4920 100644 --- a/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key +++ b/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key diff --git a/pkg/soledad b/soledad_server/pkg/soledad index c640a94d..c640a94d 100644 --- a/pkg/soledad +++ b/soledad_server/pkg/soledad diff --git a/soledad_server/setup.py b/soledad_server/setup.py new file mode 100644 index 00000000..522c86ff --- /dev/null +++ b/soledad_server/setup.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# setup.py +# Copyright (C) 2013 LEAP +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import os +from setuptools import ( +    setup, +    find_packages +) + + +install_requirements = [ +    'configparser', +    'couchdb', +    'simplejson', +    'twisted>=12.0.0',  # TODO: maybe we just want twisted-web? +    'oauth',  # this is not strictly needed by us, but we need it +              # until u1db adds it to its release as a dep. +    'u1db', +    'six==1.1.0', +    'routes', +    'PyOpenSSL', +] + + +if os.environ.get('VIRTUAL_ENV', None): +    data_files = None +else: +    # XXX this should go only for linux/mac +    data_files = [("/etc/init.d/", ["pkg/soledad"])] + +trove_classifiers = ( +    "Development Status :: 3 - Alpha", +    "Intended Audience :: Developers", +    "License :: OSI Approved :: " +    "GNU General Public License v3 or later (GPLv3+)", +    "Environment :: Console", +    "Operating System :: OS Independent", +    "Operating System :: POSIX", +    "Programming Language :: Python :: 2.6", +    "Programming Language :: Python :: 2.7", +    "Topic :: Database :: Front-Ends", +    "Topic :: Software Development :: Libraries :: Python Modules" +) + +setup( +    name='leap.soledad_server', +    version='0.1.1', +    url='https://leap.se/', +    license='GPLv3+', +    description='Synchronization of locally encrypted data among devices.', +    author='The LEAP Encryption Access Project', +    author_email='info@leap.se', +    long_description=( +        "Soledad is the part of LEAP that allows application data to be " +        "securely shared among devices. It provides, to other parts of the " +        "LEAP client, an API for data storage and sync." +    ), +    namespace_packages=["leap"], +    packages=find_packages('src'), +    package_dir={'': 'src'}, +    install_requires=install_requirements, +    data_files=data_files, +    classifiers=trove_classifiers, +) diff --git a/soledad_server/src/leap/__init__.py b/soledad_server/src/leap/__init__.py new file mode 100644 index 00000000..f48ad105 --- /dev/null +++ b/soledad_server/src/leap/__init__.py @@ -0,0 +1,6 @@ +# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages +try: +    __import__('pkg_resources').declare_namespace(__name__) +except ImportError: +    from pkgutil import extend_path +    __path__ = extend_path(__path__, __name__) diff --git a/src/leap/soledad/server.py b/soledad_server/src/leap/soledad_server/__init__.py index 9c9e0ad7..bea5d5fd 100644 --- a/src/leap/soledad/server.py +++ b/soledad_server/src/leap/soledad_server/__init__.py @@ -20,7 +20,7 @@  A U1DB server that stores data using CouchDB as its persistence layer.  This should be run with: -    twistd -n web --wsgi=leap.soledad.server.application --port=2424 +    twistd -n web --wsgi=leap.soledad_server.application --port=2424  """  import configparser @@ -53,7 +53,7 @@ if version.base() == "12.0.0":  from couchdb.client import Server  from leap.soledad import SECRETS_DOC_ID_HASH_PREFIX -from leap.soledad.backends.couch import CouchServerState +from leap.soledad_server.couch import CouchServerState  #----------------------------------------------------------------------------- @@ -126,7 +126,7 @@ class URLToAuth(object):          @return: The database name corresponding to C{uuid}.          @rtype: str          """ -        return sha256('%s%s' % (SECRETS_DOC_ID_HASH_PREFIX, uuid)).hexdigest() +        return '%s%s' % (SoledadApp.USER_DB_PREFIX, uuid)      def _register_auth_info(self, dbname):          """ @@ -329,6 +329,11 @@ class SoledadApp(http_app.HTTPApp):      The name of the shared database that holds user's encrypted secrets.      """ +    USER_DB_PREFIX = 'uuid-' +    """ +    The string prefix of users' databases. +    """ +      def __call__(self, environ, start_response):          """          Handle a WSGI call to the Soledad application. diff --git a/src/leap/soledad/backends/couch.py b/soledad_server/src/leap/soledad_server/couch.py index 57885012..ed5ad6b3 100644 --- a/src/leap/soledad/backends/couch.py +++ b/soledad_server/src/leap/soledad_server/couch.py @@ -34,11 +34,10 @@ from couchdb.client import Server, Document as CouchDocument  from couchdb.http import ResourceNotFound -from leap.soledad.backends.objectstore import ( +from leap.soledad_server.objectstore import (      ObjectStoreDatabase,      ObjectStoreSyncTarget,  ) -from leap.soledad.backends.leap_backend import LeapDocument  class InvalidURLError(Exception): @@ -120,10 +119,7 @@ class CouchDatabase(ObjectStoreDatabase):          except ResourceNotFound:              self._server.create(self._dbname)              self._database = self._server[self._dbname] -        ObjectStoreDatabase.__init__(self, replica_uid=replica_uid, -                                     # TODO: move the factory choice -                                     # away -                                     document_factory=LeapDocument) +        ObjectStoreDatabase.__init__(self, replica_uid=replica_uid)      #-------------------------------------------------------------------------      # methods from Database diff --git a/src/leap/soledad/backends/objectstore.py b/soledad_server/src/leap/soledad_server/objectstore.py index 8afac3ec..8afac3ec 100644 --- a/src/leap/soledad/backends/objectstore.py +++ b/soledad_server/src/leap/soledad_server/objectstore.py diff --git a/src/leap/soledad/backends/__init__.py b/src/leap/soledad/backends/__init__.py deleted file mode 100644 index 737c08e6..00000000 --- a/src/leap/soledad/backends/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# __init__.py -# Copyright (C) 2013 LEAP -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - - -""" -Backends that extend U1DB functionality. -""" | 
