From bfb8701fdeeffddee090306b0fca36733605cdc2 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:29:49 +0000 Subject: Update module docstring for alias_resolver.py. --- src/leap/mx/alias_resolver.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index e079b80..f9f0ca1 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -5,22 +5,15 @@ alias_resolver.py ================= Classes for resolving postfix aliases. -@authors: Isis Agora Lovecruft -@version: 0.0.1-beta -@license: see included LICENSE file -@copyright: copyright 2013 Isis Agora Lovecruft +:authors: Isis Agora Lovecruft +:version: 0.0.1-beta +:license: see included LICENSE file +:copyright: (c) 2013 Isis Agora Lovecruft TODO: o Look into using twisted.protocols.postfix.policies classes for controlling concurrent connections and throttling resource consumption. - - o alias.ProcessAlias() - -## have uuid -> get gpg keyid - -alias.ProcessAlias('/path/to/mail_reciever', *args) - ''' import os -- cgit v1.2.3 From b86827df8d3db5ca87eb064f65886660426fa60f Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:30:23 +0000 Subject: Import our couchdb module into alias_resolver.py. --- src/leap/mx/alias_resolver.py | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index f9f0ca1..8ab84e5 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -27,6 +27,7 @@ except ImportError: print "This software requires Twisted. Please see the README file" print "for instructions on getting required dependencies." +from leap.mx import couchdb from leap.mx.util import net, log, config, exceptions -- cgit v1.2.3 From db49089b2f13d45a1f0fca5ae5cc52dfcc4eac2e Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:31:01 +0000 Subject: Update docstring for function alias_resolver.createUUID(). --- src/leap/mx/alias_resolver.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 8ab84e5..d8d4646 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -32,14 +32,16 @@ from leap.mx.util import net, log, config, exceptions def createUUID(alias): - """ - Creates Universal Unique ID by taking the SHA-1 HASH of an email alias: + """Creates Universal Unique ID by taking the SHA1 HASH of an email alias: + + >>> uuid.uuid5(uuid.NAMESPACE_URL, "isis@leap.se") + UUID('7194878e-4aea-563f-85a4-4f58519f3c4f') - >>> uuid.uuid5(uuid.NAMESPACE_URL, "isis@leap.se") - UUID('7194878e-4aea-563f-85a4-4f58519f3c4f') + TODO: Is there a commonly accepted way to check that an email address + is valid? - @param alias: An email address alias. - @returns: A :class:`uuid.UUID` containing attributes specifying the UUID. + :param str alias: An email address alias. + :returns: A :class:`uuid.UUID` containing attributes specifying the UUID. """ return uuid.uuid5(uuid.NAMESPACE_URL, str(alias)) -- cgit v1.2.3 From 23bfd56fc80fac38ece4273d8c0ebe678e458be3 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:31:34 +0000 Subject: Add DatabaseNotConnected exception to alias_resolver.py. --- src/leap/mx/alias_resolver.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index d8d4646..30d8ee3 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -45,6 +45,10 @@ def createUUID(alias): """ return uuid.uuid5(uuid.NAMESPACE_URL, str(alias)) + +class DatabaseNotConnected(Exception): + """Raised when not currently connected to a database.""" + class StatusCodes(object): """ The Postfix manual states: -- cgit v1.2.3 From 4b13ac66d10b98a57c9161ed9b43a26b22585e96 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:32:44 +0000 Subject: Update class docstring for alias_resolver.StatusCodes. --- src/leap/mx/alias_resolver.py | 46 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 30d8ee3..310830b 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -50,15 +50,51 @@ class DatabaseNotConnected(Exception): """Raised when not currently connected to a database.""" class StatusCodes(object): - """ - The Postfix manual states: + """The Postfix manual states: + + The request completion status is one of OK, RETRY, NOKEY (lookup failed + because the key was not found), BAD (malformed request) or DENY (the + table is not approved for proxy read or update access). + + In brief, Postfix will send ``get SPACE key NEWLINE``, or + ``put SPACE key NEWLINE`` where ``key`` is an alias or email address. + It expects non-printable ascii characters to be url-encoded, i.e. a + get-request would look like: + + ``get%20isis@leap.se%0A`` + + and in response, Postfix expects an SMTP-like status code and a string + describing the nature of or reason for the response, no longer than + 4096 "characters" (which, due to UTF-8 ubiquity, we'll err on the safe + side and assume that means 4096 bytes.) - The request completion status is one of OK, RETRY, NOKEY (lookup - failed because the key was not found), BAD (malformed request) or DENY - (the table is not approved for proxy read or update access). + From the Postfix manual on its TCP map protocol + (http://www.postfix.org/tcp_table.5.html): + + 500 SPACE text NEWLINE + In case of a lookup request, the requested data + does not exist. In case of an update request, the + request was rejected. The text describes the + nature of the problem. + + 400 SPACE text NEWLINE + This indicates an error condition. The text + describes the nature of the problem. The client + should retry the request later. + + 200 SPACE text NEWLINE + The request was successful. In the case of a lookup + request, the text contains an encoded version of + the requested data. Other SMTP codes: http://www.greenend.org.uk/rjk/tech/smtpreplies.html + + >>> statcodes = StatusCodes() + >>> if : + >>> response_message = statcodes(200) + >>> aliasresolver.tellMTA() """ + OK = "OK Others might say 'HELLA AWESOME'...but we're not convinced." RETRY = "RETRY Server is busy plotting revolution; requests might take a while." BAD = "BAD bad Leroy Brown, baddest man in the whole...er. Malformed request." -- cgit v1.2.3 From df6f7a038f3738f76cf7f5bb4a85e17a9a27ec56 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:34:02 +0000 Subject: Update mappings of Postfix TCP map protocol codes to message strings. --- src/leap/mx/alias_resolver.py | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 310830b..38311d8 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -101,15 +101,23 @@ class StatusCodes(object): NOKEY = "NOKEY Couldn't find your keys, sorry. Did you check in the sofa?" DEFER = "DEFER_IF_LOCAL xxx fill me in" DENY = "DENY no gurlz aloud in teh tree house." - FAIL = "FAIL xxx fill me in" - - fakeSMTPCodes = { '250': OK, - '300': RETRY, - '500': BAD, - '550': NOKEY, - '552': DEFER, - '553': DENY, - '554': FAIL, } + FAIL = "FAIL this belongs on the failblog" + + SMTPCodes = { '200': OK, + '400': RETRY, + '500': BAD, + '550': NOKEY, + '552': DEFER, + '553': DENY, + '554': FAIL, } + + SMTPStrings = { 'OK' 200, + 'RETRY': 400, + 'BAD': 500, + 'NOKEY': 550, + 'DEFER': 552, + 'DENY': 553, + 'FAIL': 554, } def __init__(self, status_code=None): """xxx fill me in""" -- cgit v1.2.3 From e17f2beb230b3276473d77957e4d6a3f4da2c814 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:34:57 +0000 Subject: Create method-level docstrings for alias_resolver.StatusCodes. --- src/leap/mx/alias_resolver.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 38311d8..4fc20f5 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -120,12 +120,30 @@ class StatusCodes(object): 'FAIL': 554, } def __init__(self, status_code=None): - """xxx fill me in""" + """Construct an SMTP status code generator. + + :type status_code: str or int + :param status_code: (optional) see :func:`StatusCode.get`. + """ if status_code: self.get(status_code) def get(self, status_code=None) - """xxx fill me in""" + """Takes an SMTP-like status code and returns an SMTP-like message. + + :type status_code: str or int + :param status_code: The string or integer for the response we want + to give back to the MTA, after looking up an + email address in the local user database. + Can be one of: + * ``OK`` or ``200`` + * ``RETRY`` or ``400`` + * ``BAD`` or ``500`` + * ``NOKEY`` or ``550`` + * ``DEFER`` or ``552`` + * ``DENY`` or ``553`` + * ``FAIL`` or ``554`` + """ if status_code: if isinstance(status_code, str): return status_code, getattr(self, status_code.upper(), None) -- cgit v1.2.3 From 8646cf310a34828920f9cbf36c1f4c3da3cb6f9d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:35:47 +0000 Subject: Fix logic for return of Postfix TCP map responses in alias_resolver.StatusCodes --- src/leap/mx/alias_resolver.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 4fc20f5..48e7a85 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -146,11 +146,15 @@ class StatusCodes(object): """ if status_code: if isinstance(status_code, str): - return status_code, getattr(self, status_code.upper(), None) + if status_code.upper() in self.SMTPStrings.keys(): + return self.SMTPStrings[status_code], getattr( + self, status_code.upper(), '') + else: + return 500, self.FAIL elif isinstance(status_code, int): - for k, v in self.fake_smtp_codes.items(): - ## we want to return None if it's 550 - if k == str(status_code) and k != '550': + for k, v in self.SMTPCodes.items(): + ## we want to return None if it's 500 + if k == str(status_code) and k != '500': return status_code, v log.debug("%s" % self.NOKEY) return None, '' -- cgit v1.2.3 From 0d6a18c52fa2632e9915bf4acdf01a43c2487e8d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:38:18 +0000 Subject: Update docstrings in alias_resolver.AliasResolver. --- src/leap/mx/alias_resolver.py | 45 ++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 48e7a85..2a244d0 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -161,12 +161,11 @@ class StatusCodes(object): class AliasResolver(postfix.PostfixTCPMapServer): - """ - Resolve postfix aliases, similarly to using "$ postmap -q ". + """Resolve postfix aliases, similarly to using "$ postmap -q ". This class starts a simple LineReceiver server which listens for a string - specifying an alias to look up, :param:`key`, and which will be used to - query the local Postfix server. You can test it with: + specifying an alias ``key`` to look up, which will be used to query the + local user database. You can test it with: $ ./alias_resolver.py & $ /usr/bin/postmap -q tcp:localhost:1347 @@ -176,7 +175,12 @@ class AliasResolver(postfix.PostfixTCPMapServer): https://www.iana.org/assignments/smtp-enhanced-status-codes/ """ def __init__(self, *args, **kwargs): - """Create a server which listens for Postfix aliases to resolve.""" + """Create a server which listens for Postfix aliases to resolve. + + :param int timeout: Number of seconds to wait for a response. + :param str delimiter: The delimiter to use for the EOL on responses. + (Default: '\n') + """ super(postfix.PostfixTCPMapServer, self).__init__(*args, **kwargs) self.status_codes = StatusCodes() @@ -198,7 +202,11 @@ class AliasResolver(postfix.PostfixTCPMapServer): @defer.inlineCallbacks def do_put(self, keyAndValue): - """Add a key and value to the database, provided it does not exist.""" + """Add a key and value to the database, provided it does not exist. + + :param str keyAndValue: An alias and email address, separated by a + space, i.e. ``"isis isis@leap.se"``. + """ if keyAndValue is None: self.sendCode(500) log.warn("Command 'put' takes two parameters.") @@ -219,20 +227,26 @@ class AliasResolver(postfix.PostfixTCPMapServer): @defer.inlineCallbacks def do_delete(self, key): - """ - Delete an alias from the mapping database. + """Delete an alias from the CouchDB. + + xxx I'm not sure if implementing this would be a good idea... - xxx not sure if this is a good idea... + :param str key: An email address to delete from the CouchDB. """ raise NotImplemented def check_recipient_access(self, key): - """Make a query to resolve an alias.""" - self.do_get(self, key) + """Make a query to the CouchDB to resolve an alias. - def virtual_alias_map(self, key): + If the ``key`` is an email address which the CouchDB has information + for that account, we should respond to Postfix with an '200%20\n". + + :param str key: An email address to look up in the CouchDB. """ - Get the Universal Unique ID for the alias address. If + self.do_get(key) + + def virtual_alias_map(self, key): + """Get the Universal Unique ID for the alias address. If virtual_transport is True, then suffix the UUID with a domain. xxx I don't think we actually need couchdb for this, the UUID is an @@ -241,6 +255,11 @@ class AliasResolver(postfix.PostfixTCPMapServer): querying a database, I would presume), it seems silly to do this. Instead, we should query CouchDB with the UUID to get the GPG keyid. + + xxx Or are we supposed to query Soledad for this? + + :param str key: An email address to look up in the CouchDB. + :returns: The UUID of the user. """ ## xxx need email address parser client_id = createUUID(key) -- cgit v1.2.3 From 80e9dc5548b36d1c4f99446a4c1412fcb2c93122 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:40:05 +0000 Subject: Add support for Postfix virtual transports to alias_resolver.AliasResolver. --- src/leap/mx/alias_resolver.py | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 2a244d0..c080123 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -174,6 +174,10 @@ class AliasResolver(postfix.PostfixTCPMapServer): http://www.postfix.org/proxymap.8.html https://www.iana.org/assignments/smtp-enhanced-status-codes/ """ + + virtual_transport = '@example.com' + use_virtual_transport = False + def __init__(self, *args, **kwargs): """Create a server which listens for Postfix aliases to resolve. @@ -262,31 +266,13 @@ class AliasResolver(postfix.PostfixTCPMapServer): :returns: The UUID of the user. """ ## xxx need email address parser - client_id = createUUID(key) + userid = createUUID(key) - if self.virtual_transport: - return client.get_urn() + '@example.com' - else: - return client.get_urn() - - def _cbGot(self, value): - """Callback for self.get()""" - if value is None: - self.sendCode(550) + if self.use_virtual_transport \ + and isinstance(self.virtual_transport, str): + return userid.get_urn() + self.virtual_transport else: - self.sendCode(250, quote(value)) - - def _cbNot(self, fail): - """Errback for self.get()""" - self.sendCode(554, fail.getErrorMessage()) - - def _cbPut(self, value): - """xxx fill me in""" - pass - - def _cbPout(self, fail): - """xxx fill me in""" - pass + return userid.get_urn() class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): @@ -314,6 +300,8 @@ class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): super(postfix.PostfixTCPMapDeferringDictServerFactory, self).__init__(data=data) self.timeout = timeout + self.virtual_transport = virtual_transport + self.use_virtual_transport = use_virtual_transport self.noisy = True if config.advanced.noisy else False try: @@ -339,6 +327,8 @@ class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): """ proto = self.protocol() proto.timeout = self.timeout + proto.virtual_transport = self.virtual_transport + proto.use_virtual_transport = self.use_virtual_transport proto.factory = self return proto -- cgit v1.2.3 From 2c3083e0631f59faeb60197bfa06235b36b86a99 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:41:15 +0000 Subject: Change the logic on sending Postfix TCP map status codes and messages. --- src/leap/mx/alias_resolver.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index c080123..1a7392d 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -189,9 +189,21 @@ class AliasResolver(postfix.PostfixTCPMapServer): self.status_codes = StatusCodes() def sendCode(self, code, message=None): - """Send an SMTP-like code with a message.""" - if not message: - message = self.status_codes.get(code) + """Send an SMTP-like code with a message. + + :type code: str or int + :param code: The status code to send, see + ``alias_resolver.StatusCodes``. + """ + try: + assert isinstance(code, int), "status code must be type int" + except AssertionError as ae: + log.err(ae.message) + self.sendLine('500 internal server error: %s' % ae.message) + + msg = self.status_codes.get(code) + if message is not None and isinstance(message, str): + msg += (" " + message) self.sendLine('%3.3d %s' % (code, message or '')) def do_get(self, key): -- cgit v1.2.3 From 6ff05c3bf6d66f9b9efcfccf4a61b11d0434cf43 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:46:31 +0000 Subject: Pass the deferred response from CouchDB along to sendLine in AliasResolver. --- src/leap/mx/alias_resolver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 1a7392d..8a1537a 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -259,7 +259,7 @@ class AliasResolver(postfix.PostfixTCPMapServer): :param str key: An email address to look up in the CouchDB. """ - self.do_get(key) + return self.do_get(key) def virtual_alias_map(self, key): """Get the Universal Unique ID for the alias address. If -- cgit v1.2.3 From 784b0f531edee13f9ff66b73f90aad7176ae4a24 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:47:43 +0000 Subject: Add CouchDB instance as an attribute of AliasResolverFactory and update docs. --- src/leap/mx/alias_resolver.py | 58 +++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 8a1537a..a489e4c 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -288,26 +288,48 @@ class AliasResolver(postfix.PostfixTCPMapServer): class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): - """ - A Factory for creating :class:`AliasResolver` servers, which handles inputs - and outputs, and keeps an in-memory mapping of Postfix aliases in the form - of a dictionary. - - xxx fill me in + """A Factory for creating :class:`AliasResolver` servers, which handles + inputs and outputs, and keeps an in-memory mapping of Postfix aliases in + the form of a dictionary. + + >>> from leap.mx import alias_resolver + >>> aliasResolverFactory = alias_resolver.AliasResolver( + ... data={'isis': 'isis@leap.se', + ... 'drebs': 'drebs@leap.se', + ... 'elijah': 'elijah@leap.se',}) + >>> aliasResolver = aliasResolverFactory.buildProtocol() + >>> aliasResolver.check_recipient_access('isis') """ protocol = AliasResolver - - def __init__(self, addr='127.0.0.1', port=4242, timeout=120, data=None): - """ - Create a Factory which returns :class:`AliasResolver` servers. - - @param addr: A string giving the IP address of this server. - Default: '127.0.0.1' - @param port: An integer that specifies the port number to listen - on. Default: 4242 - @param timeout: An integer specifying the number of seconds to wait - until we should time out. Default: 120 - @param data: A dict to use to initialise or update the alias mapping. + database = couchdb.ConnectedCouchDB + + def __init__(self, addr='127.0.0.1', port=4242, timeout=120, + data=None, virtual_transport=None, use_virtual_transport=False, + couch_host=None, couch_port=None, couch_dbname='users', + couch_username=None, couch_password=None): + """Create a Factory which returns :class:`AliasResolver` servers. + + :param str addr: A string giving the IP address of this server, for + talking to postfix. Default: '127.0.0.1' + :param int port: An integer that specifies the port number that this + server should listen and respond on, for talking to + Postfix. on. Default: 4242 + :param int timeout: An integer specifying the number of seconds to wait + until we should time out. Default: 120 + :param dict data: A dict to use to initialise or update the alias + mapping. + :param str virtual_transport: The domain portion of an email address + to suffix the UUID responses of + ``AliasResolver.virtual_alias_map`` with. + :param bool use_virtual_transport: If True, suffix UUIDs with the + ``virtual_transport`` string. + + :param str couch_host: The IP address of the CouchDB server to query. + :param int couch_port: The port of the CouchDB server to query. + :param str couch_dbname: The database in the CouchDB to bind to. + :param str couch_username: The username for authenticating to the + CouchDB. + :param str couch_password: The password for authentication. """ super(postfix.PostfixTCPMapDeferringDictServerFactory, self).__init__(data=data) -- cgit v1.2.3 From dd0920e81e15539560f1d29033658132ba7044c1 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:48:59 +0000 Subject: Add connection to CouchDB instance to AliasResolverFactory. --- src/leap/mx/alias_resolver.py | 47 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index a489e4c..0747882 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -338,6 +338,16 @@ class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): self.use_virtual_transport = use_virtual_transport self.noisy = True if config.advanced.noisy else False + if couch_port is None: + couch_port = 5984 + if couch_dbname is None: + couch_dbname = 'users' + self.database_connected = False + if couch_host is not None: + self.couch = self.connectDatabase(couch_host, couch_port, + couch_dbname, couch_username, + couch_password) + try: assert isinstance(port, int), "Port number must be an integer" assert isinstance(timeout, int), "Timeout must be an integer" @@ -366,17 +376,36 @@ class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): proto.factory = self return proto - def get(self, *args, **kwargs): - """ - xxx connect me to the couchdb - """ - pass + def _cb_connectDatabase(self): + self.database_connected = True - def put(self, *args, **kwargs): - """ - xxx connect me to the couchdb + def connectDatabase(self, couch_host, couch_port=None, couch_dbname=None, + couch_username=None, couch_password=None): + """Connect to the CouchDB instance.""" + if not self.database_connected: + d = self.database(couch_host, couch_port, dbName=couch_dbname, + username=couch_username, password=couch_password) + d.addCallback(self._cb_connectDatabase) + d.addErrback(log.err) + return d + else: + return self.couch ## xxx are we sure we only want one connection? + + def get(self, key, **kwargs): + """Query the CouchDB for a user's info. + + :param str key: The alias to look up. Should be either an email address + or a username. (xxx do we want to also support lookups + by UUID?) """ - pass + if self.database_connected: + return self.couch.queryByEmailOrAlias(key) + else: + raise DatabaseNotConnected("Must be connected to a database.") + + def put(self, key, **kwargs): + """Add an alias to the CouchDB database.""" + raise NotImplemented if __name__ == "__main__": -- cgit v1.2.3 From cc56ea05d09dd2304350ed531d6220e9b2adc29d Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:49:38 +0000 Subject: Update AliasResolver.buildProtocol() docstring. --- src/leap/mx/alias_resolver.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 0747882..f71c4d8 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -366,9 +366,7 @@ class AliasResolverFactory(postfix.PostfixTCPMapDeferringDictServerFactory): % (addr, port)) def buildProtocol(self): - """ - Create an instance of the :class:`AliasResolver` server. - """ + """Create an instance of the :class:`AliasResolver` server.""" proto = self.protocol() proto.timeout = self.timeout proto.virtual_transport = self.virtual_transport -- cgit v1.2.3 From f69a085cfe9d904404cb421e802515b716cfbf9c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:50:23 +0000 Subject: Update couchdb.ConnectedCouchDB class docstring. --- src/leap/mx/couchdb.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index b5d4127..c020295 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -26,11 +26,10 @@ from leap.mx.util import log class ConnectedCouchDB(client.CouchDB): - """ - Connect to a CouchDB instance. + """Connect to a CouchDB instance. - ## xxx will we need to open CouchDB documents and views? - ## yes, these are in a _design document + CouchDB document for testing is '_design', and the view is simply + a preconfigured set of mapped responses. """ def __init__(self, host, port, dbName=None, username=None, password=None, *args, **kwargs): -- cgit v1.2.3 From 07488a8d4c4aea1f7c86cd13219ee37ec8b46850 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:50:50 +0000 Subject: Add default CouchDB port to couchdb.ConnectCouchDB parameters. --- src/leap/mx/couchdb.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index c020295..f63d2f0 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -31,7 +31,7 @@ class ConnectedCouchDB(client.CouchDB): CouchDB document for testing is '_design', and the view is simply a preconfigured set of mapped responses. """ - def __init__(self, host, port, dbName=None, username=None, + def __init__(self, host, port=5984, dbName=None, username=None, password=None, *args, **kwargs): """ Connect to a CouchDB instance. @@ -44,7 +44,8 @@ class ConnectedCouchDB(client.CouchDB): @returns: A :class:`twisted.internet.defer.Deferred` representing the the client connection to the CouchDB instance. """ - super(client.CouchDB, self).__init__(host, port, + super(client.CouchDB, self).__init__(host, + port=port, dbName=dbName, username=username, password=password, -- cgit v1.2.3 From 368f03896aaf88249805b5ae2484c67d8fe73d74 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:52:29 +0000 Subject: Update ConnectedCouchDB.__init__() docstring. --- src/leap/mx/couchdb.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index f63d2f0..e7aee8b 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -36,12 +36,12 @@ class ConnectedCouchDB(client.CouchDB): """ Connect to a CouchDB instance. - @param host: A hostname string for the CouchDB server. - @param port: The port of the CouchDB server, as an integer. - @param dbName: (optional) The default database to connect to. - @param username: (optional) The username for authorization. - @param password: (optional) The password for authorization. - @returns: A :class:`twisted.internet.defer.Deferred` representing the + :param str host: A hostname string for the CouchDB server. + :param int port: The port of the CouchDB server. + :param str dbName: (optional) The default database to bind queries to. + :param str username: (optional) The username for authorization. + :param str password: (optional) The password for authorization. + :returns: A :class:`twisted.internet.defer.Deferred` representing the the client connection to the CouchDB instance. """ super(client.CouchDB, self).__init__(host, -- cgit v1.2.3 From 9a166f7cd1247e022ca2f0b5685e927f3d0edfca Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:53:04 +0000 Subject: Remove duplicate call to bind database, it's in the super() call. --- src/leap/mx/couchdb.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index e7aee8b..826e83e 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -50,9 +50,7 @@ class ConnectedCouchDB(client.CouchDB): username=username, password=password, *args, **kwargs) - if dbName: - self.bindToDB(dbName) - else: + if dbName is None: databases = self.listDB() log.msg("Available databases: %s" % databases) -- cgit v1.2.3 From 6e97e1f509025569979153542aa2362bb7c2f413 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:53:39 +0000 Subject: Override parent CouchDB methods for database creation and deletion. --- src/leap/mx/couchdb.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index 826e83e..9b69091 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -54,6 +54,14 @@ class ConnectedCouchDB(client.CouchDB): databases = self.listDB() log.msg("Available databases: %s" % databases) + def createDB(self, dbName): + """Overrides ``paisley.client.CouchDB.createDB``.""" + pass + + def deleteDB(self, dbName): + """Overrides ``paisley.client.CouchDB.deleteDB``.""" + pass + def queryByEmailOrAlias(self, alias, dbDoc="User", view="by_email_or_alias"): """ -- cgit v1.2.3 From 5048af81ffea65f9abc8d9aae451a58f97e015fd Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:54:14 +0000 Subject: Update ConnectedCouchDB.queryByEmailOrAlias() docstring. --- src/leap/mx/couchdb.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index 9b69091..fb4d8f6 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -64,12 +64,11 @@ class ConnectedCouchDB(client.CouchDB): def queryByEmailOrAlias(self, alias, dbDoc="User", view="by_email_or_alias"): - """ - Check to see if a particular email or alias exists. + """Check to see if a particular email or alias exists. - @param alias: A string representing the email or alias to check. - @param dbDoc: The CouchDB document to open. - @param view: The view of the CouchDB document to use. + :param str alias: A string representing the email or alias to check. + :param str dbDoc: The CouchDB document to open. + :param str view: The view of the CouchDB document to use. """ assert isinstance(alias, str), "Email or alias queries must be string" -- cgit v1.2.3 From a0cdd89a1e74f61c263bd7ee4b214d823b8e3a7c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:54:54 +0000 Subject: Update ConnectedCouchDB.query() docstring. --- src/leap/mx/couchdb.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index fb4d8f6..fe46ac6 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -89,8 +89,10 @@ class ConnectedCouchDB(client.CouchDB): return d def query(self, uri): - """ - Query a CouchDB instance that we are connected to. + """Query a CouchDB instance that we are connected to. + + :param str uri: A particular URI in the CouchDB, i.e. + "/users/_design/User/_view/by_email_or_alias". """ try: self.checkURI(uri) ## xxx write checkURI() -- cgit v1.2.3 From 471c584b4fac9de68200f3b252292f1735f3d1a4 Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Mon, 15 Apr 2013 19:55:19 +0000 Subject: Update ConnectedCouchDB.listUsersAndEmails() docstring. --- src/leap/mx/couchdb.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/leap/mx/couchdb.py b/src/leap/mx/couchdb.py index fe46ac6..04cfc4d 100644 --- a/src/leap/mx/couchdb.py +++ b/src/leap/mx/couchdb.py @@ -109,12 +109,14 @@ class ConnectedCouchDB(client.CouchDB): @defer.inlineCallbacks def listUsersAndEmails(self, limit=1000, reverse=False): - """ - List all users and email addresses, up to the given limit. + """List all users and email addresses, up to the given limit. + + :param int limit: The number of results to limit the response to. + :param bool reverse: Start at the end of the database mapping. """ query = "/users/_design/User/_view/by_email_or_alias/?reduce=false" answer = yield self.query(query, limit=limit, reverse=reverse) - + if answer: parsed = yield self.parseResult(answer) if parsed: -- cgit v1.2.3