summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomás Touceda <chiiph@leap.se>2013-08-21 14:50:28 -0300
committerTomás Touceda <chiiph@leap.se>2013-08-21 14:50:28 -0300
commit0de5ddd4aa0bb2eef41572d61304719939f4f459 (patch)
tree5ca9d38c3a77a57e7903c8c7da9c03892917ce26
parentcb9453ea3abc35adb3707f2c9877777cc7a27893 (diff)
parent50e5a604096365509b5d1a1fe810f4ec019eb0ee (diff)
Merge remote-tracking branch 'drebs/feature/3487_split-soledad-into-common-client-and-server-3' into develop
-rw-r--r--.gitignore6
-rw-r--r--README.rst16
-rw-r--r--client/changes/feature_3118-provide-a-way-to-access-the-saved-password (renamed from soledad/changes/feature_3118-provide-a-way-to-access-the-saved-password)0
-rw-r--r--client/changes/feature_3487-split-soledad-into-common-client-and-server1
-rw-r--r--client/setup.py (renamed from soledad/setup.py)21
-rw-r--r--client/src/leap/__init__.py (renamed from soledad/src/leap/__init__.py)0
-rw-r--r--client/src/leap/soledad/__init__.py (renamed from soledad_server/src/leap/__init__.py)0
-rw-r--r--client/src/leap/soledad/client/__init__.py (renamed from soledad/src/leap/soledad/__init__.py)64
-rw-r--r--client/src/leap/soledad/client/auth.py (renamed from soledad/src/leap/soledad/auth.py)3
-rw-r--r--client/src/leap/soledad/client/crypto.py (renamed from soledad/src/leap/soledad/crypto.py)2
-rw-r--r--client/src/leap/soledad/client/dbwrapper.py (renamed from soledad/src/leap/soledad/dbwrapper.py)2
-rw-r--r--client/src/leap/soledad/client/shared_db.py (renamed from soledad/src/leap/soledad/shared_db.py)2
-rw-r--r--client/src/leap/soledad/client/sqlcipher.py (renamed from soledad/src/leap/soledad/sqlcipher.py)117
-rw-r--r--client/src/leap/soledad/client/target.py (renamed from soledad/src/leap/soledad/target.py)50
-rw-r--r--common/changes/feature_3487-split-soledad-into-common-client-and-server1
-rw-r--r--common/setup.py79
-rw-r--r--common/src/leap/__init__.py6
-rw-r--r--common/src/leap/soledad/__init__.py6
-rw-r--r--common/src/leap/soledad/common/__init__.py64
-rw-r--r--common/src/leap/soledad/common/couch.py (renamed from soledad_server/src/leap/soledad_server/couch.py)3
-rw-r--r--common/src/leap/soledad/common/crypto.py55
-rw-r--r--common/src/leap/soledad/common/document.py (renamed from soledad/src/leap/soledad/document.py)0
-rw-r--r--common/src/leap/soledad/common/objectstore.py (renamed from soledad_server/src/leap/soledad_server/objectstore.py)3
-rw-r--r--common/src/leap/soledad/common/tests/__init__.py (renamed from soledad/src/leap/soledad/tests/__init__.py)24
-rw-r--r--common/src/leap/soledad/common/tests/couchdb.ini.template (renamed from soledad/src/leap/soledad/tests/couchdb.ini.template)0
-rw-r--r--common/src/leap/soledad/common/tests/test_couch.py (renamed from soledad/src/leap/soledad/tests/test_couch.py)10
-rw-r--r--common/src/leap/soledad/common/tests/test_crypto.py (renamed from soledad/src/leap/soledad/tests/test_crypto.py)12
-rw-r--r--common/src/leap/soledad/common/tests/test_server.py (renamed from soledad/src/leap/soledad/tests/test_server.py)22
-rw-r--r--common/src/leap/soledad/common/tests/test_soledad.py (renamed from soledad/src/leap/soledad/tests/test_soledad.py)111
-rw-r--r--common/src/leap/soledad/common/tests/test_sqlcipher.py (renamed from soledad/src/leap/soledad/tests/test_sqlcipher.py)25
-rw-r--r--common/src/leap/soledad/common/tests/test_target.py (renamed from soledad/src/leap/soledad/tests/test_target.py)44
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/README (renamed from soledad/src/leap/soledad/tests/u1db_tests/README)0
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/__init__.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/__init__.py)7
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_backends.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_backends.py)4
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_document.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_document.py)2
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_http_app.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py)2
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_http_client.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py)2
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_http_database.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py)4
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_https.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_https.py)6
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_open.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_open.py)4
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_remote_sync_target.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py)2
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_sqlite_backend.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py)4
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/test_sync.py (renamed from soledad/src/leap/soledad/tests/u1db_tests/test_sync.py)10
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/testing-certs/Makefile (renamed from soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile)0
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/testing-certs/cacert.pem (renamed from soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem)0
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.cert (renamed from soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert)0
-rw-r--r--common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.key (renamed from soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key)0
-rw-r--r--server/changes/feature_3487-split-soledad-into-common-client-and-server1
-rw-r--r--server/pkg/soledad (renamed from soledad_server/pkg/soledad)0
-rw-r--r--server/setup.py (renamed from soledad_server/setup.py)9
-rw-r--r--server/src/leap/__init__.py6
-rw-r--r--server/src/leap/soledad/__init__.py6
-rw-r--r--server/src/leap/soledad/server/__init__.py (renamed from soledad_server/src/leap/soledad_server/__init__.py)6
-rw-r--r--server/src/leap/soledad/server/auth.py (renamed from soledad_server/src/leap/soledad_server/auth.py)0
-rw-r--r--soledad/src/leap/soledad/backends/__init__.py0
-rw-r--r--soledad/src/leap/soledad/backends/leap_backend.py73
56 files changed, 526 insertions, 371 deletions
diff --git a/.gitignore b/.gitignore
index 4d06b77d..701f48fc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,10 @@ build/
MANIFEST
*.egg-info/
*.egg
+*.swp
+*.swo
+*.pyc
+*.log
+*.*~
+
diff --git a/README.rst b/README.rst
index ccf8d5da..c2a33234 100644
--- a/README.rst
+++ b/README.rst
@@ -14,18 +14,16 @@ Library dependencies
Tests
-----
-Client and server tests are both included in leap.soledad. Because
-soledad_server depends on soledad and soledad tests depend on soledad_server,
-if you want to run tests in development mode you must first install soledad,
-then soledad_server, and then run the tests.
+Client and server tests are both included in leap.soledad.common. If you want
+to run tests in development mode you must do the following::
-Therefore, tests must be run with::
-
- cd soledad
+ cd common
+ python setup.py develop
+ cd ../client
python setup.py develop
- cd ../soledad_server
+ cd ../server
python setup.py develop
- cd ../soledad
+ cd ../common
python setup.py test
Note that to run CouchDB tests, be sure you have ``CouchDB`` installed on your
diff --git a/soledad/changes/feature_3118-provide-a-way-to-access-the-saved-password b/client/changes/feature_3118-provide-a-way-to-access-the-saved-password
index 69cb0b1d..69cb0b1d 100644
--- a/soledad/changes/feature_3118-provide-a-way-to-access-the-saved-password
+++ b/client/changes/feature_3118-provide-a-way-to-access-the-saved-password
diff --git a/client/changes/feature_3487-split-soledad-into-common-client-and-server b/client/changes/feature_3487-split-soledad-into-common-client-and-server
new file mode 100644
index 00000000..2eab6b56
--- /dev/null
+++ b/client/changes/feature_3487-split-soledad-into-common-client-and-server
@@ -0,0 +1 @@
+ o Split soledad package into common, client and server. Closes #3487.
diff --git a/soledad/setup.py b/client/setup.py
index 6da976a9..291c95fe 100644
--- a/soledad/setup.py
+++ b/client/setup.py
@@ -29,20 +29,10 @@ install_requirements = [
'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',
'scrypt',
'pyxdg',
'pycryptopp',
-]
-
-
-tests_requirements = [
- 'mock',
- 'nose2',
- 'testscenarios',
- 'leap.common',
- 'leap.soledad_server',
- 'pyOpenSSL',
+ 'leap.soledad.common>=0.3.0',
]
@@ -60,8 +50,9 @@ trove_classifiers = (
"Topic :: Software Development :: Libraries :: Python Modules"
)
+
setup(
- name='leap.soledad',
+ name='leap.soledad.client',
version='0.3.0',
url='https://leap.se/',
license='GPLv3+',
@@ -73,12 +64,10 @@ setup(
"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', exclude=['leap.soledad.tests']),
+ namespace_packages=["leap", "leap.soledad"],
+ packages=find_packages('src'),
package_dir={'': 'src'},
- test_suite='leap.soledad.tests',
install_requires=install_requirements,
- tests_require=tests_requirements,
classifiers=trove_classifiers,
extras_require={'signaling': ['leap.common']},
)
diff --git a/soledad/src/leap/__init__.py b/client/src/leap/__init__.py
index f48ad105..f48ad105 100644
--- a/soledad/src/leap/__init__.py
+++ b/client/src/leap/__init__.py
diff --git a/soledad_server/src/leap/__init__.py b/client/src/leap/soledad/__init__.py
index f48ad105..f48ad105 100644
--- a/soledad_server/src/leap/__init__.py
+++ b/client/src/leap/soledad/__init__.py
diff --git a/soledad/src/leap/soledad/__init__.py b/client/src/leap/soledad/client/__init__.py
index 3fe9629f..fc8219fa 100644
--- a/soledad/src/leap/soledad/__init__.py
+++ b/client/src/leap/soledad/client/__init__.py
@@ -45,49 +45,6 @@ from u1db.remote.ssl_match_hostname import match_hostname
#
-# Assert functions
-#
-
-# we want to use leap.common.check.leap_assert in case it is available,
-# because it also logs in a way other parts of leap can access log messages.
-
-try:
- from leap.common.check import leap_assert as soledad_assert
-
-except ImportError:
-
- def soledad_assert(condition, message):
- """
- Asserts the condition and displays the message if that's not
- met.
-
- @param condition: condition to check
- @type condition: bool
- @param message: message to display if the condition isn't met
- @type message: str
- """
- assert condition, message
-
-try:
- from leap.common.check import leap_assert_type as soledad_assert_type
-
-except ImportError:
-
- def soledad_assert_type(var, expectedType):
- """
- Helper assert check for a variable's expected type
-
- @param var: variable to check
- @type var: any
- @param expectedType: type to check agains
- @type expectedType: type
- """
- soledad_assert(isinstance(var, expectedType),
- "Expected type %r instead of %r" %
- (expectedType, type(var)))
-
-
-#
# Signaling function
#
@@ -124,13 +81,14 @@ except ImportError:
logger.info("Would signal: %s - %s." % (str(signal), content))
-from leap.soledad.crypto import SoledadCrypto
-from leap.soledad.dbwrapper import SQLCipherWrapper
-from leap.soledad.document import SoledadDocument
-from leap.soledad.shared_db import SoledadSharedDatabase
-from leap.soledad.sqlcipher import open as sqlcipher_open
-from leap.soledad.sqlcipher import SQLCipherDatabase
-from leap.soledad.target import SoledadSyncTarget
+from leap.soledad.common import soledad_assert, soledad_assert_type
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.client.crypto import SoledadCrypto
+from leap.soledad.client.dbwrapper import SQLCipherWrapper
+from leap.soledad.client.shared_db import SoledadSharedDatabase
+from leap.soledad.client.sqlcipher import open as sqlcipher_open
+from leap.soledad.client.sqlcipher import SQLCipherDatabase
+from leap.soledad.client.target import SoledadSyncTarget
logger = logging.getLogger(name=__name__)
@@ -429,8 +387,7 @@ class Soledad(object):
buflen=32, # we need a key with 256 bits (32 bytes)
)
- # Instantiate a thread-safe wrapper
- self._db = SQLCipherWrapper(
+ self._db = sqlcipher_open(
self._local_db_path,
binascii.b2a_hex(key), # sqlcipher only accepts the hex version
create=True,
@@ -444,7 +401,7 @@ class Soledad(object):
"""
if hasattr(self, '_db') and isinstance(
self._db,
- SQLCipherWrapper):
+ SQLCipherDatabase):
self._db.close()
def __del__(self):
@@ -650,6 +607,7 @@ class Soledad(object):
self.SECRET_KEY: '%s%s%s' % (
str(iv), self.IV_SEPARATOR, binascii.b2a_base64(ciphertext)),
}
+
self._store_secrets()
self._passphrase = new_passphrase
diff --git a/soledad/src/leap/soledad/auth.py b/client/src/leap/soledad/client/auth.py
index 81e838d2..3cd6dabe 100644
--- a/soledad/src/leap/soledad/auth.py
+++ b/client/src/leap/soledad/client/auth.py
@@ -67,4 +67,5 @@ class TokenBasedAuth(object):
return [('Authorization', 'Token %s' % auth.encode('base64')[:-1])]
else:
raise errors.UnknownAuthMethod(
- 'Wrong credentials: %s' % self._creds) \ No newline at end of file
+ 'Wrong credentials: %s' % self._creds)
+
diff --git a/soledad/src/leap/soledad/crypto.py b/client/src/leap/soledad/client/crypto.py
index 3c1061d5..9fcff8e9 100644
--- a/soledad/src/leap/soledad/crypto.py
+++ b/client/src/leap/soledad/client/crypto.py
@@ -31,7 +31,7 @@ from pycryptopp.cipher.aes import AES
from pycryptopp.cipher.xsalsa20 import XSalsa20
-from leap.soledad import (
+from leap.soledad.common import (
soledad_assert,
soledad_assert_type,
)
diff --git a/soledad/src/leap/soledad/dbwrapper.py b/client/src/leap/soledad/client/dbwrapper.py
index c16c4925..a27a933e 100644
--- a/soledad/src/leap/soledad/dbwrapper.py
+++ b/client/src/leap/soledad/client/dbwrapper.py
@@ -31,7 +31,7 @@ import exceptions
from functools import partial
-from leap.soledad import sqlcipher
+from leap.soledad.client import sqlcipher
logger = logging.getLogger(__name__)
diff --git a/soledad/src/leap/soledad/shared_db.py b/client/src/leap/soledad/client/shared_db.py
index 33c5c484..a6ca504d 100644
--- a/soledad/src/leap/soledad/shared_db.py
+++ b/client/src/leap/soledad/client/shared_db.py
@@ -26,7 +26,7 @@ import simplejson as json
from u1db.remote import http_database
-from leap.soledad.auth import TokenBasedAuth
+from leap.soledad.client.auth import TokenBasedAuth
#-----------------------------------------------------------------------------
diff --git a/soledad/src/leap/soledad/sqlcipher.py b/client/src/leap/soledad/client/sqlcipher.py
index acbeabe6..c605c28c 100644
--- a/soledad/src/leap/soledad/sqlcipher.py
+++ b/client/src/leap/soledad/client/sqlcipher.py
@@ -43,23 +43,33 @@ So, as the statements above were introduced for backwards compatibility with
SLCipher 1.1 databases, we do not implement them as all SQLCipher databases
handled by Soledad should be created by SQLCipher >= 2.0.
"""
-
+import logging
import os
import time
import string
+import threading
from u1db.backends import sqlite_backend
from pysqlcipher import dbapi2
-from u1db import (
- errors,
-)
-from leap.soledad.document import SoledadDocument
+from u1db import errors as u1db_errors
+from leap.soledad.common.document import SoledadDocument
+
+logger = logging.getLogger(__name__)
# Monkey-patch u1db.backends.sqlite_backend with pysqlcipher.dbapi2
sqlite_backend.dbapi2 = dbapi2
+# It seems that, as long as we are not using old sqlite versions, serialized
+# mode is enabled by default at compile time. So accessing db connections from
+# different threads should be safe, as long as no attempt is made to use them
+# from multiple threads with no locking.
+# See https://sqlite.org/threadsafe.html
+# and http://bugs.python.org/issue16509
+
+SQLITE_CHECK_SAME_THREAD = False
+
def open(path, password, create=True, document_factory=None, crypto=None,
raw_key=False, cipher='aes-256-cbc', kdf_iter=4000,
@@ -125,6 +135,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
"""A U1DB implementation that uses SQLCipher as its persistence layer."""
_index_storage_value = 'expand referenced encrypted'
+ k_lock = threading.Lock()
def __init__(self, sqlcipher_file, password, document_factory=None,
crypto=None, raw_key=False, cipher='aes-256-cbc',
@@ -158,20 +169,23 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
sqlcipher_file, password, raw_key, cipher, kdf_iter,
cipher_page_size)
# connect to the database
- self._db_handle = dbapi2.connect(sqlcipher_file)
- # set SQLCipher cryptographic parameters
- self._set_crypto_pragmas(
- self._db_handle, password, raw_key, cipher, kdf_iter,
- cipher_page_size)
- self._real_replica_uid = None
- self._ensure_schema()
- self._crypto = crypto
+ with self.k_lock:
+ self._db_handle = dbapi2.connect(
+ sqlcipher_file,
+ check_same_thread=SQLITE_CHECK_SAME_THREAD)
+ # set SQLCipher cryptographic parameters
+ self._set_crypto_pragmas(
+ self._db_handle, password, raw_key, cipher, kdf_iter,
+ cipher_page_size)
+ self._real_replica_uid = None
+ self._ensure_schema()
+ self._crypto = crypto
def factory(doc_id=None, rev=None, json='{}', has_conflicts=False,
syncable=True):
return SoledadDocument(doc_id=doc_id, rev=rev, json=json,
- has_conflicts=has_conflicts,
- syncable=syncable)
+ has_conflicts=has_conflicts,
+ syncable=syncable)
self.set_document_factory(factory)
@classmethod
@@ -205,22 +219,35 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
@rtype: SQLCipherDatabase
"""
if not os.path.isfile(sqlcipher_file):
- raise errors.DatabaseDoesNotExist()
+ raise u1db_errors.DatabaseDoesNotExist()
+
tries = 2
+ # 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
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(sqlcipher_file)
- # set cryptographic params
- cls._set_crypto_pragmas(
- db_handle, password, raw_key, cipher, kdf_iter,
- cipher_page_size)
- c = db_handle.cursor()
- v, err = cls._which_index_storage(c)
- db_handle.close()
- if v is not None:
- break
+
+ with cls.k_lock:
+ db_handle = dbapi2.connect(
+ sqlcipher_file,
+ check_same_thread=SQLITE_CHECK_SAME_THREAD)
+
+ try:
+ # set cryptographic params
+ cls._set_crypto_pragmas(
+ db_handle, password, raw_key, cipher, kdf_iter,
+ cipher_page_size)
+ c = db_handle.cursor()
+ # XXX if we use it here, it should be public
+ v, err = cls._which_index_storage(c)
+ except Exception as exc:
+ logger.warning("ERROR OPENING DATABASE!")
+ logger.debug("error was: %r" % exc)
+ v, err = None, exc
+ finally:
+ db_handle.close()
+ if v is not None:
+ break
# possibly another process is initializing it, wait for it to be
# done
if tries == 0:
@@ -273,7 +300,7 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
sqlcipher_file, password, document_factory=document_factory,
crypto=crypto, raw_key=raw_key, cipher=cipher,
kdf_iter=kdf_iter, cipher_page_size=cipher_page_size)
- except errors.DatabaseDoesNotExist:
+ except u1db_errors.DatabaseDoesNotExist:
if not create:
raise
# TODO: remove backend class from here.
@@ -301,17 +328,21 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
@rtype: int
"""
from u1db.sync import Synchronizer
- from leap.soledad.target import SoledadSyncTarget
+ from leap.soledad.client.target import SoledadSyncTarget
return Synchronizer(
self,
SoledadSyncTarget(url,
- creds=creds,
- crypto=self._crypto)).sync(autocreate=autocreate)
+ creds=creds,
+ crypto=self._crypto)).sync(autocreate=autocreate)
def _extra_schema_init(self, c):
"""
Add any extra fields, etc to the basic table definitions.
+ This method is called by u1db.backends.sqlite_backend._initialize()
+ method, which is executed when the database schema is created. Here,
+ we use it to include the "syncable" property for LeapDocuments.
+
@param c: The cursor for querying the database.
@type c: dbapi2.cursor
"""
@@ -402,10 +433,15 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
except dbapi2.DatabaseError:
# assert that we can access it using SQLCipher with the given
# key
- db_handle = dbapi2.connect(sqlcipher_file)
- cls._set_crypto_pragmas(
- db_handle, key, raw_key, cipher, kdf_iter, cipher_page_size)
- db_handle.cursor().execute('SELECT count(*) FROM sqlite_master')
+ with cls.k_lock:
+ db_handle = dbapi2.connect(
+ sqlcipher_file,
+ check_same_thread=SQLITE_CHECK_SAME_THREAD)
+ cls._set_crypto_pragmas(
+ db_handle, key, raw_key, cipher,
+ kdf_iter, cipher_page_size)
+ db_handle.cursor().execute(
+ 'SELECT count(*) FROM sqlite_master')
@classmethod
def _set_crypto_pragmas(cls, db_handle, key, raw_key, cipher, kdf_iter,
@@ -649,5 +685,12 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
raise NotAnHexString(key)
db_handle.cursor().execute('PRAGMA rekey = "x\'%s"' % passphrase)
+ def __del__(self):
+ """
+ Closes db_handle upon object destruction.
+ """
+ if self._db_handle is not None:
+ self._db_handle.close()
+
sqlite_backend.SQLiteDatabase.register_implementation(SQLCipherDatabase)
diff --git a/soledad/src/leap/soledad/target.py b/client/src/leap/soledad/client/target.py
index cad51b74..d0bc3706 100644
--- a/soledad/src/leap/soledad/target.py
+++ b/client/src/leap/soledad/client/target.py
@@ -32,13 +32,23 @@ 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 (
+from leap.soledad.common import soledad_assert
+from leap.soledad.common.crypto import (
+ EncryptionSchemes,
+ MacMethods,
+ ENC_JSON_KEY,
+ ENC_SCHEME_KEY,
+ ENC_METHOD_KEY,
+ ENC_IV_KEY,
+ MAC_KEY,
+ MAC_METHOD_KEY,
+)
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.client.auth import TokenBasedAuth
+from leap.soledad.client.crypto import (
EncryptionMethods,
UnknownEncryptionMethod,
)
-from leap.soledad.auth import TokenBasedAuth
#
@@ -74,38 +84,9 @@ class WrongMac(Exception):
#
-# Encryption schemes used for encryption.
-#
-
-class EncryptionSchemes(object):
- """
- Representation of encryption schemes used to encrypt documents.
- """
-
- NONE = 'none'
- SYMKEY = 'symkey'
- PUBKEY = 'pubkey'
-
-
-class MacMethods(object):
- """
- Representation of MAC methods used to authenticate document's contents.
- """
-
- HMAC = 'hmac'
-
-
-#
# Crypto utilities for a SoledadDocument.
#
-ENC_JSON_KEY = '_enc_json'
-ENC_SCHEME_KEY = '_enc_scheme'
-ENC_METHOD_KEY = '_enc_method'
-ENC_IV_KEY = '_enc_iv'
-MAC_KEY = '_mac'
-MAC_METHOD_KEY = '_mac_method'
-
def mac_doc(crypto, doc_id, doc_rev, ciphertext, mac_method):
"""
@@ -367,7 +348,8 @@ class SoledadSyncTarget(HTTPSyncTarget, TokenBasedAuth):
#-------------------------------------------------------------
# if arriving content was symmetrically encrypted, we decrypt
# it.
- doc = SoledadDocument(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:
diff --git a/common/changes/feature_3487-split-soledad-into-common-client-and-server b/common/changes/feature_3487-split-soledad-into-common-client-and-server
new file mode 100644
index 00000000..2eab6b56
--- /dev/null
+++ b/common/changes/feature_3487-split-soledad-into-common-client-and-server
@@ -0,0 +1 @@
+ o Split soledad package into common, client and server. Closes #3487.
diff --git a/common/setup.py b/common/setup.py
new file mode 100644
index 00000000..6a432608
--- /dev/null
+++ b/common/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/>.
+
+
+from setuptools import (
+ setup,
+ find_packages
+)
+
+
+install_requirements = [
+ 'simplejson',
+ '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', # some tests are incompatible with newer versions of six.
+]
+
+
+tests_requirements = [
+ 'mock',
+ 'nose2',
+ 'testscenarios',
+ 'leap.common',
+ 'leap.soledad.server',
+ 'leap.soledad.client',
+]
+
+
+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.common',
+ version='0.3.0',
+ 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", "leap.soledad"],
+ packages=find_packages('src', exclude=['leap.soledad.common.tests']),
+ package_dir={'': 'src'},
+ test_suite='leap.soledad.common.tests',
+ install_requires=install_requirements,
+ tests_require=tests_requirements,
+ classifiers=trove_classifiers,
+)
diff --git a/common/src/leap/__init__.py b/common/src/leap/__init__.py
new file mode 100644
index 00000000..f48ad105
--- /dev/null
+++ b/common/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/common/src/leap/soledad/__init__.py b/common/src/leap/soledad/__init__.py
new file mode 100644
index 00000000..f48ad105
--- /dev/null
+++ b/common/src/leap/soledad/__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/common/src/leap/soledad/common/__init__.py b/common/src/leap/soledad/common/__init__.py
new file mode 100644
index 00000000..4e45b828
--- /dev/null
+++ b/common/src/leap/soledad/common/__init__.py
@@ -0,0 +1,64 @@
+# -*- 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/>.
+
+
+"""
+Soledad routines common to client and server.
+"""
+
+
+#
+# Assert functions
+#
+
+# we want to use leap.common.check.leap_assert in case it is available,
+# because it also logs in a way other parts of leap can access log messages.
+
+try:
+ from leap.common.check import leap_assert as soledad_assert
+
+except ImportError:
+
+ def soledad_assert(condition, message):
+ """
+ Asserts the condition and displays the message if that's not
+ met.
+
+ @param condition: condition to check
+ @type condition: bool
+ @param message: message to display if the condition isn't met
+ @type message: str
+ """
+ assert condition, message
+
+try:
+ from leap.common.check import leap_assert_type as soledad_assert_type
+
+except ImportError:
+
+ def soledad_assert_type(var, expectedType):
+ """
+ Helper assert check for a variable's expected type
+
+ @param var: variable to check
+ @type var: any
+ @param expectedType: type to check agains
+ @type expectedType: type
+ """
+ soledad_assert(isinstance(var, expectedType),
+ "Expected type %r instead of %r" %
+ (expectedType, type(var)))
diff --git a/soledad_server/src/leap/soledad_server/couch.py b/common/src/leap/soledad/common/couch.py
index ed5ad6b3..9642e8f3 100644
--- a/soledad_server/src/leap/soledad_server/couch.py
+++ b/common/src/leap/soledad/common/couch.py
@@ -18,7 +18,6 @@
"""A U1DB backend that uses CouchDB as its persistence layer."""
-# general imports
import uuid
import re
import simplejson as json
@@ -34,7 +33,7 @@ from couchdb.client import Server, Document as CouchDocument
from couchdb.http import ResourceNotFound
-from leap.soledad_server.objectstore import (
+from leap.soledad.common.objectstore import (
ObjectStoreDatabase,
ObjectStoreSyncTarget,
)
diff --git a/common/src/leap/soledad/common/crypto.py b/common/src/leap/soledad/common/crypto.py
new file mode 100644
index 00000000..2c6bd7a3
--- /dev/null
+++ b/common/src/leap/soledad/common/crypto.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+# crypto.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/>.
+
+
+"""
+Soledad common crypto bits.
+"""
+
+
+#
+# Encryption schemes used for encryption.
+#
+
+class EncryptionSchemes(object):
+ """
+ Representation of encryption schemes used to encrypt documents.
+ """
+
+ NONE = 'none'
+ SYMKEY = 'symkey'
+ PUBKEY = 'pubkey'
+
+
+class MacMethods(object):
+ """
+ Representation of MAC methods used to authenticate document's contents.
+ """
+
+ HMAC = 'hmac'
+
+
+#
+# Crypto utilities for a SoledadDocument.
+#
+
+ENC_JSON_KEY = '_enc_json'
+ENC_SCHEME_KEY = '_enc_scheme'
+ENC_METHOD_KEY = '_enc_method'
+ENC_IV_KEY = '_enc_iv'
+MAC_KEY = '_mac'
+MAC_METHOD_KEY = '_mac_method'
diff --git a/soledad/src/leap/soledad/document.py b/common/src/leap/soledad/common/document.py
index cc24b53a..cc24b53a 100644
--- a/soledad/src/leap/soledad/document.py
+++ b/common/src/leap/soledad/common/document.py
diff --git a/soledad_server/src/leap/soledad_server/objectstore.py b/common/src/leap/soledad/common/objectstore.py
index 8afac3ec..921cf075 100644
--- a/soledad_server/src/leap/soledad_server/objectstore.py
+++ b/common/src/leap/soledad/common/objectstore.py
@@ -26,11 +26,12 @@ extended to implement OpenStack or Amazon S3 storage, for example.
See U1DB documentation for more information on how to use databases.
"""
+
+from u1db import errors
from u1db.backends.inmemory import (
InMemoryDatabase,
InMemorySyncTarget,
)
-from u1db import errors
class ObjectStoreDatabase(InMemoryDatabase):
diff --git a/soledad/src/leap/soledad/tests/__init__.py b/common/src/leap/soledad/common/tests/__init__.py
index b33f866c..9f47d74a 100644
--- a/soledad/src/leap/soledad/tests/__init__.py
+++ b/common/src/leap/soledad/common/tests/__init__.py
@@ -3,14 +3,16 @@ Tests to make sure Soledad provides U1DB functionality and more.
"""
import os
+import random
+import string
import u1db
from mock import Mock
-from leap.soledad import Soledad
-from leap.soledad.document import SoledadDocument
-from leap.soledad.crypto import SoledadCrypto
-from leap.soledad.target import (
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.client import Soledad
+from leap.soledad.client.crypto import SoledadCrypto
+from leap.soledad.client.target import (
decrypt_doc,
ENC_SCHEME_KEY,
)
@@ -40,16 +42,23 @@ class BaseSoledadTest(BaseLeapTest):
document_factory=SoledadDocument)
self._db2 = u1db.open(self.db2_file, create=True,
document_factory=SoledadDocument)
+ # get a random prefix for each test, so we do not mess with
+ # concurrency during initialization and shutting down of
+ # each local db.
+ self.rand_prefix = ''.join(
+ map(lambda x: random.choice(string.ascii_letters), range(6)))
# initialize soledad by hand so we can control keys
- self._soledad = self._soledad_instance(user=self.email)
+ self._soledad = self._soledad_instance(
+ prefix=self.rand_prefix, user=self.email)
def tearDown(self):
self._db1.close()
self._db2.close()
+ self._soledad.close()
+ # XXX should not access "private" attrs
for f in [self._soledad._local_db_path, self._soledad._secrets_path]:
if os.path.isfile(f):
os.unlink(f)
- self._soledad.close()
def _soledad_instance(self, user=ADDRESS, passphrase='123',
prefix='',
@@ -72,7 +81,8 @@ class BaseSoledadTest(BaseLeapTest):
return Soledad(
user,
passphrase,
- secrets_path=os.path.join(self.tempdir, prefix, secrets_path),
+ secrets_path=os.path.join(
+ self.tempdir, prefix, secrets_path),
local_db_path=os.path.join(
self.tempdir, prefix, local_db_path),
server_url=server_url, # Soledad will fail if not given an url.
diff --git a/soledad/src/leap/soledad/tests/couchdb.ini.template b/common/src/leap/soledad/common/tests/couchdb.ini.template
index 7d0316f0..7d0316f0 100644
--- a/soledad/src/leap/soledad/tests/couchdb.ini.template
+++ b/common/src/leap/soledad/common/tests/couchdb.ini.template
diff --git a/soledad/src/leap/soledad/tests/test_couch.py b/common/src/leap/soledad/common/tests/test_couch.py
index a84bb46c..2fb799b7 100644
--- a/soledad/src/leap/soledad/tests/test_couch.py
+++ b/common/src/leap/soledad/common/tests/test_couch.py
@@ -27,12 +27,12 @@ from base64 import b64decode
from leap.common.files import mkdir_p
-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
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.common.tests import u1db_tests as tests
+from leap.soledad.common.tests.u1db_tests import test_backends
+from leap.soledad.common.tests.u1db_tests import test_sync
+from leap.soledad.common import couch
import simplejson as json
-from leap.soledad.document import SoledadDocument
#-----------------------------------------------------------------------------
diff --git a/soledad/src/leap/soledad/tests/test_crypto.py b/common/src/leap/soledad/common/tests/test_crypto.py
index eea67b45..01b43299 100644
--- a/soledad/src/leap/soledad/tests/test_crypto.py
+++ b/common/src/leap/soledad/common/tests/test_crypto.py
@@ -32,19 +32,18 @@ from leap.common.testing.basetest import BaseLeapTest
from Crypto import Random
-from leap.common.testing.basetest import BaseLeapTest
-from leap.soledad import (
+from leap.soledad.client import (
Soledad,
crypto,
target,
)
-from leap.soledad.document import SoledadDocument
-from leap.soledad.tests import (
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.common.tests import (
BaseSoledadTest,
KEY_FINGERPRINT,
PRIVATE_KEY,
)
-from leap.soledad.tests.u1db_tests import (
+from leap.soledad.common.tests.u1db_tests import (
simple_doc,
nested_doc,
TestCaseWithServer,
@@ -137,7 +136,8 @@ class SoledadSecretsTestCase(BaseSoledadTest):
secret_id_2 == hashlib.sha256(sol.storage_secret).hexdigest())
def test__has_secret(self):
- sol = self._soledad_instance(user='user@leap.se')
+ sol = self._soledad_instance(
+ user='user@leap.se', prefix=self.rand_prefix)
self.assertTrue(sol._has_secret(), "Should have a secret at "
"this point")
# setting secret id to None should not interfere in the fact we have a
diff --git a/soledad/src/leap/soledad/tests/test_server.py b/common/src/leap/soledad/common/tests/test_server.py
index 24cd68dc..beb7e04d 100644
--- a/soledad/src/leap/soledad/tests/test_server.py
+++ b/common/src/leap/soledad/common/tests/test_server.py
@@ -26,27 +26,27 @@ import simplejson as json
import mock
-from leap.soledad import Soledad
-from leap.soledad_server import SoledadApp
-from leap.soledad_server.auth import URLToAuthorization
-from leap.soledad_server.couch import (
+from leap.common.testing.basetest import BaseLeapTest
+from leap.soledad.common.couch import (
CouchServerState,
CouchDatabase,
)
-from leap.soledad import target
-
-
-from leap.common.testing.basetest import BaseLeapTest
-from leap.soledad.tests.u1db_tests import (
+from leap.soledad.common.tests.u1db_tests import (
TestCaseWithServer,
simple_doc,
)
-from leap.soledad.tests.test_couch import CouchDBTestCase
-from leap.soledad.tests.test_target import (
+from leap.soledad.common.tests.test_couch import CouchDBTestCase
+from leap.soledad.common.tests.test_target import (
make_token_soledad_app,
make_leap_document_for_test,
token_leap_sync_target,
)
+from leap.soledad.client import (
+ Soledad,
+ target,
+)
+from leap.soledad.server import SoledadApp
+from leap.soledad.server.auth import URLToAuthorization
class ServerAuthorizationTestCase(BaseLeapTest):
diff --git a/soledad/src/leap/soledad/tests/test_soledad.py b/common/src/leap/soledad/common/tests/test_soledad.py
index 63ab5551..0b753647 100644
--- a/soledad/src/leap/soledad/tests/test_soledad.py
+++ b/common/src/leap/soledad/common/tests/test_soledad.py
@@ -22,25 +22,21 @@ Tests for general Soledad functionality.
import os
-import re
-import tempfile
-import simplejson as json
from mock import Mock
from pysqlcipher.dbapi2 import DatabaseError
-from leap.common.testing.basetest import BaseLeapTest
from leap.common.events import events_pb2 as proto
-from leap.soledad.tests import (
+from leap.soledad.common.tests import (
BaseSoledadTest,
ADDRESS,
)
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.target import SoledadSyncTarget
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.client import Soledad, PassphraseTooShort
+from leap.soledad.client.crypto import SoledadCrypto
+from leap.soledad.client.shared_db import SoledadSharedDatabase
+from leap.soledad.client.target import SoledadSyncTarget
class AuxMethodsTestCase(BaseSoledadTest):
@@ -62,7 +58,7 @@ class AuxMethodsTestCase(BaseSoledadTest):
sol._gen_secret()
sol._load_secrets()
sol._init_db()
- from leap.soledad.sqlcipher import SQLCipherDatabase
+ from leap.soledad.client.sqlcipher import SQLCipherDatabase
self.assertIsInstance(sol._db, SQLCipherDatabase)
def test__init_config_defaults(self):
@@ -113,17 +109,26 @@ class AuxMethodsTestCase(BaseSoledadTest):
"""
sol = self._soledad_instance(
'leap@leap.se',
- passphrase='123')
+ passphrase='123',
+ prefix=self.rand_prefix,
+ )
doc = sol.create_doc({'simple': 'doc'})
doc_id = doc.doc_id
+
# change the passphrase
sol.change_passphrase('654321')
- # assert we can not use the old passphrase anymore
+
self.assertRaises(
DatabaseError,
- self._soledad_instance, 'leap@leap.se', '123')
+ self._soledad_instance, 'leap@leap.se',
+ passphrase='123',
+ prefix=self.rand_prefix)
+
# use new passphrase and retrieve doc
- sol2 = self._soledad_instance('leap@leap.se', '654321')
+ sol2 = self._soledad_instance(
+ 'leap@leap.se',
+ passphrase='654321',
+ prefix=self.rand_prefix)
doc2 = sol2.get_doc(doc_id)
self.assertEqual(doc, doc2)
@@ -137,7 +142,7 @@ class AuxMethodsTestCase(BaseSoledadTest):
passphrase='123')
# check that soledad complains about new passphrase length
self.assertRaises(
- soledad.PassphraseTooShort,
+ PassphraseTooShort,
sol.change_passphrase, '54321')
def test_get_passphrase(self):
@@ -198,7 +203,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):
def setUp(self):
BaseSoledadTest.setUp(self)
# mock signaling
- soledad.signal = Mock()
+ soledad.client.signal = Mock()
def tearDown(self):
pass
@@ -212,54 +217,54 @@ class SoledadSignalingTestCase(BaseSoledadTest):
"""
Test that a fresh soledad emits all bootstrap signals.
"""
- soledad.signal.reset_mock()
+ soledad.client.signal.reset_mock()
# get a fresh instance so it emits all bootstrap signals
sol = self._soledad_instance(
secrets_path='alternative.json',
local_db_path='alternative.u1db')
# reverse call order so we can verify in the order the signals were
# expected
- soledad.signal.mock_calls.reverse()
- soledad.signal.call_args = \
- soledad.signal.call_args_list[0]
- soledad.signal.call_args_list.reverse()
+ soledad.client.signal.mock_calls.reverse()
+ soledad.client.signal.call_args = \
+ soledad.client.signal.call_args_list[0]
+ soledad.client.signal.call_args_list.reverse()
# assert signals
- soledad.signal.assert_called_with(
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_CREATING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_CREATING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_UPLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_UPLOADING_KEYS,
ADDRESS,
)
@@ -268,32 +273,32 @@ class SoledadSignalingTestCase(BaseSoledadTest):
"""
Test that an existent soledad emits some of the bootstrap signals.
"""
- soledad.signal.reset_mock()
+ soledad.client.signal.reset_mock()
# get an existent instance so it emits only some of bootstrap signals
sol = self._soledad_instance()
# reverse call order so we can verify in the order the signals were
# expected
- soledad.signal.mock_calls.reverse()
- soledad.signal.call_args = \
- soledad.signal.call_args_list[0]
- soledad.signal.call_args_list.reverse()
+ soledad.client.signal.mock_calls.reverse()
+ soledad.client.signal.call_args = \
+ soledad.client.signal.call_args_list[0]
+ soledad.client.signal.call_args_list.reverse()
# assert signals
- soledad.signal.assert_called_with(
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_DOWNLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_UPLOADING_KEYS,
ADDRESS,
)
- self._pop_mock_call(soledad.signal)
- soledad.signal.assert_called_with(
+ self._pop_mock_call(soledad.client.signal)
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_UPLOADING_KEYS,
ADDRESS,
)
@@ -302,7 +307,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):
"""
Test Soledad emits SOLEDAD_CREATING_KEYS signal.
"""
- soledad.signal.reset_mock()
+ soledad.client.signal.reset_mock()
# get a fresh instance so it emits all bootstrap signals
sol = self._soledad_instance()
# mock the actual db sync so soledad does not try to connect to the
@@ -311,7 +316,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):
# do the sync
sol.sync()
# assert the signal has been emitted
- soledad.signal.assert_called_with(
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_DONE_DATA_SYNC,
ADDRESS,
)
@@ -320,7 +325,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):
"""
Test Soledad emits SOLEDAD_CREATING_KEYS signal.
"""
- soledad.signal.reset_mock()
+ soledad.client.signal.reset_mock()
sol = self._soledad_instance()
# mock the sync target
old_get_sync_info = SoledadSyncTarget.get_sync_info
@@ -330,7 +335,7 @@ class SoledadSignalingTestCase(BaseSoledadTest):
# check for new data to sync
sol.need_sync('http://provider/userdb')
# assert the signal has been emitted
- soledad.signal.assert_called_with(
+ soledad.client.signal.assert_called_with(
proto.SOLEDAD_NEW_DATA_TO_SYNC,
ADDRESS,
)
diff --git a/soledad/src/leap/soledad/tests/test_sqlcipher.py b/common/src/leap/soledad/common/tests/test_sqlcipher.py
index 25d04861..66a673b6 100644
--- a/soledad/src/leap/soledad/tests/test_sqlcipher.py
+++ b/common/src/leap/soledad/common/tests/test_sqlcipher.py
@@ -43,27 +43,27 @@ from u1db.backends.sqlite_backend import SQLitePartialExpandDatabase
# soledad stuff.
-from leap.soledad.document import SoledadDocument
-from leap.soledad.sqlcipher import (
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.client.sqlcipher import (
SQLCipherDatabase,
DatabaseIsNotEncrypted,
open as u1db_open,
)
-from leap.soledad.target import (
+from leap.soledad.common.crypto import (
EncryptionSchemes,
- decrypt_doc,
ENC_JSON_KEY,
ENC_SCHEME_KEY,
)
+from leap.soledad.client.target import decrypt_doc
# u1db tests stuff.
-from leap.soledad.tests import u1db_tests as tests, BaseSoledadTest
-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.target import SoledadSyncTarget
+from leap.soledad.common.tests import u1db_tests as tests, BaseSoledadTest
+from leap.soledad.common.tests.u1db_tests import test_sqlite_backend
+from leap.soledad.common.tests.u1db_tests import test_backends
+from leap.soledad.common.tests.u1db_tests import test_open
+from leap.soledad.common.tests.u1db_tests import test_sync
+from leap.soledad.client.target import SoledadSyncTarget
from leap.common.testing.basetest import BaseLeapTest
PASSWORD = '123456'
@@ -438,7 +438,8 @@ 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 = SoledadSyncTarget.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)
@@ -682,7 +683,7 @@ class SQLCipherSyncTargetTests(
def setUp(self):
test_sync.DatabaseSyncTargetTests.setUp(self)
- BaseSoledadTest.setUp(self)
+ #BaseSoledadTest.setUp(self)
def tearDown(self):
test_sync.DatabaseSyncTargetTests.tearDown(self)
diff --git a/soledad/src/leap/soledad/tests/test_target.py b/common/src/leap/soledad/common/tests/test_target.py
index ca2878a5..5a541745 100644
--- a/soledad/src/leap/soledad/tests/test_target.py
+++ b/common/src/leap/soledad/common/tests/test_target.py
@@ -34,25 +34,26 @@ from u1db.remote import (
http_target,
)
-from leap import soledad
-from leap.soledad import (
+from leap.soledad import client
+from leap.soledad.client import (
target,
auth,
+ VerifiedHTTPSConnection,
)
-from leap.soledad.document import SoledadDocument
-from leap.soledad_server import SoledadApp
-from leap.soledad_server.auth import SoledadTokenAuthMiddleware
+from leap.soledad.common.document import SoledadDocument
+from leap.soledad.server import SoledadApp
+from leap.soledad.server.auth import SoledadTokenAuthMiddleware
-from leap.soledad.tests import u1db_tests as tests
-from leap.soledad.tests import BaseSoledadTest
-from leap.soledad.tests.u1db_tests import test_backends
-from leap.soledad.tests.u1db_tests import test_http_database
-from leap.soledad.tests.u1db_tests import test_http_client
-from leap.soledad.tests.u1db_tests import test_document
-from leap.soledad.tests.u1db_tests import test_remote_sync_target
-from leap.soledad.tests.u1db_tests import test_https
-from leap.soledad.tests.u1db_tests import test_sync
+from leap.soledad.common.tests import u1db_tests as tests
+from leap.soledad.common.tests import BaseSoledadTest
+from leap.soledad.common.tests.u1db_tests import test_backends
+from leap.soledad.common.tests.u1db_tests import test_http_database
+from leap.soledad.common.tests.u1db_tests import test_http_client
+from leap.soledad.common.tests.u1db_tests import test_document
+from leap.soledad.common.tests.u1db_tests import test_remote_sync_target
+from leap.soledad.common.tests.u1db_tests import test_https
+from leap.soledad.common.tests.u1db_tests import test_sync
#-----------------------------------------------------------------------------
@@ -77,7 +78,7 @@ def make_token_soledad_app(state):
return True
return False
- # we test for action authorization in leap.soledad.tests.test_server
+ # we test for action authorization in leap.soledad.common.tests.test_server
def _verify_authorization(uuid, environ):
return True
@@ -504,8 +505,9 @@ def token_leap_https_sync_target(test, host, path):
return st
-class TestSoledadSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSupport,
- BaseSoledadTest):
+class TestSoledadSyncTargetHttpsSupport(
+ test_https.TestHttpSyncTargetHttpsSupport,
+ BaseSoledadTest):
scenarios = [
('token_soledad_https',
@@ -520,8 +522,8 @@ class TestSoledadSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSuppor
# run smoothly with standard u1db.
test_https.TestHttpSyncTargetHttpsSupport.setUp(self)
# so here monkey patch again to test our functionality.
- http_client._VerifiedHTTPSConnection = soledad.VerifiedHTTPSConnection
- soledad.SOLEDAD_CERT = http_client.CA_CERTS
+ http_client._VerifiedHTTPSConnection = VerifiedHTTPSConnection
+ client.SOLEDAD_CERT = http_client.CA_CERTS
def test_working(self):
"""
@@ -532,7 +534,7 @@ class TestSoledadSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSuppor
"""
self.startServer()
db = self.request_state._create_database('test')
- self.patch(soledad, 'SOLEDAD_CERT', self.cacert_pem)
+ self.patch(client, 'SOLEDAD_CERT', self.cacert_pem)
remote_target = self.getSyncTarget('localhost', 'test')
remote_target.record_sync_info('other-id', 2, 'T-id')
self.assertEqual(
@@ -548,7 +550,7 @@ class TestSoledadSyncTargetHttpsSupport(test_https.TestHttpSyncTargetHttpsSuppor
"""
self.startServer()
self.request_state._create_database('test')
- self.patch(soledad, 'SOLEDAD_CERT', self.cacert_pem)
+ self.patch(client, 'SOLEDAD_CERT', self.cacert_pem)
remote_target = self.getSyncTarget('127.0.0.1', 'test')
self.assertRaises(
http_client.CertificateError, remote_target.record_sync_info,
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/README b/common/src/leap/soledad/common/tests/u1db_tests/README
index 605f01fa..605f01fa 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/README
+++ b/common/src/leap/soledad/common/tests/u1db_tests/README
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/__init__.py b/common/src/leap/soledad/common/tests/u1db_tests/__init__.py
index 43304b43..3bc12487 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/__init__.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/__init__.py
@@ -189,8 +189,11 @@ class DatabaseBaseTests(TestCase):
scenarios = LOCAL_DATABASES_SCENARIOS
- def create_database(self, replica_uid):
- return self.make_database_for_test(self, replica_uid)
+ def make_database_for_test(self, replica_uid):
+ return make_memory_database_for_test(self, replica_uid)
+
+ def create_database(self, *args):
+ return self.make_database_for_test(self, *args)
def copy_database(self, db):
# DO NOT COPY OR REUSE THIS CODE OUTSIDE TESTS: COPYING U1DB DATABASES
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_backends.py b/common/src/leap/soledad/common/tests/u1db_tests/test_backends.py
index a53b01ba..d2a91d11 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_backends.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_backends.py
@@ -26,12 +26,12 @@ from u1db import (
vectorclock,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
simple_doc = tests.simple_doc
nested_doc = tests.nested_doc
-from leap.soledad.tests.u1db_tests.test_remote_sync_target import (
+from leap.soledad.common.tests.u1db_tests.test_remote_sync_target import (
make_http_app,
make_oauth_http_app,
)
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_document.py b/common/src/leap/soledad/common/tests/u1db_tests/test_document.py
index e706e1a9..8b30ed51 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_document.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_document.py
@@ -17,7 +17,7 @@
from u1db import errors
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
class TestDocument(tests.TestCase):
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py b/common/src/leap/soledad/common/tests/u1db_tests/test_http_app.py
index e0729aa2..789006ba 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_http_app.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_http_app.py
@@ -30,7 +30,7 @@ from u1db import (
sync,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.remote import (
http_app,
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py b/common/src/leap/soledad/common/tests/u1db_tests/test_http_client.py
index 42e98461..08e9714e 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_http_client.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_http_client.py
@@ -26,7 +26,7 @@ from u1db import (
errors,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.remote import (
http_client,
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py b/common/src/leap/soledad/common/tests/u1db_tests/test_http_database.py
index f21e6da1..3f3c7bba 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_http_database.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_http_database.py
@@ -27,13 +27,13 @@ from u1db import (
Document,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.remote import (
http_database,
http_target,
)
-from leap.soledad.tests.u1db_tests.test_remote_sync_target import (
+from leap.soledad.common.tests.u1db_tests.test_remote_sync_target import (
make_http_app,
)
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_https.py b/common/src/leap/soledad/common/tests/u1db_tests/test_https.py
index 62180f8c..c086fbc0 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_https.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_https.py
@@ -12,8 +12,8 @@ from u1db.remote import (
)
from leap import soledad
-from leap.soledad.tests import u1db_tests as tests
-from leap.soledad.tests.u1db_tests.test_remote_sync_target import (
+from leap.soledad.common.tests import u1db_tests as tests
+from leap.soledad.common.tests.u1db_tests.test_remote_sync_target import (
make_oauth_http_app,
)
@@ -75,7 +75,7 @@ class TestHttpSyncTargetHttpsSupport(tests.TestCaseWithServer):
# order to maintain the compatibility with u1db default tests, we undo
# that replacement here.
http_client._VerifiedHTTPSConnection = \
- soledad.old__VerifiedHTTPSConnection
+ soledad.client.old__VerifiedHTTPSConnection
super(TestHttpSyncTargetHttpsSupport, self).setUp()
def getSyncTarget(self, host, path=None):
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_open.py b/common/src/leap/soledad/common/tests/u1db_tests/test_open.py
index 0ff307e8..13425b4f 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_open.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_open.py
@@ -22,9 +22,9 @@ from u1db import (
errors,
open as u1db_open,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.backends import sqlite_backend
-from leap.soledad.tests.u1db_tests.test_backends import TestAlternativeDocument
+from leap.soledad.common.tests.u1db_tests.test_backends import TestAlternativeDocument
class TestU1DBOpen(tests.TestCase):
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py b/common/src/leap/soledad/common/tests/u1db_tests/test_remote_sync_target.py
index 66d404d2..3793e0df 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_remote_sync_target.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_remote_sync_target.py
@@ -22,7 +22,7 @@ from u1db import (
errors,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.remote import (
http_app,
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py b/common/src/leap/soledad/common/tests/u1db_tests/test_sqlite_backend.py
index 1380e4b1..a53ea6cc 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_sqlite_backend.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_sqlite_backend.py
@@ -27,10 +27,10 @@ from u1db import (
query_parser,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.backends import sqlite_backend
-from leap.soledad.tests.u1db_tests.test_backends import TestAlternativeDocument
+from leap.soledad.common.tests.u1db_tests.test_backends import TestAlternativeDocument
simple_doc = '{"key": "value"}'
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/test_sync.py b/common/src/leap/soledad/common/tests/u1db_tests/test_sync.py
index 96aa2736..5346d540 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/test_sync.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/test_sync.py
@@ -26,7 +26,7 @@ from u1db import (
SyncTarget,
)
-from leap.soledad.tests import u1db_tests as tests
+from leap.soledad.common.tests import u1db_tests as tests
from u1db.backends import (
inmemory,
@@ -35,7 +35,7 @@ from u1db.remote import (
http_target,
)
-from leap.soledad.tests.u1db_tests.test_remote_sync_target import (
+from leap.soledad.common.tests.u1db_tests.test_remote_sync_target import (
make_http_app,
make_oauth_http_app,
)
@@ -85,7 +85,8 @@ class DatabaseSyncTargetTests(tests.DatabaseBaseTests,
whitebox = True
def setUp(self):
- super(DatabaseSyncTargetTests, self).setUp()
+ tests.DatabaseBaseTests.setUp(self)
+ tests.TestCaseWithServer.setUp(self)
self.db, self.st = self.create_db_and_target(self)
self.other_changes = []
@@ -96,6 +97,9 @@ class DatabaseSyncTargetTests(tests.DatabaseBaseTests,
del self.db
super(DatabaseSyncTargetTests, self).tearDown()
+ def create_db_and_target(self, *args):
+ return _make_local_db_and_target(*args)
+
def receive_doc(self, doc, gen, trans_id):
self.other_changes.append(
(doc.doc_id, doc.rev, doc.get_json(), gen, trans_id))
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/Makefile
index 2385e75b..2385e75b 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/Makefile
+++ b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/Makefile
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/cacert.pem
index c019a730..c019a730 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/cacert.pem
+++ b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/cacert.pem
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.cert
index 985684fb..985684fb 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.cert
+++ b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.cert
diff --git a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.key
index d83d4920..d83d4920 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/testing-certs/testing.key
+++ b/common/src/leap/soledad/common/tests/u1db_tests/testing-certs/testing.key
diff --git a/server/changes/feature_3487-split-soledad-into-common-client-and-server b/server/changes/feature_3487-split-soledad-into-common-client-and-server
new file mode 100644
index 00000000..2eab6b56
--- /dev/null
+++ b/server/changes/feature_3487-split-soledad-into-common-client-and-server
@@ -0,0 +1 @@
+ o Split soledad package into common, client and server. Closes #3487.
diff --git a/soledad_server/pkg/soledad b/server/pkg/soledad
index c233731e..c233731e 100644
--- a/soledad_server/pkg/soledad
+++ b/server/pkg/soledad
diff --git a/soledad_server/setup.py b/server/setup.py
index 6229cf62..89354a57 100644
--- a/soledad_server/setup.py
+++ b/server/setup.py
@@ -31,10 +31,9 @@ install_requirements = [
'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',
- 'leap.soledad>=0.3.0',
+ 'leap.soledad.common>=0.3.0',
]
@@ -44,6 +43,7 @@ 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",
@@ -58,8 +58,9 @@ trove_classifiers = (
"Topic :: Software Development :: Libraries :: Python Modules"
)
+
setup(
- name='leap.soledad_server',
+ name='leap.soledad.server',
version='0.3.0',
url='https://leap.se/',
license='GPLv3+',
@@ -71,7 +72,7 @@ setup(
"securely shared among devices. It provides, to other parts of the "
"LEAP client, an API for data storage and sync."
),
- namespace_packages=["leap"],
+ namespace_packages=["leap", "leap.soledad"],
packages=find_packages('src'),
package_dir={'': 'src'},
install_requires=install_requirements,
diff --git a/server/src/leap/__init__.py b/server/src/leap/__init__.py
new file mode 100644
index 00000000..f48ad105
--- /dev/null
+++ b/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/server/src/leap/soledad/__init__.py b/server/src/leap/soledad/__init__.py
new file mode 100644
index 00000000..f48ad105
--- /dev/null
+++ b/server/src/leap/soledad/__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/soledad_server/src/leap/soledad_server/__init__.py b/server/src/leap/soledad/server/__init__.py
index 18a0546e..4ed8efc9 100644
--- a/soledad_server/src/leap/soledad_server/__init__.py
+++ b/server/src/leap/soledad/server/__init__.py
@@ -43,8 +43,8 @@ if version.base() == "12.0.0":
sys.modules['OpenSSL.tsafe'] = old_tsafe
-from leap.soledad_server.auth import SoledadTokenAuthMiddleware
-from leap.soledad_server.couch import CouchServerState
+from leap.soledad.server.auth import SoledadTokenAuthMiddleware
+from leap.soledad.common.couch import CouchServerState
#-----------------------------------------------------------------------------
@@ -122,4 +122,4 @@ state = CouchServerState(conf['couch_url'])
# WSGI application that may be used by `twistd -web`
application = SoledadTokenAuthMiddleware(SoledadApp(state))
-resource = WSGIResource(reactor, reactor.getThreadPool(), application) \ No newline at end of file
+resource = WSGIResource(reactor, reactor.getThreadPool(), application)
diff --git a/soledad_server/src/leap/soledad_server/auth.py b/server/src/leap/soledad/server/auth.py
index 3bcfcf04..3bcfcf04 100644
--- a/soledad_server/src/leap/soledad_server/auth.py
+++ b/server/src/leap/soledad/server/auth.py
diff --git a/soledad/src/leap/soledad/backends/__init__.py b/soledad/src/leap/soledad/backends/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/soledad/src/leap/soledad/backends/__init__.py
+++ /dev/null
diff --git a/soledad/src/leap/soledad/backends/leap_backend.py b/soledad/src/leap/soledad/backends/leap_backend.py
deleted file mode 100644
index a8d76b67..00000000
--- a/soledad/src/leap/soledad/backends/leap_backend.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# -*- 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)