From 37672d4caf1d2a0907732d1df257b13f0fdfd4a5 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Fri, 4 Dec 2015 15:10:45 -0400 Subject: [bug] skip fingerprint-map section for watching too --- pkg/mx.tac | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/mx.tac b/pkg/mx.tac index 6f7b104..4ae08f2 100755 --- a/pkg/mx.tac +++ b/pkg/mx.tac @@ -82,7 +82,8 @@ check_recipient.setServiceParent(application) # Mail receiver directories = [] for section in config.sections(): - if section in ("couchdb", "alias map", "check recipient", "bounce"): + if section in ("couchdb", "alias map", "check recipient", + "fingerprint map", "bounce"): continue to_watch = config.get(section, "path") recursive = config.getboolean(section, "recursive") -- cgit v1.2.3 From 66e3bda092a81176fc7d553d744ad36e5b825e56 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Fri, 4 Dec 2015 14:31:19 -0400 Subject: [pkg] fix outdated tac file path --- pkg/leap-mx.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/leap-mx.init b/pkg/leap-mx.init index 3878bce..8093c22 100644 --- a/pkg/leap-mx.init +++ b/pkg/leap-mx.init @@ -12,7 +12,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin PIDFILE=/var/run/leap_mx.pid RUNDIR=/var/lib/leap_mx/ -FILE=/usr/share/app/leap_mx.tac +FILE=/usr/share/app/mx.tac TWISTD_PATH=/usr/bin/twistd USER=leap-mx GROUP=leap-mx -- cgit v1.2.3 From 3360cc70b7752f6ebedb56cb8ffc01b81cd640d6 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Tue, 8 Dec 2015 08:51:13 -0400 Subject: [pkg] bump soledad-common dependency needed because the ServerDocument refactor - Releases: 0.8.0 --- pkg/requirements-leap.pip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/requirements-leap.pip b/pkg/requirements-leap.pip index 482d1e2..23ebb69 100644 --- a/pkg/requirements-leap.pip +++ b/pkg/requirements-leap.pip @@ -1,3 +1,3 @@ leap.common>=0.3.5 -leap.soledad.common>=0.4.5 +leap.soledad.common>=0.8.0 leap.keymanager>=0.3.4 -- cgit v1.2.3 From 8fc1258ace65be2bb828bf302fc0661cdd128bd7 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Wed, 18 Nov 2015 00:27:56 +0100 Subject: [feat] postfix lookup against couchdb for client smtp fingerprint - Resolves: #4285 --- changes/next-changelog.txt | 1 + doc/DESIGN.md | 13 +++++ pkg/mx.conf.sample | 3 ++ pkg/mx.tac | 8 +++ src/leap/mx/couchdbhelper.py | 28 +++++++++++ src/leap/mx/fingerprint_resolver.py | 98 +++++++++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+) create mode 100644 src/leap/mx/fingerprint_resolver.py diff --git a/changes/next-changelog.txt b/changes/next-changelog.txt index fbee095..641e26c 100644 --- a/changes/next-changelog.txt +++ b/changes/next-changelog.txt @@ -10,6 +10,7 @@ I've added a new category `Misc` so we can track doc/style/packaging stuff. Features ~~~~~~~~ +- `#4285 `_: Add postfix lookup against couchdb for client smtp fingerprint - `#5959 `_: Make alias resolver to return *uuid@deliver.local* - `#1234 `_: Description of the new feature corresponding with issue #1234. - New feature without related issue number. diff --git a/doc/DESIGN.md b/doc/DESIGN.md index e33c6ae..dbfbc99 100644 --- a/doc/DESIGN.md +++ b/doc/DESIGN.md @@ -145,6 +145,19 @@ virtual transport instead, we should append the domain (eg 123456@example.org). see http://www.postfix.org/ADDRESS_REWRITING_README.html#resolve +#### fingerprint_resolver + +postfix config: + +``` +virtual_alias_map tcp:localhost:2424 +``` + +postfix sends "get 12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef:12:34:56:78" +providing an smtp fingerprint and fingerprint_resolver returns "200 2016-01-19", +where 2016-01-19 is the expiration date of the given fingerprint. If the +fingerprint does not exists or is expired it will return "500 NOT FOUND SRY". + #### Return values The return codes and content of the tcp maps are: diff --git a/pkg/mx.conf.sample b/pkg/mx.conf.sample index c9ad0f8..a649b73 100644 --- a/pkg/mx.conf.sample +++ b/pkg/mx.conf.sample @@ -14,6 +14,9 @@ port=4242 [check recipient] port=2244 +[fingerprint map] +port=2424 + [bounce] from=
subject=Delivery failure \ No newline at end of file diff --git a/pkg/mx.tac b/pkg/mx.tac index 4ae08f2..42d40a8 100755 --- a/pkg/mx.tac +++ b/pkg/mx.tac @@ -24,6 +24,7 @@ from leap.mx import couchdbhelper from leap.mx.mail_receiver import MailReceiver from leap.mx.alias_resolver import AliasResolverFactory from leap.mx.check_recipient_access import CheckRecipientAccessFactory +from leap.mx.fingerprint_resolver import FingerprintResolverFactory try: from twisted.application import service, internet @@ -57,6 +58,7 @@ except ConfigParser.NoSectionError: alias_port = config.getint("alias map", "port") check_recipient_port = config.getint("check recipient", "port") +fingerprint_port = config.getint("fingerprint map", "port") cdb = couchdbhelper.ConnectedCouchDB(server, port=port, @@ -79,6 +81,12 @@ check_recipient = internet.TCPServer( interface="localhost") check_recipient.setServiceParent(application) +# Fingerprint map +fingerprint_map = internet.TCPServer( + fingerprint_port, FingerprintResolverFactory(couchdb=cdb), + interface="localhost") +fingerprint_map.setServiceParent(application) + # Mail receiver directories = [] for section in config.sections(): diff --git a/src/leap/mx/couchdbhelper.py b/src/leap/mx/couchdbhelper.py index 115ecbe..de133d5 100644 --- a/src/leap/mx/couchdbhelper.py +++ b/src/leap/mx/couchdbhelper.py @@ -138,6 +138,34 @@ class ConnectedCouchDB(client.CouchDB): d.addCallbacks(_get_pubkey_cbk, log.err) return d + def getCertExpiry(self, fingerprint): + """ + Query couch and return a deferred that will fire with the expiration + date for the cert with the given fingerprint. + + :param fingerprint: The cert fingerprint + :type fingerprint: str + + :return: A deferred that will fire with the cert expiration date as a + str. + :rtype: Deferred + """ + d = self.openView(docId="Identity", + viewId="cert_expiry_by_fingerprint/", + key=fingerprint, + reduce=False, + include_docs=True) + + def _get_cert_expiry_cbk(result): + try: + expiry = result["rows"][0]["value"] + except (KeyError, IndexError): + expiry = None + return expiry + + d.addCallback(_get_cert_expiry_cbk) + return d + def put_doc(self, uuid, doc): """ Update a document. diff --git a/src/leap/mx/fingerprint_resolver.py b/src/leap/mx/fingerprint_resolver.py new file mode 100644 index 0000000..0a0850d --- /dev/null +++ b/src/leap/mx/fingerprint_resolver.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# fingerprint_resolver.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 . + +""" +Classes for resolve expiration date of certs. + +Test this with postmap -v -q "fingerprint" tcp:localhost:2424 +""" + + +from datetime import datetime +from twisted.internet.protocol import ServerFactory +from twisted.protocols import postfix +from twisted.python import log + +from leap.mx.tcp_map import TCP_MAP_CODE_SUCCESS +from leap.mx.tcp_map import TCP_MAP_CODE_PERMANENT_FAILURE + + +class LEAPPostfixTCPMapFingerprintServer(postfix.PostfixTCPMapServer): + """ + A postfix tcp map fingerprint resolver server. + """ + + def _cbGot(self, res): + """ + Return a code and message depending on the result of the factory's + get(). + + :param res: The fingerprint and expiration date of the cert + :type res: (str, str) + """ + fingerprint, expiry = (None, None) + if res is not None: + fingerprint, expiry = res + + if expiry is None: + code = TCP_MAP_CODE_PERMANENT_FAILURE + msg = "NOT FOUND SRY" + elif expiry < datetime.utcnow().strftime("%Y-%m-%d"): + code = TCP_MAP_CODE_PERMANENT_FAILURE + msg = "EXPIRED CERT" + else: + # properly encode expiry, otherwise twisted complains when replying + if isinstance(expiry, unicode): + expiry = expiry.encode("utf8") + code = TCP_MAP_CODE_SUCCESS + msg = fingerprint + " " + expiry + + self.sendCode(code, postfix.quote(msg)) + + +class FingerprintResolverFactory(ServerFactory, object): + """ + A factory for postfix tcp map fingerprint resolver servers. + """ + + protocol = LEAPPostfixTCPMapFingerprintServer + + def __init__(self, couchdb): + """ + Initialize the factory. + + :param couchdb: A CouchDB client. + :type couchdb: leap.mx.couchdbhelper.ConnectedCouchDB + """ + self._cdb = couchdb + + def get(self, fingerprint): + """ + Look up the cert expiration date based on fingerprint. + + :param fingerprint: The cert fingerprint. + :type fingerprint: str + + :return: A deferred that will be fired with the expiration date. + :rtype: Deferred + """ + log.msg("look up: %s" % (fingerprint,)) + d = self._cdb.getCertExpiry(fingerprint.lower()) + d.addCallback(lambda expiry: (fingerprint, expiry)) + d.addErrback(log.err) + return d -- cgit v1.2.3 From b26643ea9848869ece6ead2ba6c0991333d3c6f4 Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Wed, 25 Nov 2015 19:15:33 +0100 Subject: [feat] use the original message for encryption Do not reconstruct the message from the parsed one. Added test for missleading encoding. - Resolves: #7253 --- changes/next-changelog.txt | 1 + src/leap/mx/mail_receiver.py | 9 +++------ src/leap/mx/tests/test_mail_receiver.py | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/changes/next-changelog.txt b/changes/next-changelog.txt index 641e26c..0e3da74 100644 --- a/changes/next-changelog.txt +++ b/changes/next-changelog.txt @@ -17,6 +17,7 @@ Features Bugfixes ~~~~~~~~ +- `#7253 `_: Use the original message for encryption. - `#1235 `_: Description for the fixed stuff corresponding with issue #1235. - Bugfix without related issue number. diff --git a/src/leap/mx/mail_receiver.py b/src/leap/mx/mail_receiver.py index ea13658..4d82849 100644 --- a/src/leap/mx/mail_receiver.py +++ b/src/leap/mx/mail_receiver.py @@ -166,7 +166,7 @@ class MailReceiver(Service): :param pubkey: public key for the owner of the message :type pubkey: str :param message: message contents - :type message: email.message.Message + :type message: str :return: doc to sync with Soledad or None, None if something went wrong. @@ -177,13 +177,10 @@ class MailReceiver(Service): "I know: %r" % (pubkey,)) return None - # find message's encoding - message_as_string = message.as_string() - doc = ServerDocument(doc_id=str(pyuuid.uuid4())) # store plain text if pubkey is not available - data = {'incoming': True, 'content': message_as_string} + data = {'incoming': True, 'content': message} if pubkey is None or len(pubkey) == 0: doc.content = { self.INCOMING_KEY: True, @@ -385,7 +382,7 @@ class MailReceiver(Service): defer.returnValue(None) log.msg("Encrypting message to %s's pubkey" % (uuid,)) - doc = yield self._encrypt_message(pubkey, msg) + doc = yield self._encrypt_message(pubkey, mail_data) yield self._export_message(uuid, doc) yield self._remove(filepath) diff --git a/src/leap/mx/tests/test_mail_receiver.py b/src/leap/mx/tests/test_mail_receiver.py index e72cb1a..33967ea 100644 --- a/src/leap/mx/tests/test_mail_receiver.py +++ b/src/leap/mx/tests/test_mail_receiver.py @@ -19,6 +19,7 @@ MailReceiver tests """ +import codecs import json import os import os.path @@ -97,14 +98,27 @@ class MailReceiverTestCase(unittest.TestCase): yield defer_called self.assertTrue(os.path.exists(path)) + @defer.inlineCallbacks + def test_misleading_encoding(self): + msg, path = self.addMail( + "ñáûä", headers={'Content-Transfer-Encoding': '7Bit'}) + uuid, doc = yield self.defer_put_doc + self.assertEqual(uuid, UUID) + decmsg = self.decryptDoc(doc) + self.assertEqual(unicode(msg, "utf-8"), decmsg) + self.assertFalse(os.path.exists(path)) + def addMail(self, body="", filename="foo", to=ADDRESS, - frm="someone@domain.org", subject="sent subject"): + frm="someone@domain.org", subject="sent subject", + headers={}): msg = Message() msg.add_header("To", to) msg.add_header( "Delivered-To", UUID + "@deliver.local") msg.add_header("From", frm) msg.add_header("Subject", subject) + for header, value in headers.iteritems(): + msg.add_header(header, value) msg.set_payload(body) path = os.path.join(self.directory, "new", filename) -- cgit v1.2.3 From c944cb877313fec9841c731b1ce4c4a16fb4d5f0 Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Thu, 10 Dec 2015 03:27:49 -0400 Subject: ignore .eggs folder --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 523c9d2..173cac5 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ dist build eggs +.eggs parts bin var -- cgit v1.2.3