diff options
author | drebs <drebs@leap.se> | 2015-04-09 17:18:37 -0300 |
---|---|---|
committer | drebs <drebs@leap.se> | 2015-04-09 18:20:00 -0300 |
commit | b0ef529cc882a96903597fb5279919969fa286c3 (patch) | |
tree | 2243cd550e3e0769880b350184b5f5a3653c362a /src/leap | |
parent | 45adb4d6cfdb8b9ed11e3efc398d00ec6dbdc0b0 (diff) |
[refactor] use couch reduced views for lookups
The way uuid and pgp key were being queried by means of couch views was not
efficient because they weren't using the reduce function and were filtering
the views results in the python code. Also, the uuid is not actually needed to
find out either if the address exists or if there's a pgp public key for that
address. This commit refactors the couch helper to make use of the reduce
functions in queried views and to get rid of the intermediate uuid querying.
Diffstat (limited to 'src/leap')
-rw-r--r-- | src/leap/mx/alias_resolver.py | 10 | ||||
-rw-r--r-- | src/leap/mx/check_recipient_access.py | 25 | ||||
-rw-r--r-- | src/leap/mx/couchdbhelper.py | 139 | ||||
-rw-r--r-- | src/leap/mx/tcp_map.py | 4 |
4 files changed, 47 insertions, 131 deletions
diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index a139dd0..dd631c8 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -40,22 +40,22 @@ class LEAPPostfixTCPMapAliasServer(postfix.PostfixTCPMapServer): A postfix tcp map alias resolver server. """ - def _cbGot(self, uuid): + def _cbGot(self, address): """ Return a code and message depending on the result of the factory's get(). - :param value: The uuid. - :type value: list + :param address: The address returned by the factory. + :type address: str """ - if uuid is None: + if address is None: self.sendCode( TCP_MAP_CODE_PERMANENT_FAILURE, postfix.quote("NOT FOUND SRY")) else: self.sendCode( TCP_MAP_CODE_SUCCESS, - postfix.quote(uuid)) + postfix.quote(address)) class AliasResolverFactory(LEAPPostfixTCPMapServerFactory): diff --git a/src/leap/mx/check_recipient_access.py b/src/leap/mx/check_recipient_access.py index 0977564..3b61fe8 100644 --- a/src/leap/mx/check_recipient_access.py +++ b/src/leap/mx/check_recipient_access.py @@ -50,8 +50,8 @@ class LEAPPostFixTCPMapAccessServer(postfix.PostfixTCPMapServer): :param value: The uuid and public key. :type value: list """ - uuid, pubkey = value - if uuid is None: + address, pubkey = value + if address is None: self.sendCode( TCP_MAP_CODE_PERMANENT_FAILURE, postfix.quote("REJECT")) @@ -75,25 +75,22 @@ class CheckRecipientAccessFactory(LEAPPostfixTCPMapServerFactory): protocol = LEAPPostFixTCPMapAccessServer - def _getPubKey(self, uuid): + def _getPubKey(self, address): """ - Look up PGP public key based on user uid. + Look up PGP public key based on email address. - :param uuid: The user uid. - :type uuid: str + :param address: The email address. + :type address: str - :return: A deferred that is fired with the uuid and the public key, if - available. + :return: A deferred that is fired with the address and the public key, if + each of them exists. :rtype: DeferredList """ - if uuid is None: + if not address: return defer.succeed([None, None]) - # properly encode uuid, otherwise twisted complains when replying - if isinstance(uuid, unicode): - uuid = uuid.encode("utf8") return defer.gatherResults([ - defer.succeed(uuid), - self._cdb.getPubKey(uuid), + defer.succeed(address), + self._cdb.getPubKey(address), ]) def get(self, key): diff --git a/src/leap/mx/couchdbhelper.py b/src/leap/mx/couchdbhelper.py index f20f1dd..7bcb5aa 100644 --- a/src/leap/mx/couchdbhelper.py +++ b/src/leap/mx/couchdbhelper.py @@ -15,24 +15,15 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. + """ Classes for working with CouchDB or BigCouch instances which store email alias maps, user UUIDs, and GPG keyIDs. """ -from functools import partial - -try: - from paisley import client -except ImportError: - print "This software requires paisley. Please see the README file" - print "for instructions on getting required dependencies." -try: - from twisted.python import log -except ImportError: - print "This software requires Twisted. Please see the README file" - print "for instructions on getting required dependencies." +from paisley import client +from twisted.python import log class ConnectedCouchDB(client.CouchDB): @@ -66,24 +57,8 @@ class ConnectedCouchDB(client.CouchDB): username=username, password=password, *args, **kwargs) - self._cache = {} - if dbName is None: - databases = self.listDB() - databases.addCallback(self._print_databases) - - def _print_databases(self, data): - """ - Callback for listDB that prints the available databases - - :param data: response from the listDB command - :type data: array - """ - log.msg("Available databases:") - for database in data: - log.msg(" * %s" % (database,)) - def createDB(self, dbName): """ Overrides ``paisley.client.CouchDB.createDB``. @@ -100,106 +75,52 @@ class ConnectedCouchDB(client.CouchDB): """ Check to see if a particular email or alias exists. - :param alias: A string representing the email or alias to check. - :type alias: str + :param address: A string representing the email or alias to check. + :type address: str :return: a deferred for this query :rtype twisted.defer.Deferred """ - assert isinstance(address, (str, unicode)), "Email or alias queries must be string" - # TODO: Cache results - d = self.openView(docId="Identity", viewId="by_address/", key=address, - reduce=False, - include_docs=True) + reduce=True, + include_docs=False) - d.addCallbacks(partial(self._get_uuid, address), log.err) + def _callback(result): + if len(result["rows"]): + return address + return None + + d.addCallbacks(_callback, log.err) return d - def _get_uuid(self, address, result): - """ - Parses the result of the by_address query and gets the uuid - - :param address: alias looked up - :type address: string - :param result: result dictionary - :type result: dict - :return: The uuid for alias if available - :rtype: str - """ - for row in result["rows"]: - if row["key"] == address: - uuid = row["doc"].get("user_id", None) - if uuid is None: - log.msg("ERROR: Found doc for %s but there's not user_id!" - % (address,)) - return uuid - return None - - def getPubKey(self, uuid): + def getPubKey(self, address): """ - Returns a deferred that will return the pubkey for the uuid provided + Returns a deferred that will fire with the pubkey for the address. - :param uuid: uuid for the user to query - :type uuid: str + :param address: email address to query + :type address: str :rtype: Deferred """ d = self.openView(docId="Identity", viewId="pgp_key_by_email/", - user_id=uuid, + key=address, reduce=False, - include_docs=True) - - d.addCallbacks(partial(self._get_pgp_key, uuid), log.err) + include_docs=False) - return d - - def _get_pgp_key(self, uuid, result): - """ - Callback used to filter the correct pubkey from the result of - the query to the couchdb + def _callback(result): + if not result["rows"]: + log.msg("No PGP public key found for %s." % address) + return None + if len(result["rows"]) > 1: + log.msg("More than one PGP public key found for %s, " + "will pick the first one found." % address) + row = result["rows"].pop(0) + return row["value"] - :param uuid: uuid for the user that was queried - :type uuid: str - :param result: result dictionary for the db query - :type result: dict + d.addCallbacks(_callback, log.err) - :rtype: str or None - """ - for row in result["rows"]: - user_id = row["doc"].get("user_id") - if not user_id: - print("User %s is in an inconsistent state") - continue - if user_id == uuid: - return row["value"] - return None - -if __name__ == "__main__": - from twisted.internet import reactor - cdb = ConnectedCouchDB("localhost", - port=6666, - dbName="users", - username="", - password="") - - d = cdb.queryByLoginOrAlias("test1") - - @d.addCallback - def right(result): - print "Should be an actual uuid:", result - print "Public Key:" - print cdb.getPubKey(result) - - d2 = cdb.queryByLoginOrAlias("asdjaoisdjoiqwjeoi") - - @d2.addCallback - def wrong(result): - print "Should be None:", result - - reactor.callLater(5, reactor.stop) - reactor.run() + return d diff --git a/src/leap/mx/tcp_map.py b/src/leap/mx/tcp_map.py index b62441f..d8cd835 100644 --- a/src/leap/mx/tcp_map.py +++ b/src/leap/mx/tcp_map.py @@ -43,9 +43,7 @@ class LEAPPostfixTCPMapServerFactory(ServerFactory): def get(self, key): """ - Look up uuid based on key, only up to the username id of the key. - - At some point we will have to consider the domain part too. + Look up if address exists. :param key: The lookup key. :type key: str |