From b5309dc5910f35f5320c649be2ce2c6147030b39 Mon Sep 17 00:00:00 2001 From: drebs Date: Wed, 25 Mar 2015 15:47:28 -0300 Subject: [refactor] separate tcp map server code Separate the common tcp map server code, used for both alias resolver and recipient access checker, to its own file. --- src/leap/mx/alias_resolver.py | 84 ++++++++++++++--------------------- src/leap/mx/check_recipient_access.py | 40 ++++++++++++----- src/leap/mx/tcp_map.py | 76 +++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 60 deletions(-) create mode 100644 src/leap/mx/tcp_map.py (limited to 'src') diff --git a/src/leap/mx/alias_resolver.py b/src/leap/mx/alias_resolver.py index 4247b57..9206ffb 100644 --- a/src/leap/mx/alias_resolver.py +++ b/src/leap/mx/alias_resolver.py @@ -24,65 +24,49 @@ Test this with postmap -v -q "foo" tcp:localhost:4242 TODO: o Look into using twisted.protocols.postfix.policies classes for controlling concurrent connections and throttling resource consumption. + o We should probably use twisted.mail.alias somehow. """ -try: - # TODO: we should probably use the system alias somehow - # from twisted.mail import alias - from twisted.protocols import postfix - from twisted.python import log - from twisted.internet import defer - from twisted.internet.protocol import ServerFactory -except ImportError: - print "This software requires Twisted. Please see the README file" - print "for instructions on getting required dependencies." +from twisted.protocols import postfix -class LEAPPostFixTCPMapserver(postfix.PostfixTCPMapServer): - def _cbGot(self, value): - uuid, pubkey = value - if uuid is None: - self.sendCode(500, postfix.quote("NOT FOUND SRY")) - elif pubkey is None: - self.sendCode(400, postfix.quote("4.7.13 USER ACCOUNT DISABLED")) - else: - self.sendCode(200, postfix.quote(value)) - +from leap.mx.tcp_map import LEAPostfixTCPMapServerFactory +from leap.mx.tcp_map import TCP_MAP_CODE_SUCCESS +from leap.mx.tcp_map import TCP_MAP_CODE_TEMPORARY_FAILURE +from leap.mx.tcp_map import TCP_MAP_CODE_PERMANENT_FAILURE -class AliasResolverFactory(ServerFactory): - protocol = LEAPPostFixTCPMapserver +class LEAPPostfixTCPMapAliasServer(postfix.PostfixTCPMapServer): + """ + A postfix tcp map alias resolver server. + """ - def __init__(self, couchdb): - self._cdb = couchdb - - def _to_str(self, result): - """ - Properly encodes the result string if any. + def _cbGot(self, value): """ - if isinstance(result, unicode): - result = result.encode("utf8") - if result is None: - log.msg("Result not found") - return result + Return a code and message depending on the result of the factory's + get(). - def _getPubKey(self, uuid): + :param value: The uuid and public key. + :type value: list + """ + uuid, pubkey = value if uuid is None: - return defer.succeed([None, None]) - d = defer.gatherResults([ - self._to_str(uuid), - self._cdb.getPubKey(uuid), - ]) - return d + self.sendCode( + TCP_MAP_CODE_PERMANENT_FAILURE, + postfix.quote("NOT FOUND SRY")) + elif pubkey is None: + self.sendCode( + TCP_MAP_CODE_TEMPORARY_FAILURE, + postfix.quote("4.7.13 USER ACCOUNT DISABLED")) + else: + self.sendCode( + TCP_MAP_CODE_SUCCESS, + postfix.quote(uuid)) - def get(self, key): - """ - Looks up the passed key, but only up to the username id of the key. - At some point we will have to consider the domain part too. - """ - log.msg("Query key: %s" % (key,)) - d = self._cdb.queryByAddress(key) - d.addCallback(self._getPubKey) - d.addErrback(log.err) - return d +class AliasResolverFactory(LEAPostfixTCPMapServerFactory): + """ + A factory for postfix tcp map alias resolver servers. + """ + + protocol = LEAPPostfixTCPMapAliasServer diff --git a/src/leap/mx/check_recipient_access.py b/src/leap/mx/check_recipient_access.py index d4ae339..cf172c7 100644 --- a/src/leap/mx/check_recipient_access.py +++ b/src/leap/mx/check_recipient_access.py @@ -24,22 +24,42 @@ Test this with postmap -v -q "foo" tcp:localhost:2244 from twisted.protocols import postfix -from leap.mx.alias_resolver import AliasResolverFactory +from leap.mx.tcp_map import LEAPPostfixTCPMapServerFactory +from leap.mx.tcp_map import TCP_MAP_CODE_SUCCESS +from leap.mx.tcp_map import TCP_MAP_CODE_TEMPORARY_FAILURE +from leap.mx.tcp_map import TCP_MAP_CODE_PERMANENT_FAILURE -class LEAPPostFixTCPMapserverAccess(postfix.PostfixTCPMapServer): +class LEAPPostFixTCPMapAccessServer(postfix.PostfixTCPMapServer): + """ + A postfix tcp map recipient access checker server. + """ + def _cbGot(self, value): - # For more info, see: - # http://www.postfix.org/tcp_table.5.html - # http://www.postfix.org/access.5.html + """ + Return a code and message depending on the result of the factory's + get(). + + For more info, see: http://www.postfix.org/access.5.html + + :param value: The uuid and public key. + :type value: list + """ uuid, pubkey = value if uuid is None: - self.sendCode(500, postfix.quote("REJECT")) + self.sendCode( + TCP_MAP_CODE_PERMANENT_FAILURE, + postfix.quote("REJECT")) elif pubkey is None: - self.sendCode(400, postfix.quote("4.7.13 USER ACCOUNT DISABLED")) + self.sendCode( + TCP_MAP_CODE_TEMPORARY_FAILURE, + postfix.quote("4.7.13 USER ACCOUNT DISABLED")) else: - self.sendCode(200, postfix.quote("OK")) + self.sendCode( + TCP_MAP_CODE_SUCCESS, + postfix.quote("OK")) + +class CheckRecipientAccessFactory(LEAPPostfixTCPMapServerFactory): -class CheckRecipientAccessFactory(AliasResolverFactory): - protocol = LEAPPostFixTCPMapserverAccess + protocol = LEAPPostFixTCPMapAccessServer diff --git a/src/leap/mx/tcp_map.py b/src/leap/mx/tcp_map.py new file mode 100644 index 0000000..b7066ff --- /dev/null +++ b/src/leap/mx/tcp_map.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# tcpmap.py +# Copyright (C) 2015 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 . + + +from twisted.python import log +from twisted.internet import defer +from twisted.internet.protocol import ServerFactory + + +# For info on codes, see: http://www.postfix.org/tcp_table.5.html +TCP_MAP_CODE_SUCCESS = 200 +TCP_MAP_CODE_TEMPORARY_FAILURE = 400 +TCP_MAP_CODE_PERMANENT_FAILURE = 500 + + +class LEAPPostfixTCPMapServerFactory(ServerFactory): + """ + A factory for postfix tcp map servers. + """ + + def __init__(self, couchdb): + """ + Initialize the factory. + + :param couchdb: A CouchDB client. + :type couchdb: leap.mx.couchdbhelper.ConnectedCouchDB + """ + self._cdb = couchdb + + def _getPubKey(self, uuid): + """ + Look up PGP public key based on user uid. + + :param uuid: The user uid. + :type uuid: str + + :return: A deferred that is fired with the uuid and the public key, if + available. + :rtype: DeferredList + """ + if uuid is None: + return defer.succeed([None, None]) + return defer.gatherResults([ + defer.succeed(uuid), + self._cdb.getPubKey(uuid), + ]) + + 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. + + :param key: The lookup key. + :type key: str + """ + log.msg("Query key: %s" % (key,)) + d = self._cdb.queryByAddress(key) + d.addCallback(self._getPubKey) + d.addErrback(log.err) + return d -- cgit v1.2.3