[or-cvs] r20803: {projects} Towards mail forwarding feature (in projects/gettor: . gettor)

kaner at seul.org kaner at seul.org
Sun Oct 18 14:02:17 UTC 2009


Author: kaner
Date: 2009-10-18 10:02:16 -0400 (Sun, 18 Oct 2009)
New Revision: 20803

Modified:
   projects/gettor/GetTor.py
   projects/gettor/gettor/config.py
   projects/gettor/gettor/constants.py
   projects/gettor/gettor/opt.py
   projects/gettor/gettor/requests.py
   projects/gettor/gettor/responses.py
   projects/gettor/gettor/utils.py
Log:
Towards mail forwarding feature


Modified: projects/gettor/GetTor.py
===================================================================
--- projects/gettor/GetTor.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/GetTor.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -36,9 +36,9 @@
     # Retrieve request from stdin
     try:
         request = gettor.requests.requestMail(conf)
-        replyTo, lang, pack, split, sig = request.parseMail()
-        log.info("Request from %s package %s, lang %s, split %s" \
-                    % (replyTo, pack, lang, split))
+        replyTo, lang, pack, split, sig, cmdAddr = request.parseMail()
+        log.info("Request from %s package %s, lang %s, split %s, cmdaddr %s" \
+                    % (replyTo, pack, lang, split, cmdAddr))
         log.info("Signature is %s" % sig)
     except Exception, e:
         log.error("Parsing the request failed.")
@@ -48,13 +48,15 @@
 
     # Ok, information aquired. Initiate reply sequence
     try:
-        reply = gettor.responses.Response(conf, replyTo, lang, pack, split, sig)
+        reply = gettor.responses.Response(conf, replyTo, lang, pack, split, \
+                                            sig, cmdAddr)
         reply.sendReply()
         return True
     except Exception, e:
         log.error("Sending the reply failed.")
         log.error("Here is the exception I saw: %s" % sys.exc_info()[0])
         log.error("Detail: %s" %e)
+        raise
         return False
 
 def processOptions(options, conf):
@@ -80,6 +82,10 @@
         gettor.utils.clearWhitelist(conf)
     if options.clearbl:
         gettor.utils.clearBlacklist(conf)
+    if options.cmdpass:
+        gettor.utils.setCmdPassword(conf, options.cmdpass)
+        test = "haha"
+        gettor.utils.verifyPassword(conf, test)
 
 def main():
     # Parse command line, setup config and logging

Modified: projects/gettor/gettor/config.py
===================================================================
--- projects/gettor/gettor/config.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/config.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -95,6 +95,7 @@
                         "logSubSystem": ("nothing",                 "global"),
                         "logFile":      ("/dev/null",               "global"),
                         "localeDir":    ("/usr/share/locale",       "global"),
+                        "cmdPassFile":  ("/var/lib/gettor/cmdpass", "global"),
                         "delayAlert":   (True,                    "global")}
 
         # One ConfigParser instance to read the actual values from config
@@ -171,6 +172,9 @@
     def getLocaleDir(self):
         return self.useConf["localeDir"][0]
 
+    def getCmdPassFile(self):
+        return self.useConf["cmdPassFile"][0]
+
     def getDelayAlert(self):
         return self.useConf["delayAlert"][0]
 

Modified: projects/gettor/gettor/constants.py
===================================================================
--- projects/gettor/gettor/constants.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/constants.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -15,7 +15,7 @@
 _ = gettext.gettext
 
 helpmsg = _("""
-    Hello! This is the "gettor" robot.
+    Hello! This is the "GetTor" robot.
 
     Unfortunately, we won't answer you at this address. You should make
     an account with GMAIL.COM or YAHOO.CN and send the mail from
@@ -37,7 +37,7 @@
         """)
 
 packagehelpmsg = _("""
-    Hello, This is the "gettor" robot.
+    Hello, This is the "GetTor" robot.
 
     I will mail you a Tor package, if you tell me which one you want.
     Please select one of the following package names:
@@ -60,7 +60,7 @@
         """)
 
 packagemsg = _("""
-    Hello! This is the "gettor" robot.
+    Hello! This is the "GetTor" robot.
 
     Here's your requested software as a zip file. Please unzip the
     package and verify the signature.
@@ -99,7 +99,7 @@
         """)
 
 splitpackagemsg = _("""
-    Hello! This is the "gettor" robot.
+    Hello! This is the "GetTor" robot.
 
     Here's your requested software as a zip file. Please unzip the
     package and verify the signature.
@@ -147,7 +147,7 @@
         """)
 
 delayalertmsg = _("""
-    Hello, This is the "gettor" robot.
+    Hello, This is the "GetTor" robot.
 
     Thank you for your request. It was successfully understood. Your request is
     currently being processed. Your package should arrive within the next ten

Modified: projects/gettor/gettor/opt.py
===================================================================
--- projects/gettor/gettor/opt.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/opt.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -58,6 +58,10 @@
     cmdParser.add_option("-r", "--install-translations", dest="insttrans",
                         action="store_true", default=False,
                         help="Compile and install translation files [check -d]")
+    cmdParser.add_option("-s", "--set-cmdpassword", dest="cmdpass",
+                        default="",
+                        help="Set the password for mail commands",
+                        metavar="CMDPASS")
     cmdParser.add_option("-d", "--i18n-dir", dest="i18ndir",
                         default="./i18n",
                         help="Set your locale src dir to DIR [default = %default]",

Modified: projects/gettor/gettor/requests.py
===================================================================
--- projects/gettor/gettor/requests.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/requests.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -36,6 +36,7 @@
         self.rawMessage = sys.stdin.read()
         self.parsedMessage = email.message_from_string(self.rawMessage)
         self.signature = False
+        self.config = config
         # TODO XXX:
         # This should catch DNS exceptions and fail to verify if we have a 
         # dns timeout
@@ -53,9 +54,11 @@
         # If no package name could be recognized, use 'None'
         self.returnPackage = None
         self.splitDelivery = False
+        self.commandaddress = None
         self.replyLocale = "en"
         packager = gettor.packages.Packages(config)
         self.packages = packager.getPackageList()
+        assert len(self.packages) > 0, "Empty package list"
 
     def parseMail(self):
         # Parse line by line
@@ -71,6 +74,7 @@
                 if match: 
                     self.returnPackage = package
                     log.info("User requested package %s" % self.returnPackage)
+                    break
             # If we find 'split' somewhere in the mail, we assume that the user 
             # wants a split delivery
             match = re.match(".*split.*", line)
@@ -82,7 +86,25 @@
             if match:
                 self.replyLocale = match.group(1)
                 log.info("User requested locale %s" % self.replyLocale)
+            # Check if this is a command
+            match = re.match(".*[Cc]ommand:\s+(.*)$", line)
+            if match:
+                log.info("Command received from %s" % self.replytoAddress) 
+                cmd = match.group(1).split()
+                length = len(cmd)
+                assert length == 3, "Wrong command syntax"
+                auth = cmd[0]
+                # Package is parsed by the usual package parsing mechanism
+                package = cmd[1]
+                address = cmd[2]
+                verified = gettor.utils.verifyPassword(self.config, auth)
+                assert verified == True, \
+                        "Unauthorized attempt to command from: %s" \
+                        % self.replytoAddress
+                self.commandaddress = address
 
+        if self.returnPackage is None:
+            log.info("User didn't select any packages")
         # Actually use a map here later XXX
         for (key, lang) in self.supportedLangs.items():
             if self.replyLocale == key:
@@ -92,8 +114,8 @@
                         % (self.replyLocale, self.defaultLang))
             self.replyLocale = self.defaultLang
 
-        return (self.replytoAddress, self.replyLocale, \
-                self.returnPackage, self.splitDelivery, self.signature)
+        return (self.replytoAddress, self.replyLocale, self.returnPackage, \
+                self.splitDelivery, self.signature, self.commandaddress)
 
     def getRawMessage(self):
         return self.rawMessage

Modified: projects/gettor/gettor/responses.py
===================================================================
--- projects/gettor/gettor/responses.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/responses.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -29,18 +29,22 @@
 
 class Response:
 
-    def __init__(self, config, replyto, lang, package, split, signature):
+    def __init__(self, config, replyto, lang, package, split, signature, caddr):
         self.config = config
         self.srcEmail = "GetTor <gettor at torproject.org>"
         self.replyTo = replyto
-        if self.replyTo is None:
-            log.error("Empty replyto address.")
-            # XXX Raise something self-defined
-            raise Exception("Empty reply to address")
+        assert self.replyTo is not None, "Empty replyto address."
         self.mailLang = lang
         self.package = package
         self.splitsend = split
         self.signature = signature
+        self.cmdAddr = caddr
+        # If cmdAddr is set, we are forwarding mail rather than sending a 
+        # reply to someone
+        if self.cmdAddr is not None:
+            self.sendTo = self.cmdAddr
+        else:
+            self.sendTo = self.replyTo
         self.whiteList = gettor.blacklist.BWList(config.getWlStateDir())
         self.blackList = gettor.blacklist.BWList(config.getBlStateDir())
         try:
@@ -53,7 +57,7 @@
     def sendReply(self):
         """All routing decisions take place here."""
         # Check we're happy with sending this user a package
-        if not self.signature \
+        if not self.signature and not self.cmdAddr \
            and not self.whiteList.lookupListEntry(self.replyTo) \
            and not re.compile(".*@yahoo.com.cn").match(self.replyTo) \
            and not re.compile(".*@yahoo.cn").match(self.replyTo) \
@@ -68,6 +72,12 @@
                 log.info("Unsigned messaged to gettor. We will issue help.")
                 return self.sendHelp()
         else:
+            if self.cmdAddr is not None:
+                success = self.sendPackage()
+                if not success:
+                    log.error("Failed to forward mail to '%s'" % self.cmdAddr)
+                return self.sendForwardReply(success)
+                
             if self.package is None:
                 return self.sendPackageHelp()
             delayAlert = self.config.getDelayAlert()
@@ -82,7 +92,7 @@
 
     def sendPackage(self):
         """ Send a message with an attachment to the user"""
-        log.info("Sending out %s to %s." % (self.package, self.replyTo))
+        log.info("Sending out %s to %s." % (self.package, self.sendTo))
         packages = gettor.packages.Packages(self.config)
         packageList = packages.getPackageList()
         filename = packageList[self.package]
@@ -128,12 +138,12 @@
 
     def sendDelayAlert(self):
         """ Send a delay notification """
-        log.info("Sending delay alert to %s" % self.replyTo)
+        log.info("Sending delay alert to %s" % self.sendTo)
         return self.sendGenericMessage(gettor.constants.delayalertmsg)
             
     def sendHelp(self):
         """ Send a helpful message to the user interacting with us """
-        log.info("Sending out help message to %s" % self.replyTo)
+        log.info("Sending out help message to %s" % self.sendTo)
         return self.sendGenericMessage(gettor.constants.helpmsg)
 
 ## XXX the following line was used below to automatically list the names
@@ -145,16 +155,24 @@
 
     def sendPackageHelp(self):
         """ Send a helpful message to the user interacting with us """
-        log.info("Sending package help to %s" % self.replyTo)
+        log.info("Sending package help to %s" % self.sendTo)
         return self.sendGenericMessage(gettor.constants.packagehelpmsg)
 
+    def sendForwardReply(self, status):
+        " Send a message to the user that issued the forward command """
+        log.info("Sending reply to forwarder '%s'" % self.replyTo)
+        message = "Forwarding mail to '%s' status: %s" % (self.sendTo, status)
+        # Magic: We're now returning to the original issuer
+        self.sendTo = self.replyTo
+        return self.sendGenericMessage(message)
+
     def sendGenericMessage(self, text):
         """ Send a message of some sort """
         message = self.constructMessage(text, "")
         try:
             status = self.sendMessage(message)
         except:
-            log.error("Could not send message to user %s" % self.replyTo)
+            log.error("Could not send message to user %s" % self.sendTo)
             status = False
 
         log.info("Send status: %s" % status)
@@ -170,7 +188,7 @@
         mime = MimeWriter.MimeWriter(message)
         mime.addheader('MIME-Version', '1.0')
         mime.addheader('Subject', subj)
-        mime.addheader('To', self.replyTo)
+        mime.addheader('To', self.sendTo)
         mime.addheader('From', self.srcEmail)
         mime.startmultipartbody('mixed')
 
@@ -192,7 +210,7 @@
     def sendMessage(self, message, smtpserver="localhost:25"):
         try:
             smtp = smtplib.SMTP(smtpserver)
-            smtp.sendmail(self.srcEmail, self.replyTo, message.getvalue())
+            smtp.sendmail(self.srcEmail, self.sendTo, message.getvalue())
             smtp.quit()
             status = True
         except smtplib.SMTPAuthenticationError:

Modified: projects/gettor/gettor/utils.py
===================================================================
--- projects/gettor/gettor/utils.py	2009-10-18 12:18:44 UTC (rev 20802)
+++ projects/gettor/gettor/utils.py	2009-10-18 14:02:16 UTC (rev 20803)
@@ -13,6 +13,7 @@
 
 import os
 import subprocess
+import hashlib
 
 import gettor.gtlog
 import gettor.blacklist
@@ -205,6 +206,36 @@
         log.info("Deleting blacklist done.")
         return True
 
+def setCmdPassword(conf, password):
+    log.info("Setting command password")
+    passwordHash = str(hashlib.sha1(password).hexdigest())
+    cmdPassFile = conf.getCmdPassFile()
+    try:
+        fd = open(cmdPassFile, 'w')
+        fd.write(passwordHash)
+        fd.close
+        return True
+    except Exception, e:
+        log.error("Creating list entry %s failed: %s" % (entry, e))
+        return False
+
+def verifyPassword(conf, password):
+    candidateHash = str(hashlib.sha1(password).hexdigest())
+    cmdPassFile = conf.getCmdPassFile()
+    try:
+        fd = open(cmdPassFile, 'r')
+        passwordHash = fd.read()
+        fd.close
+        if candidateHash == passwordHash:
+            log.info("Verification succeeded")
+            return True
+        else:
+            log.info("Verification failed")
+            return False
+    except Exception, e:
+        log.error("Verifying password failed: %s" % e)
+        return False
+
 # Helper routines go here ####################################################
 
 def installMo(poFile, targetDir):



More information about the tor-commits mailing list