summaryrefslogtreecommitdiff
path: root/common/src/leap/soledad
diff options
context:
space:
mode:
Diffstat (limited to 'common/src/leap/soledad')
-rw-r--r--common/src/leap/soledad/common/l2db/__init__.py4
-rw-r--r--common/src/leap/soledad/common/l2db/backends/sqlite_backend.py28
-rw-r--r--common/src/leap/soledad/common/l2db/commandline/__init__.py15
-rw-r--r--common/src/leap/soledad/common/l2db/commandline/client.py497
-rw-r--r--common/src/leap/soledad/common/l2db/commandline/command.py80
-rw-r--r--common/src/leap/soledad/common/l2db/commandline/serve.py58
-rw-r--r--common/src/leap/soledad/common/l2db/errors.py3
-rw-r--r--common/src/leap/soledad/common/l2db/query_parser.py4
-rw-r--r--common/src/leap/soledad/common/l2db/remote/cors_middleware.py42
-rw-r--r--common/src/leap/soledad/common/l2db/remote/http_app.py24
-rw-r--r--common/src/leap/soledad/common/l2db/remote/http_database.py6
-rw-r--r--common/src/leap/soledad/common/l2db/remote/http_target.py2
-rw-r--r--common/src/leap/soledad/common/l2db/remote/oauth_middleware.py89
-rw-r--r--common/src/leap/soledad/common/l2db/remote/server_state.py1
-rw-r--r--common/src/leap/soledad/common/l2db/remote/ssl_match_hostname.py11
-rw-r--r--common/src/leap/soledad/common/l2db/sync.py32
16 files changed, 62 insertions, 834 deletions
diff --git a/common/src/leap/soledad/common/l2db/__init__.py b/common/src/leap/soledad/common/l2db/__init__.py
index cc121d06..c0bd15fe 100644
--- a/common/src/leap/soledad/common/l2db/__init__.py
+++ b/common/src/leap/soledad/common/l2db/__init__.py
@@ -464,8 +464,8 @@ class DocumentBase(object):
"""
# Since this is just for testing, we don't worry about comparing
# against things that aren't a Document.
- return ((self.doc_id, self.rev, self.get_json())
- < (other.doc_id, other.rev, other.get_json()))
+ return ((self.doc_id, self.rev, self.get_json()) <
+ (other.doc_id, other.rev, other.get_json()))
def get_json(self):
"""Get the json serialization of this document."""
diff --git a/common/src/leap/soledad/common/l2db/backends/sqlite_backend.py b/common/src/leap/soledad/common/l2db/backends/sqlite_backend.py
index 309000ee..ba273039 100644
--- a/common/src/leap/soledad/common/l2db/backends/sqlite_backend.py
+++ b/common/src/leap/soledad/common/l2db/backends/sqlite_backend.py
@@ -156,7 +156,7 @@ class SQLiteDatabase(CommonBackend):
def _initialize(self, c):
"""Create the schema in the database."""
- #read the script with sql commands
+ # read the script with sql commands
# TODO: Change how we set up the dependency. Most likely use something
# like lp:dirspec to grab the file from a common resource
# directory. Doesn't specifically need to be handled until we get
@@ -172,7 +172,7 @@ class SQLiteDatabase(CommonBackend):
if not line:
continue
c.execute(line)
- #add extra fields
+ # add extra fields
self._extra_schema_init(c)
# A unique identifier should be set for this replica. Implementations
# don't have to strictly use uuid here, but we do want the uid to be
@@ -509,7 +509,8 @@ class SQLiteDatabase(CommonBackend):
def _put_doc_if_newer(self, doc, save_conflict, replica_uid=None,
replica_gen=None, replica_trans_id=None):
with self._db_handle:
- return super(SQLiteDatabase, self)._put_doc_if_newer(doc,
+ return super(SQLiteDatabase, self)._put_doc_if_newer(
+ doc,
save_conflict=save_conflict,
replica_uid=replica_uid, replica_gen=replica_gen,
replica_trans_id=replica_trans_id)
@@ -620,14 +621,14 @@ class SQLiteDatabase(CommonBackend):
novalue_where = ["d.doc_id = d%d.doc_id"
" AND d%d.field_name = ?"
% (i, i) for i in range(len(definition))]
- wildcard_where = [novalue_where[i]
- + (" AND d%d.value NOT NULL" % (i,))
+ wildcard_where = [novalue_where[i] +
+ (" AND d%d.value NOT NULL" % (i,))
for i in range(len(definition))]
- exact_where = [novalue_where[i]
- + (" AND d%d.value = ?" % (i,))
+ exact_where = [novalue_where[i] +
+ (" AND d%d.value = ?" % (i,))
for i in range(len(definition))]
- like_where = [novalue_where[i]
- + (" AND d%d.value GLOB ?" % (i,))
+ like_where = [novalue_where[i] +
+ (" AND d%d.value GLOB ?" % (i,))
for i in range(len(definition))]
is_wildcard = False
# Merge the lists together, so that:
@@ -672,7 +673,8 @@ class SQLiteDatabase(CommonBackend):
try:
c.execute(statement, tuple(args))
except dbapi2.OperationalError, e:
- raise dbapi2.OperationalError(str(e) +
+ raise dbapi2.OperationalError(
+ str(e) +
'\nstatement: %s\nargs: %s\n' % (statement, args))
res = c.fetchall()
results = []
@@ -771,7 +773,8 @@ class SQLiteDatabase(CommonBackend):
try:
c.execute(statement, tuple(args))
except dbapi2.OperationalError, e:
- raise dbapi2.OperationalError(str(e) +
+ raise dbapi2.OperationalError(
+ str(e) +
'\nstatement: %s\nargs: %s\n' % (statement, args))
res = c.fetchall()
results = []
@@ -800,7 +803,8 @@ class SQLiteDatabase(CommonBackend):
try:
c.execute(statement, tuple(definition))
except dbapi2.OperationalError, e:
- raise dbapi2.OperationalError(str(e) +
+ raise dbapi2.OperationalError(
+ str(e) +
'\nstatement: %s\nargs: %s\n' % (statement, tuple(definition)))
return c.fetchall()
diff --git a/common/src/leap/soledad/common/l2db/commandline/__init__.py b/common/src/leap/soledad/common/l2db/commandline/__init__.py
deleted file mode 100644
index 3f32e381..00000000
--- a/common/src/leap/soledad/common/l2db/commandline/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2011 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
diff --git a/common/src/leap/soledad/common/l2db/commandline/client.py b/common/src/leap/soledad/common/l2db/commandline/client.py
deleted file mode 100644
index 15bf8561..00000000
--- a/common/src/leap/soledad/common/l2db/commandline/client.py
+++ /dev/null
@@ -1,497 +0,0 @@
-# Copyright 2011 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
-
-"""Commandline bindings for the u1db-client program."""
-
-import argparse
-import os
-try:
- import simplejson as json
-except ImportError:
- import json # noqa
-import sys
-
-from u1db import (
- Document,
- open as u1db_open,
- sync,
- errors,
- )
-from u1db.commandline import command
-from u1db.remote import (
- http_database,
- http_target,
- )
-
-
-client_commands = command.CommandGroup()
-
-
-def set_oauth_credentials(client):
- keys = os.environ.get('OAUTH_CREDENTIALS', None)
- if keys is not None:
- consumer_key, consumer_secret, \
- token_key, token_secret = keys.split(":")
- client.set_oauth_credentials(consumer_key, consumer_secret,
- token_key, token_secret)
-
-
-class OneDbCmd(command.Command):
- """Base class for commands operating on one local or remote database."""
-
- def _open(self, database, create):
- if database.startswith(('http://', 'https://')):
- db = http_database.HTTPDatabase(database)
- set_oauth_credentials(db)
- db.open(create)
- return db
- else:
- return u1db_open(database, create)
-
-
-class CmdCreate(OneDbCmd):
- """Create a new document from scratch"""
-
- name = 'create'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to update',
- metavar='database-path-or-url')
- parser.add_argument('infile', nargs='?', default=None,
- help='The file to read content from.')
- parser.add_argument('--id', dest='doc_id', default=None,
- help='Set the document identifier')
-
- def run(self, database, infile, doc_id):
- if infile is None:
- infile = self.stdin
- db = self._open(database, create=False)
- doc = db.create_doc_from_json(infile.read(), doc_id=doc_id)
- self.stderr.write('id: %s\nrev: %s\n' % (doc.doc_id, doc.rev))
-
-client_commands.register(CmdCreate)
-
-
-class CmdDelete(OneDbCmd):
- """Delete a document from the database"""
-
- name = 'delete'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to update',
- metavar='database-path-or-url')
- parser.add_argument('doc_id', help='The document id to retrieve')
- parser.add_argument('doc_rev',
- help='The revision of the document (which is being superseded.)')
-
- def run(self, database, doc_id, doc_rev):
- db = self._open(database, create=False)
- doc = Document(doc_id, doc_rev, None)
- db.delete_doc(doc)
- self.stderr.write('rev: %s\n' % (doc.rev,))
-
-client_commands.register(CmdDelete)
-
-
-class CmdGet(OneDbCmd):
- """Extract a document from the database"""
-
- name = 'get'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to query',
- metavar='database-path-or-url')
- parser.add_argument('doc_id', help='The document id to retrieve.')
- parser.add_argument('outfile', nargs='?', default=None,
- help='The file to write the document to',
- type=argparse.FileType('wb'))
-
- def run(self, database, doc_id, outfile):
- if outfile is None:
- outfile = self.stdout
- try:
- db = self._open(database, create=False)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- doc = db.get_doc(doc_id)
- if doc is None:
- self.stderr.write('Document not found (id: %s)\n' % (doc_id,))
- return 1 # failed
- if doc.is_tombstone():
- outfile.write('[document deleted]\n')
- else:
- outfile.write(doc.get_json() + '\n')
- self.stderr.write('rev: %s\n' % (doc.rev,))
- if doc.has_conflicts:
- self.stderr.write("Document has conflicts.\n")
-
-client_commands.register(CmdGet)
-
-
-class CmdGetDocConflicts(OneDbCmd):
- """Get the conflicts from a document"""
-
- name = 'get-doc-conflicts'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local database to query',
- metavar='database-path')
- parser.add_argument('doc_id', help='The document id to retrieve.')
-
- def run(self, database, doc_id):
- try:
- db = self._open(database, False)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- conflicts = db.get_doc_conflicts(doc_id)
- if not conflicts:
- if db.get_doc(doc_id) is None:
- self.stderr.write("Document does not exist.\n")
- return 1
- self.stdout.write("[")
- for i, doc in enumerate(conflicts):
- if i:
- self.stdout.write(",")
- self.stdout.write(
- json.dumps(dict(rev=doc.rev, content=doc.content), indent=4))
- self.stdout.write("]\n")
-
-client_commands.register(CmdGetDocConflicts)
-
-
-class CmdInitDB(OneDbCmd):
- """Create a new database"""
-
- name = 'init-db'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to create',
- metavar='database-path-or-url')
- parser.add_argument('--replica-uid', default=None,
- help='The unique identifier for this database (not for remote)')
-
- def run(self, database, replica_uid):
- db = self._open(database, create=True)
- if replica_uid is not None:
- db._set_replica_uid(replica_uid)
-
-client_commands.register(CmdInitDB)
-
-
-class CmdPut(OneDbCmd):
- """Add a document to the database"""
-
- name = 'put'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to update',
- metavar='database-path-or-url'),
- parser.add_argument('doc_id', help='The document id to retrieve')
- parser.add_argument('doc_rev',
- help='The revision of the document (which is being superseded.)')
- parser.add_argument('infile', nargs='?', default=None,
- help='The filename of the document that will be used for content',
- type=argparse.FileType('rb'))
-
- def run(self, database, doc_id, doc_rev, infile):
- if infile is None:
- infile = self.stdin
- try:
- db = self._open(database, create=False)
- doc = Document(doc_id, doc_rev, infile.read())
- doc_rev = db.put_doc(doc)
- self.stderr.write('rev: %s\n' % (doc_rev,))
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- except errors.RevisionConflict:
- if db.get_doc(doc_id) is None:
- self.stderr.write("Document does not exist.\n")
- else:
- self.stderr.write("Given revision is not current.\n")
- except errors.ConflictedDoc:
- self.stderr.write(
- "Document has conflicts.\n"
- "Inspect with get-doc-conflicts, then resolve.\n")
- else:
- return
- return 1
-
-client_commands.register(CmdPut)
-
-
-class CmdResolve(OneDbCmd):
- """Resolve a conflicted document"""
-
- name = 'resolve-doc'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database',
- help='The local or remote database to update',
- metavar='database-path-or-url'),
- parser.add_argument('doc_id', help='The conflicted document id')
- parser.add_argument('doc_revs', metavar="doc-rev", nargs="+",
- help='The revisions that the new content supersedes')
- parser.add_argument('--infile', nargs='?', default=None,
- help='The filename of the document that will be used for content',
- type=argparse.FileType('rb'))
-
- def run(self, database, doc_id, doc_revs, infile):
- if infile is None:
- infile = self.stdin
- try:
- db = self._open(database, create=False)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- doc = db.get_doc(doc_id)
- if doc is None:
- self.stderr.write("Document does not exist.\n")
- return 1
- doc.set_json(infile.read())
- db.resolve_doc(doc, doc_revs)
- self.stderr.write("rev: %s\n" % db.get_doc(doc_id).rev)
- if doc.has_conflicts:
- self.stderr.write("Document still has conflicts.\n")
-
-client_commands.register(CmdResolve)
-
-
-class CmdSync(command.Command):
- """Synchronize two databases"""
-
- name = 'sync'
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('source', help='database to sync from')
- parser.add_argument('target', help='database to sync to')
-
- def _open_target(self, target):
- if target.startswith(('http://', 'https://')):
- st = http_target.HTTPSyncTarget.connect(target)
- set_oauth_credentials(st)
- else:
- db = u1db_open(target, create=True)
- st = db.get_sync_target()
- return st
-
- def run(self, source, target):
- """Start a Sync request."""
- source_db = u1db_open(source, create=False)
- st = self._open_target(target)
- syncer = sync.Synchronizer(source_db, st)
- syncer.sync()
- source_db.close()
-
-client_commands.register(CmdSync)
-
-
-class CmdCreateIndex(OneDbCmd):
- """Create an index"""
-
- name = "create-index"
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database', help='The local database to update',
- metavar='database-path')
- parser.add_argument('index', help='the name of the index')
- parser.add_argument('expression', help='an index expression',
- nargs='+')
-
- def run(self, database, index, expression):
- try:
- db = self._open(database, create=False)
- db.create_index(index, *expression)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- except errors.IndexNameTakenError:
- self.stderr.write("There is already a different index named %r.\n"
- % (index,))
- return 1
- except errors.IndexDefinitionParseError:
- self.stderr.write("Bad index expression.\n")
- return 1
-
-client_commands.register(CmdCreateIndex)
-
-
-class CmdListIndexes(OneDbCmd):
- """List existing indexes"""
-
- name = "list-indexes"
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database', help='The local database to query',
- metavar='database-path')
-
- def run(self, database):
- try:
- db = self._open(database, create=False)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- for (index, expression) in db.list_indexes():
- self.stdout.write("%s: %s\n" % (index, ", ".join(expression)))
-
-client_commands.register(CmdListIndexes)
-
-
-class CmdDeleteIndex(OneDbCmd):
- """Delete an index"""
-
- name = "delete-index"
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database', help='The local database to update',
- metavar='database-path')
- parser.add_argument('index', help='the name of the index')
-
- def run(self, database, index):
- try:
- db = self._open(database, create=False)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- return 1
- db.delete_index(index)
-
-client_commands.register(CmdDeleteIndex)
-
-
-class CmdGetIndexKeys(OneDbCmd):
- """Get the index's keys"""
-
- name = "get-index-keys"
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database', help='The local database to query',
- metavar='database-path')
- parser.add_argument('index', help='the name of the index')
-
- def run(self, database, index):
- try:
- db = self._open(database, create=False)
- for key in db.get_index_keys(index):
- self.stdout.write("%s\n" % (", ".join(
- [i.encode('utf-8') for i in key],)))
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- except errors.IndexDoesNotExist:
- self.stderr.write("Index does not exist.\n")
- else:
- return
- return 1
-
-client_commands.register(CmdGetIndexKeys)
-
-
-class CmdGetFromIndex(OneDbCmd):
- """Find documents by searching an index"""
-
- name = "get-from-index"
- argv = None
-
- @classmethod
- def _populate_subparser(cls, parser):
- parser.add_argument('database', help='The local database to query',
- metavar='database-path')
- parser.add_argument('index', help='the name of the index')
- parser.add_argument('values', metavar="value",
- help='the value to look up (one per index column)',
- nargs="+")
-
- def run(self, database, index, values):
- try:
- db = self._open(database, create=False)
- docs = db.get_from_index(index, *values)
- except errors.DatabaseDoesNotExist:
- self.stderr.write("Database does not exist.\n")
- except errors.IndexDoesNotExist:
- self.stderr.write("Index does not exist.\n")
- except errors.InvalidValueForIndex:
- index_def = db._get_index_definition(index)
- len_diff = len(index_def) - len(values)
- if len_diff == 0:
- # can't happen (HAH)
- raise
- argv = self.argv if self.argv is not None else sys.argv
- self.stderr.write(
- "Invalid query: "
- "index %r requires %d query expression%s%s.\n"
- "For example, the following would be valid:\n"
- " %s %s %r %r %s\n"
- % (index,
- len(index_def),
- "s" if len(index_def) > 1 else "",
- ", not %d" % len(values) if len(values) else "",
- argv[0], argv[1], database, index,
- " ".join(map(repr,
- values[:len(index_def)]
- + ["*" for i in range(len_diff)])),
- ))
- except errors.InvalidGlobbing:
- argv = self.argv if self.argv is not None else sys.argv
- fixed = []
- for (i, v) in enumerate(values):
- fixed.append(v)
- if v.endswith('*'):
- break
- # values has at least one element, so i is defined
- fixed.extend('*' * (len(values) - i - 1))
- self.stderr.write(
- "Invalid query: a star can only be followed by stars.\n"
- "For example, the following would be valid:\n"
- " %s %s %r %r %s\n"
- % (argv[0], argv[1], database, index,
- " ".join(map(repr, fixed))))
-
- else:
- self.stdout.write("[")
- for i, doc in enumerate(docs):
- if i:
- self.stdout.write(",")
- self.stdout.write(
- json.dumps(
- dict(id=doc.doc_id, rev=doc.rev, content=doc.content),
- indent=4))
- self.stdout.write("]\n")
- return
- return 1
-
-client_commands.register(CmdGetFromIndex)
-
-
-def main(args):
- return client_commands.run_argv(args, sys.stdin, sys.stdout, sys.stderr)
diff --git a/common/src/leap/soledad/common/l2db/commandline/command.py b/common/src/leap/soledad/common/l2db/commandline/command.py
deleted file mode 100644
index eace0560..00000000
--- a/common/src/leap/soledad/common/l2db/commandline/command.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2011 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
-
-"""Command infrastructure for u1db"""
-
-import argparse
-import inspect
-
-
-class CommandGroup(object):
- """A collection of commands."""
-
- def __init__(self, description=None):
- self.commands = {}
- self.description = description
-
- def register(self, cmd):
- """Register a new command to be incorporated with this group."""
- self.commands[cmd.name] = cmd
-
- def make_argparser(self):
- """Create an argparse.ArgumentParser"""
- parser = argparse.ArgumentParser(description=self.description)
- subs = parser.add_subparsers(title='commands')
- for name, cmd in sorted(self.commands.iteritems()):
- sub = subs.add_parser(name, help=cmd.__doc__)
- sub.set_defaults(subcommand=cmd)
- cmd._populate_subparser(sub)
- return parser
-
- def run_argv(self, argv, stdin, stdout, stderr):
- """Run a command, from a sys.argv[1:] style input."""
- parser = self.make_argparser()
- args = parser.parse_args(argv)
- cmd = args.subcommand(stdin, stdout, stderr)
- params, _, _, _ = inspect.getargspec(cmd.run)
- vals = []
- for param in params[1:]:
- vals.append(getattr(args, param))
- return cmd.run(*vals)
-
-
-class Command(object):
- """Definition of a Command that can be run.
-
- :cvar name: The name of the command, so that you can run
- 'u1db-client <name>'.
- """
-
- name = None
-
- def __init__(self, stdin, stdout, stderr):
- self.stdin = stdin
- self.stdout = stdout
- self.stderr = stderr
-
- @classmethod
- def _populate_subparser(cls, parser):
- """Child classes should override this to provide their arguments."""
- raise NotImplementedError(cls._populate_subparser)
-
- def run(self, *args):
- """This is where the magic happens.
-
- Subclasses should implement this, requesting their specific arguments.
- """
- raise NotImplementedError(self.run)
diff --git a/common/src/leap/soledad/common/l2db/commandline/serve.py b/common/src/leap/soledad/common/l2db/commandline/serve.py
deleted file mode 100644
index 5e10f9cb..00000000
--- a/common/src/leap/soledad/common/l2db/commandline/serve.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright 2011 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
-
-"""Build server for u1db-serve."""
-import os
-
-from paste import httpserver
-
-from u1db.remote import (
- http_app,
- server_state,
- cors_middleware
- )
-
-
-class DbListingServerState(server_state.ServerState):
- """ServerState capable of listing dbs."""
-
- def global_info(self):
- """Return list of dbs."""
- dbs = []
- for fname in os.listdir(self._workingdir):
- p = os.path.join(self._workingdir, fname)
- if os.path.isfile(p) and os.access(p, os.R_OK|os.W_OK):
- try:
- with open(p, 'rb') as f:
- header = f.read(16)
- if header == "SQLite format 3\000":
- dbs.append(fname)
- except IOError:
- pass
- return {"databases": dict.fromkeys(dbs), "db_count": len(dbs)}
-
-
-def make_server(host, port, working_dir, accept_cors_connections=None):
- """Make a server on host and port exposing dbs living in working_dir."""
- state = DbListingServerState()
- state.set_workingdir(working_dir)
- application = http_app.HTTPApp(state)
- if accept_cors_connections:
- application = cors_middleware.CORSMiddleware(application,
- accept_cors_connections)
- server = httpserver.WSGIServer(application, (host, port),
- httpserver.WSGIHandler)
- return server
diff --git a/common/src/leap/soledad/common/l2db/errors.py b/common/src/leap/soledad/common/l2db/errors.py
index e5ee8f45..b502fc2d 100644
--- a/common/src/leap/soledad/common/l2db/errors.py
+++ b/common/src/leap/soledad/common/l2db/errors.py
@@ -185,8 +185,7 @@ class UnknownAuthMethod(U1DBError):
# mapping wire (transimission) descriptions/tags for errors to the exceptions
wire_description_to_exc = dict(
(x.wire_description, x) for x in globals().values()
- if getattr(x, 'wire_description', None) not in (None, "error")
-)
+ if getattr(x, 'wire_description', None) not in (None, "error"))
wire_description_to_exc["error"] = U1DBError
diff --git a/common/src/leap/soledad/common/l2db/query_parser.py b/common/src/leap/soledad/common/l2db/query_parser.py
index 7f07b554..dd35b12a 100644
--- a/common/src/leap/soledad/common/l2db/query_parser.py
+++ b/common/src/leap/soledad/common/l2db/query_parser.py
@@ -358,8 +358,8 @@ class Parser(object):
@classmethod
def register_transormation(cls, transform):
assert transform.name not in cls._transformations, (
- "Transform %s already registered for %s"
- % (transform.name, cls._transformations[transform.name]))
+ "Transform %s already registered for %s"
+ % (transform.name, cls._transformations[transform.name]))
cls._transformations[transform.name] = transform
diff --git a/common/src/leap/soledad/common/l2db/remote/cors_middleware.py b/common/src/leap/soledad/common/l2db/remote/cors_middleware.py
deleted file mode 100644
index 8041b968..00000000
--- a/common/src/leap/soledad/common/l2db/remote/cors_middleware.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2012 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
-"""U1DB Cross-Origin Resource Sharing WSGI middleware."""
-
-
-class CORSMiddleware(object):
- """U1DB Cross-Origin Resource Sharing WSGI middleware."""
-
- def __init__(self, app, accept_cors_connections):
- self.origins = ' '.join(accept_cors_connections)
- self.app = app
-
- def _cors_headers(self):
- return [('access-control-allow-origin', self.origins),
- ('access-control-allow-headers',
- 'authorization, content-type, x-requested-with'),
- ('access-control-allow-methods',
- 'GET, POST, PUT, DELETE, OPTIONS')]
-
- def __call__(self, environ, start_response):
- def wrap_start_response(status, headers, exc_info=None):
- headers += self._cors_headers()
- return start_response(status, headers, exc_info)
-
- if environ['REQUEST_METHOD'].lower() == 'options':
- wrap_start_response("200 OK", [('content-type', 'text/plain')])
- return ['']
-
- return self.app(environ, wrap_start_response)
diff --git a/common/src/leap/soledad/common/l2db/remote/http_app.py b/common/src/leap/soledad/common/l2db/remote/http_app.py
index 3b65f5f7..65277bd1 100644
--- a/common/src/leap/soledad/common/l2db/remote/http_app.py
+++ b/common/src/leap/soledad/common/l2db/remote/http_app.py
@@ -18,7 +18,6 @@
"""
HTTP Application exposing U1DB.
"""
-
# TODO -- deprecate, use twisted/txaio.
import functools
@@ -340,18 +339,18 @@ class DocResource(object):
headers={
'x-u1db-rev': '',
'x-u1db-has-conflicts': 'false'
- })
+ })
return
headers = {
'x-u1db-rev': doc.rev,
'x-u1db-has-conflicts': json.dumps(doc.has_conflicts)
- }
+ }
if doc.is_tombstone():
self.responder.send_response_json(
- http_errors.wire_description_to_status[
- errors.DOCUMENT_DELETED],
- error=errors.DOCUMENT_DELETED,
- headers=headers)
+ http_errors.wire_description_to_status[
+ errors.DOCUMENT_DELETED],
+ error=errors.DOCUMENT_DELETED,
+ headers=headers)
else:
self.responder.send_response_content(
doc.get_json(), headers=headers)
@@ -431,7 +430,7 @@ class SyncResource(object):
self.responder.start_response(200)
self.responder.start_stream(),
header = {"new_generation": new_gen,
- "new_transaction_id": self.sync_exch.new_trans_id}
+ "new_transaction_id": self.sync_exch.new_trans_id}
if self.replica_uid is not None:
header['replica_uid'] = self.replica_uid
self.responder.stream_entry(header)
@@ -462,10 +461,11 @@ class HTTPResponder(object):
return
self._started = True
status_text = httplib.responses[status]
- self._write = self._start_response('%d %s' % (status, status_text),
- [('content-type', self.content_type),
- ('cache-control', 'no-cache')] +
- headers.items())
+ self._write = self._start_response(
+ '%d %s' % (status, status_text),
+ [('content-type', self.content_type),
+ ('cache-control', 'no-cache')] +
+ headers.items())
# xxx version in headers
if obj_dic is not None:
self._no_initial_obj = False
diff --git a/common/src/leap/soledad/common/l2db/remote/http_database.py b/common/src/leap/soledad/common/l2db/remote/http_database.py
index d8dcfd55..b2b48dee 100644
--- a/common/src/leap/soledad/common/l2db/remote/http_database.py
+++ b/common/src/leap/soledad/common/l2db/remote/http_database.py
@@ -92,9 +92,9 @@ class HTTPDatabase(http_client.HTTPClientBase, Database):
return None
except errors.HTTPError, e:
if (e.status == DOCUMENT_DELETED_STATUS and
- 'x-u1db-rev' in e.headers):
- res = None
- headers = e.headers
+ 'x-u1db-rev' in e.headers):
+ res = None
+ headers = e.headers
else:
raise
doc_rev = headers['x-u1db-rev']
diff --git a/common/src/leap/soledad/common/l2db/remote/http_target.py b/common/src/leap/soledad/common/l2db/remote/http_target.py
index 598170e4..7e7f366f 100644
--- a/common/src/leap/soledad/common/l2db/remote/http_target.py
+++ b/common/src/leap/soledad/common/l2db/remote/http_target.py
@@ -47,7 +47,7 @@ class HTTPSyncTarget(http_client.HTTPClientBase, SyncTarget):
if self._trace_hook: # for tests
self._trace_hook('record_sync_info')
self._request_json('PUT', ['sync-from', source_replica_uid], {},
- {'generation': source_replica_generation,
+ {'generation': source_replica_generation,
'transaction_id': source_transaction_id})
def _parse_sync_stream(self, data, return_doc_cb, ensure_callback=None):
diff --git a/common/src/leap/soledad/common/l2db/remote/oauth_middleware.py b/common/src/leap/soledad/common/l2db/remote/oauth_middleware.py
deleted file mode 100644
index 5772580a..00000000
--- a/common/src/leap/soledad/common/l2db/remote/oauth_middleware.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright 2012 Canonical Ltd.
-#
-# This file is part of u1db.
-#
-# u1db is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License version 3
-# as published by the Free Software Foundation.
-#
-# u1db 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 Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with u1db. If not, see <http://www.gnu.org/licenses/>.
-"""U1DB OAuth authorisation WSGI middleware."""
-import httplib
-from oauth import oauth
-try:
- import simplejson as json
-except ImportError:
- import json # noqa
-from urllib import quote
-from wsgiref.util import shift_path_info
-
-
-sign_meth_HMAC_SHA1 = oauth.OAuthSignatureMethod_HMAC_SHA1()
-sign_meth_PLAINTEXT = oauth.OAuthSignatureMethod_PLAINTEXT()
-
-
-class OAuthMiddleware(object):
- """U1DB OAuth Authorisation WSGI middleware."""
-
- # max seconds the request timestamp is allowed to be shifted
- # from arrival time
- timestamp_threshold = 300
-
- def __init__(self, app, base_url, prefix='/~/'):
- self.app = app
- self.base_url = base_url
- self.prefix = prefix
-
- def get_oauth_data_store(self):
- """Provide a oauth.OAuthDataStore."""
- raise NotImplementedError(self.get_oauth_data_store)
-
- def _error(self, start_response, status, description, message=None):
- start_response("%d %s" % (status, httplib.responses[status]),
- [('content-type', 'application/json')])
- err = {"error": description}
- if message:
- err['message'] = message
- return [json.dumps(err)]
-
- def __call__(self, environ, start_response):
- if self.prefix and not environ['PATH_INFO'].startswith(self.prefix):
- return self._error(start_response, 400, "bad request")
- headers = {}
- if 'HTTP_AUTHORIZATION' in environ:
- headers['Authorization'] = environ['HTTP_AUTHORIZATION']
- oauth_req = oauth.OAuthRequest.from_request(
- http_method=environ['REQUEST_METHOD'],
- http_url=self.base_url + environ['PATH_INFO'],
- headers=headers,
- query_string=environ['QUERY_STRING']
- )
- if oauth_req is None:
- return self._error(start_response, 401, "unauthorized",
- "Missing OAuth.")
- try:
- self.verify(environ, oauth_req)
- except oauth.OAuthError, e:
- return self._error(start_response, 401, "unauthorized",
- e.message)
- shift_path_info(environ)
- return self.app(environ, start_response)
-
- def verify(self, environ, oauth_req):
- """Verify OAuth request, put user_id in the environ."""
- oauth_server = oauth.OAuthServer(self.get_oauth_data_store())
- oauth_server.timestamp_threshold = self.timestamp_threshold
- oauth_server.add_signature_method(sign_meth_HMAC_SHA1)
- oauth_server.add_signature_method(sign_meth_PLAINTEXT)
- consumer, token, parameters = oauth_server.verify_request(oauth_req)
- # filter out oauth bits
- environ['QUERY_STRING'] = '&'.join("%s=%s" % (quote(k, safe=''),
- quote(v, safe=''))
- for k, v in parameters.iteritems())
- return consumer, token
diff --git a/common/src/leap/soledad/common/l2db/remote/server_state.py b/common/src/leap/soledad/common/l2db/remote/server_state.py
index 6c1104c6..f131e09e 100644
--- a/common/src/leap/soledad/common/l2db/remote/server_state.py
+++ b/common/src/leap/soledad/common/l2db/remote/server_state.py
@@ -18,6 +18,7 @@
import os
import errno
+
class ServerState(object):
"""Passed to a Request when it is instantiated.
diff --git a/common/src/leap/soledad/common/l2db/remote/ssl_match_hostname.py b/common/src/leap/soledad/common/l2db/remote/ssl_match_hostname.py
index fbabc177..ce82f1b2 100644
--- a/common/src/leap/soledad/common/l2db/remote/ssl_match_hostname.py
+++ b/common/src/leap/soledad/common/l2db/remote/ssl_match_hostname.py
@@ -52,13 +52,14 @@ def match_hostname(cert, hostname):
return
dnsnames.append(value)
if len(dnsnames) > 1:
- raise CertificateError("hostname %r "
- "doesn't match either of %s"
+ raise CertificateError(
+ "hostname %r doesn't match either of %s"
% (hostname, ', '.join(map(repr, dnsnames))))
elif len(dnsnames) == 1:
- raise CertificateError("hostname %r "
- "doesn't match %r"
+ raise CertificateError(
+ "hostname %r doesn't match %r"
% (hostname, dnsnames[0]))
else:
- raise CertificateError("no appropriate commonName or "
+ raise CertificateError(
+ "no appropriate commonName or "
"subjectAltName fields were found")
diff --git a/common/src/leap/soledad/common/l2db/sync.py b/common/src/leap/soledad/common/l2db/sync.py
index 26e67140..c612629f 100644
--- a/common/src/leap/soledad/common/l2db/sync.py
+++ b/common/src/leap/soledad/common/l2db/sync.py
@@ -53,7 +53,8 @@ class Synchronizer(object):
"""
# Increases self.num_inserted depending whether the document
# was effectively inserted.
- state, _ = self.source._put_doc_if_newer(doc, save_conflict=True,
+ state, _ = self.source._put_doc_if_newer(
+ doc, save_conflict=True,
replica_uid=self.target_replica_uid, replica_gen=replica_gen,
replica_trans_id=trans_id)
if state == 'inserted':
@@ -85,10 +86,10 @@ class Synchronizer(object):
new generation.
"""
cur_gen, trans_id = self.source._get_generation_info()
- if (cur_gen == start_generation + self.num_inserted
- and self.num_inserted > 0):
- self.sync_target.record_sync_info(
- self.source._replica_uid, cur_gen, trans_id)
+ last_gen = start_generation + self.num_inserted
+ if (cur_gen == last_gen and self.num_inserted > 0):
+ self.sync_target.record_sync_info(
+ self.source._replica_uid, cur_gen, trans_id)
def sync(self, callback=None, autocreate=False):
"""Synchronize documents between source and target."""
@@ -124,15 +125,17 @@ class Synchronizer(object):
if self.target_replica_uid is None:
target_last_known_gen, target_last_known_trans_id = 0, ''
else:
- target_last_known_gen, target_last_known_trans_id = \
- self.source._get_replica_gen_and_trans_id(self.target_replica_uid)
+ target_last_known_gen, target_last_known_trans_id = (
+ self.source._get_replica_gen_and_trans_id( # nopep8
+ self.target_replica_uid))
if not changes and target_last_known_gen == target_gen:
if target_trans_id != target_last_known_trans_id:
raise errors.InvalidTransactionId
return my_gen
changed_doc_ids = [doc_id for doc_id, _, _ in changes]
# prepare to send all the changed docs
- docs_to_send = self.source.get_docs(changed_doc_ids,
+ docs_to_send = self.source.get_docs(
+ changed_doc_ids,
check_for_conflicts=False, include_deleted=True)
# TODO: there must be a way to not iterate twice
docs_by_generation = zip(
@@ -172,7 +175,7 @@ class SyncExchange(object):
self._db._last_exchange_log = {
'receive': {'docs': self._incoming_trace},
'return': None
- }
+ }
def _set_trace_hook(self, cb):
self._trace_hook = cb
@@ -198,7 +201,8 @@ class SyncExchange(object):
:param source_gen: The source generation of doc.
:return: None
"""
- state, at_gen = self._db._put_doc_if_newer(doc, save_conflict=False,
+ state, at_gen = self._db._put_doc_if_newer(
+ doc, save_conflict=False,
replica_uid=self.source_replica_uid, replica_gen=source_gen,
replica_trans_id=trans_id)
if state == 'inserted':
@@ -217,7 +221,7 @@ class SyncExchange(object):
self._db._last_exchange_log['receive'].update({
'source_uid': self.source_replica_uid,
'source_gen': source_gen
- })
+ })
def find_changes_to_return(self):
"""Find changes to return.
@@ -232,7 +236,7 @@ class SyncExchange(object):
"""
self._db._last_exchange_log['receive'].update({ # for tests
'last_known_gen': self.source_last_known_generation
- })
+ })
self._trace('before whats_changed')
gen, trans_id, changes = self._db.whats_changed(
self.source_last_known_generation)
@@ -242,9 +246,9 @@ class SyncExchange(object):
seen_ids = self.seen_ids
# changed docs that weren't superseded by or converged with
self.changes_to_return = [
- (doc_id, gen, trans_id) for (doc_id, gen, trans_id) in changes
+ (doc_id, gen, trans_id) for (doc_id, gen, trans_id) in changes if
# there was a subsequent update
- if doc_id not in seen_ids or seen_ids.get(doc_id) < gen]
+ doc_id not in seen_ids or seen_ids.get(doc_id) < gen]
return self.new_gen
def return_docs(self, return_doc_cb):