summaryrefslogtreecommitdiff
path: root/src/leap/soledad/server
diff options
context:
space:
mode:
authorVictor Shyba <victor1984@riseup.net>2017-07-05 02:17:38 -0300
committerdrebs <drebs@leap.se>2017-07-18 15:22:23 -0300
commit361eb8d7121cc8abb94d9fef784d5ff2b27722d0 (patch)
tree54f1fd298522303aec74a9a622e39f0cfb6800f5 /src/leap/soledad/server
parentec8d1f5aedcd077b5b1521e15b1432e616f83f3a (diff)
[feature] add blobs as a incoming api backend
We started with CouchDB due legacy system relying on it. This commit adds the possibility of adding blobs as a IncomingAPI backend if blobs is enabled on config file. -- Resolves: #8868
Diffstat (limited to 'src/leap/soledad/server')
-rw-r--r--src/leap/soledad/server/_blobs.py20
-rw-r--r--src/leap/soledad/server/_incoming.py45
2 files changed, 58 insertions, 7 deletions
diff --git a/src/leap/soledad/server/_blobs.py b/src/leap/soledad/server/_blobs.py
index f87c3818..87b171fb 100644
--- a/src/leap/soledad/server/_blobs.py
+++ b/src/leap/soledad/server/_blobs.py
@@ -237,3 +237,23 @@ if __name__ == '__main__':
factory = Site(root)
reactor.listenTCP(args.port, factory)
reactor.run()
+
+
+class BlobsServerState(object):
+ """
+ Given a backend name, it gives a instance of IBlobsBackend
+ """
+ # Allowed backend classes are defined here
+ handlers = {"filesystem": FilesystemBlobsBackend}
+
+ def __init__(self, backend, **backend_kwargs):
+ if backend not in self.handlers:
+ raise ImproperlyConfiguredException("No such backend: %s", backend)
+ self.backend = self.handlers[backend](**backend_kwargs)
+
+ def open_database(self, user_id):
+ """
+ That method is just for compatibility with CouchServerState, so
+ IncomingAPI can change backends.
+ """
+ return self.backend
diff --git a/src/leap/soledad/server/_incoming.py b/src/leap/soledad/server/_incoming.py
index 6fd91a08..6fdeb7ae 100644
--- a/src/leap/soledad/server/_incoming.py
+++ b/src/leap/soledad/server/_incoming.py
@@ -17,38 +17,61 @@
"""
A twisted resource that saves externally delivered documents into user's db.
"""
+from twisted.web.server import NOT_DONE_YET
from twisted.web.resource import Resource
from ._config import get_config
+from io import BytesIO
+from leap.soledad.server._blobs import BlobsServerState
from leap.soledad.common.couch.state import CouchServerState
from leap.soledad.common.document import ServerDocument
from leap.soledad.common.crypto import ENC_JSON_KEY
from leap.soledad.common.crypto import ENC_SCHEME_KEY
from leap.soledad.common.crypto import EncryptionSchemes
+from leap.soledad.common import preamble
__all__ = ['IncomingResource']
-def _default_backend():
+def _get_backend_from_config():
conf = get_config()
- return CouchServerState(conf['couch_url'], create_cmd=conf['create_cmd'])
+ if conf['blobs']:
+ return BlobsServerState("filesystem", conf['blobs_path'])
+ return CouchServerState(conf['couch_url'])
class IncomingResource(Resource):
isLeaf = True
def __init__(self, backend_factory=None):
- self.factory = backend_factory or _default_backend()
+ self.factory = backend_factory or _get_backend_from_config()
self.formatter = IncomingFormatter()
def render_PUT(self, request):
uuid, doc_id = request.postpath
scheme = EncryptionSchemes.PUBKEY
db = self.factory.open_database(uuid)
- doc = ServerDocument(doc_id)
- doc.content = self.formatter.format(request.content.read(), scheme)
- db.put_doc(doc)
- return '{"success": true}'
+ if hasattr(db, 'put_doc'):
+ doc = ServerDocument(doc_id)
+ doc.content = self.formatter.format(request.content.read(), scheme)
+ db.put_doc(doc)
+ self._finish(request)
+ else:
+ raw_content = request.content.read()
+ preamble = self.formatter.preamble(raw_content, doc_id)
+ request.content = BytesIO(preamble + raw_content)
+ d = db.write_blob(uuid, doc_id, request, namespace='incoming')
+ d.addCallback(lambda _: self._finish(request))
+ return NOT_DONE_YET
+
+ def _finish(self, request):
+ request.write('{"success": true}')
+ request.finish()
+
+ def _error(self, e, request):
+ request.write('{"success": false}')
+ request.setResponseCode(500)
+ request.finish()
class IncomingFormatter(object):
@@ -65,3 +88,11 @@ class IncomingFormatter(object):
self.ERROR_DECRYPTING_KEY: False,
ENC_SCHEME_KEY: EncryptionSchemes.NONE,
ENC_JSON_KEY: raw_content}
+
+ def preamble(self, raw_content, doc_id):
+ rev = '0'
+ scheme = preamble.ENC_SCHEME.external
+ method = preamble.ENC_METHOD.pgp
+ size = len(raw_content)
+ return preamble.Preamble(doc_id, rev, scheme, method,
+ content_size=size).encode()