summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2013-08-19 10:13:51 -0300
committerdrebs <drebs@leap.se>2013-08-21 14:40:33 -0300
commit11ac38cb021e97cca77df2e9cf15f9136b24fc43 (patch)
tree2f4e3e004f57ac3436d8258937bf2145ca3de576
parentf424e2fee278bd9f3a9fb838025db7d4c1bb44bb (diff)
Split soledad into common, client and server.
-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)57
-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.py183
-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)11
-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)11
-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)9
-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)90
-rw-r--r--common/src/leap/soledad/common/tests/test_sqlcipher.py (renamed from soledad/src/leap/soledad/tests/test_sqlcipher.py)23
-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)0
-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)4
-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
54 files changed, 583 insertions, 308 deletions
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 67ef3cc8..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 fc0c10ce..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,12 +81,14 @@ except ImportError:
logger.info("Would signal: %s - %s." % (str(signal), content))
-from leap.soledad.crypto import SoledadCrypto
-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__)
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/client/src/leap/soledad/client/dbwrapper.py b/client/src/leap/soledad/client/dbwrapper.py
new file mode 100644
index 00000000..a27a933e
--- /dev/null
+++ b/client/src/leap/soledad/client/dbwrapper.py
@@ -0,0 +1,183 @@
+# -*- coding: utf-8 -*-
+# dbwrapper.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/>.
+"""
+Thread-safe wrapper for sqlite/pysqlcipher.
+
+*TODO*
+At some point we surely will want to switch to a twisted way of dealing
+with this, using defers and proper callbacks. But I had this tested for
+some time so postponing that refactor.
+"""
+import logging
+import threading
+import Queue
+import time
+
+import exceptions
+
+from functools import partial
+
+from leap.soledad.client import sqlcipher
+
+logger = logging.getLogger(__name__)
+
+
+class SQLCipherWrapper(threading.Thread):
+
+ def __init__(self, *args, **kwargs):
+ """
+ Initializes a wrapper that proxies method and attribute
+ access to an underlying SQLCipher instance. We instantiate sqlcipher
+ in a thread, and all method accesses communicate with it using a
+ Queue.
+
+ :param *args: position arguments to pass to pysqlcipher initialization
+ :type args: tuple
+
+ :param **kwargs: keyword arguments to pass to pysqlcipher
+ initialization
+ :type kwargs: dict
+ """
+ threading.Thread.__init__(self)
+ self._db = None
+ self._wrargs = args, kwargs
+
+ self._queue = Queue.Queue()
+ self._stopped = threading.Event()
+
+ self.start()
+
+ def _init_db(self):
+ """
+ Initializes sqlcipher database.
+
+ This is called on a separate thread.
+ """
+ # instantiate u1db
+ args, kwargs = self._wrargs
+ self._db = sqlcipher.open(*args, **kwargs)
+
+ def run(self):
+ """
+ Main loop for the sqlcipher thread.
+ """
+ logger.debug("SQLCipherWrapper thread started.")
+ logger.debug("Initializing sqlcipher")
+ end_mths = ("__end_thread", "_SQLCipherWrapper__end_thread")
+
+ self._init_db()
+ self._lock = threading.Lock()
+
+ ct = 0
+ started = False
+
+ while True:
+ if self._db is None:
+ if started:
+ break
+ if ct > 10:
+ break # XXX DEBUG
+ logger.debug('db not ready yet, waiting...')
+ time.sleep(1)
+ ct += 1
+
+ started = True
+
+ with self._lock:
+ try:
+ mth, q, wrargs = self._queue.get()
+ except:
+ logger.error("exception getting args from queue")
+
+ res = None
+ attr = getattr(self._db, mth, None)
+ if not attr:
+ if mth not in end_mths:
+ logger.error('method %s does not exist' % (mth,))
+ res = AttributeError(
+ "_db instance has no attribute %s" % mth)
+
+ elif callable(attr):
+ # invoke the method with the passed args
+ args = wrargs.get('args', [])
+ kwargs = wrargs.get('kwargs', {})
+ try:
+ res = attr(*args, **kwargs)
+ except Exception as e:
+ logger.error(
+ "Error on proxied method %s: '%r'." % (
+ attr, e))
+ res = e
+ else:
+ # non-callable attribute
+ res = attr
+ logger.debug('returning proxied db call...')
+ q.put(res)
+
+ if mth in end_mths:
+ logger.debug('ending thread')
+ break
+
+ logger.debug("SQLCipherWrapper thread terminated.")
+ self._stopped.set()
+
+ def close(self):
+ """
+ Closes the sqlcipher database and finishes the thread. This method
+ should always be called explicitely.
+ """
+ self.__getattr__('close')()
+ self.__end_thread()
+
+ def __getattr__(self, attr):
+ """
+ Returns _db proxied attributes.
+ """
+
+ def __proxied_mth(method, *args, **kwargs):
+ if not self._stopped.isSet():
+ wrargs = {'args': args, 'kwargs': kwargs}
+ q = Queue.Queue()
+ self._queue.put((method, q, wrargs))
+ res = q.get()
+ q.task_done()
+
+ if isinstance(res, exceptions.BaseException):
+ # XXX should get the original bt
+ raise res
+ return res
+ else:
+ logger.warning("tried to call proxied meth "
+ "but stopped is set: %s" %
+ (method,))
+
+ rgetattr = object.__getattribute__
+
+ if attr != "_db":
+ proxied = partial(__proxied_mth, attr)
+ return proxied
+
+ # fallback to regular behavior
+ return rgetattr(self, attr)
+
+ def __del__(self):
+ """
+ Do not trust this get called. No guarantees given. Because of a funny
+ dance with the refs and the way the gc works, we should be calling the
+ close method explicitely.
+ """
+ self.close()
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 94d0fb04..c605c28c 100644
--- a/soledad/src/leap/soledad/sqlcipher.py
+++ b/client/src/leap/soledad/client/sqlcipher.py
@@ -1,4 +1,4 @@
- # -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
# sqlcipher.py
# Copyright (C) 2013 LEAP
#
@@ -53,7 +53,7 @@ import threading
from u1db.backends import sqlite_backend
from pysqlcipher import dbapi2
from u1db import errors as u1db_errors
-from leap.soledad.document import SoledadDocument
+from leap.soledad.common.document import SoledadDocument
logger = logging.getLogger(__name__)
@@ -328,7 +328,7 @@ 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,
@@ -339,10 +339,13 @@ class SQLCipherDatabase(sqlite_backend.SQLitePartialExpandDatabase):
"""
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
"""
- # XXX used??? private method not used in module
c.execute(
'ALTER TABLE document '
'ADD COLUMN syncable BOOL NOT NULL DEFAULT TRUE')
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 84882e27..9f47d74a 100644
--- a/soledad/src/leap/soledad/tests/__init__.py
+++ b/common/src/leap/soledad/common/tests/__init__.py
@@ -9,10 +9,13 @@ import u1db
from mock import Mock
-from leap.soledad import Soledad
-from leap.soledad.document import SoledadDocument
-from leap.soledad.target import decrypt_doc
-from leap.soledad.target import ENC_SCHEME_KEY
+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,
+)
from leap.common.testing.basetest import BaseLeapTest
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..0c7b8254 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,
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 531bb572..0b753647 100644
--- a/soledad/src/leap/soledad/tests/test_soledad.py
+++ b/common/src/leap/soledad/common/tests/test_soledad.py
@@ -27,16 +27,16 @@ from mock import Mock
from pysqlcipher.dbapi2 import DatabaseError
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):
@@ -58,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):
@@ -142,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):
@@ -203,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
@@ -217,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,
)
@@ -273,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,
)
@@ -307,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
@@ -316,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,
)
@@ -325,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
@@ -335,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 4c4384b8..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)
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 3bc12487..3bc12487 100644
--- a/soledad/src/leap/soledad/tests/u1db_tests/__init__.py
+++ b/common/src/leap/soledad/common/tests/u1db_tests/__init__.py
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 a87c1787..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,
)
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)