[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r20886: {projects} Move more stuff around (in projects/gettor: . lib lib/gettor)
Author: kaner
Date: 2009-11-01 06:50:51 -0500 (Sun, 01 Nov 2009)
New Revision: 20886
Added:
projects/gettor/MANIFEST.in
projects/gettor/lib/gettor/
projects/gettor/lib/gettor/__init__.py
projects/gettor/lib/gettor/blacklist.py
projects/gettor/lib/gettor/config.py
projects/gettor/lib/gettor/constants.py
projects/gettor/lib/gettor/gtlog.py
projects/gettor/lib/gettor/opt.py
projects/gettor/lib/gettor/packages.py
projects/gettor/lib/gettor/requests.py
projects/gettor/lib/gettor/responses.py
projects/gettor/lib/gettor/utils.py
projects/gettor/setup.cfg
Removed:
projects/gettor/MANIFEST
projects/gettor/gettor/
Modified:
projects/gettor/setup.py
Log:
Move more stuff around
Deleted: projects/gettor/MANIFEST
===================================================================
--- projects/gettor/MANIFEST 2009-11-01 11:45:23 UTC (rev 20885)
+++ projects/gettor/MANIFEST 2009-11-01 11:50:51 UTC (rev 20886)
@@ -1,17 +0,0 @@
-LICENSE
-README
-TODO
-i18n/de/gettor_de.po
-i18n/en/gettor_en.po
-GetTor.py
-gettor/config.py
-gettor/packages.py
-gettor/responses.py
-gettor/opt.py
-gettor/requests.py
-gettor/__init__.py
-gettor/gtlog.py
-gettor/blacklist.py
-sample-emails/positive-DKIM-header.eml
-sample-emails/negative-DKIM-header.eml
-sample-emails/negative-DKIM-header-package-sample.eml
Copied: projects/gettor/MANIFEST.in (from rev 20885, projects/gettor/MANIFEST)
===================================================================
--- projects/gettor/MANIFEST.in (rev 0)
+++ projects/gettor/MANIFEST.in 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1 @@
+include README TODO
Copied: projects/gettor/lib/gettor/__init__.py (from rev 20885, projects/gettor/gettor/__init__.py)
===================================================================
--- projects/gettor/lib/gettor/__init__.py (rev 0)
+++ projects/gettor/lib/gettor/__init__.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1 @@
+# :)
Copied: projects/gettor/lib/gettor/blacklist.py (from rev 20885, projects/gettor/gettor/blacklist.py)
===================================================================
--- projects/gettor/lib/gettor/blacklist.py (rev 0)
+++ projects/gettor/lib/gettor/blacklist.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,104 @@
+#!/usr/bin/python2.5
+"""This library implements all of the black listing features needed for gettor.
+Basically, it offers creation, removal and lookup of email addresses stored as
+SHA1 hashes in a dedicated directory on the filesystem.
+"""
+
+import hashlib
+import os
+import re
+import gettor.config
+import gettor.gtlog
+
+log = gettor.gtlog.getLogger()
+
+conf = gettor.config.Config()
+stateDir = conf.getStateDir()
+blStateDir = conf.getBlStateDir()
+
+# XXX
+def createDir(path):
+ try:
+ log.info("Creating directory %s.." % path)
+ os.makedirs(path)
+ except OSError, e:
+ log.error("Failed to create directory %s: %s" % (path, e))
+ return False
+ return True
+
+class BWList:
+ def __init__(self, listdir):
+ self.listDir = listdir
+ if not os.path.isdir(self.listDir):
+ if not createDir(self.listDir):
+ # XXX Change this to something more appropriate
+ raise IOError("Bad dir: %s" % self.listDir)
+
+ def lookupListEntry(self, address):
+ """Check to see if we have a list entry for the given address."""
+ if address is None:
+ log.error("Argument 'address' is None")
+ return False
+ emailonly = self.stripEmail(address)
+ entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
+ try:
+ entry = os.stat(entry)
+ except OSError:
+ return False
+ return True
+
+ def createListEntry(self, address):
+ """ Create a black- or whitelist entry """
+ if address is None:
+ log.error("Argument 'address' is None")
+ return False
+ emailonly = self.stripEmail(address)
+ entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
+ if self.lookupListEntry(address) == False:
+ try:
+ fd = open(entry, 'w')
+ fd.close
+ return True
+ except:
+ log.error("Creating list entry %s failed." % entry)
+ return False
+ else:
+ # List entry already exists
+ return False
+
+ def removeListEntry(self, address):
+ """ Remove an entry from the black- or whitelist """
+ if address is None:
+ log.error("Argument 'address' is None")
+ return False
+ emailonly = self.stripEmail(address)
+ entry = self.listDir + "/" + str(hashlib.sha1(emailonly).hexdigest())
+ if (self.lookupListEntry(address) == True):
+ try:
+ os.unlink(entry)
+ except OSError:
+ log.error("Could not unlink entry %s" % entry)
+ return False
+ else:
+ log.info("Requested removal of non-existing entry %s. Abord."
+ % entry)
+ return False
+
+ def removeAll(self):
+ print "Removing all entries from list!"
+ for root, dirs, files in os.walk(self.listDir):
+ for file in files:
+ try:
+ rmfile = os.path.join(root, file)
+ os.remove(rmfile)
+ except:
+ log.error("Could not remove %s." % rmfile)
+ return False
+ return True
+
+ def stripEmail(self, address):
+ '''Strip "Bart Foobar <bart@xxxxxxxxxx>" to "<bart@xxxxxxxxxx">'''
+ match = re.search('<.*?>', address)
+ if match is not None:
+ return match.group()
+ return address
Copied: projects/gettor/lib/gettor/config.py (from rev 20885, projects/gettor/gettor/config.py)
===================================================================
--- projects/gettor/lib/gettor/config.py (rev 0)
+++ projects/gettor/lib/gettor/config.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,184 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ gettor_config.py - Parse configuration file for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+
+ We grab configurable values from the users' gettor config file. If that file
+ is not present, we will supply reasonable defaults. Config files are ini-style
+ formatted. We know this is ugly, but we prefer it to XML and also ConfigParser
+ seems handy. ;-)
+
+ A valid config file should look like this:
+
+ [global]
+ stateDir = /var/lib/gettor/
+ blStateDir = /var/lib/gettor/bl/
+ distDir = /var/lib/gettor/pkg/
+ srcEmail = gettor@xxxxxxx
+ locale = en
+ logSubSystem = nothing
+ logFile = /dev/null
+ localeDir = /usr/share/locale
+ delayAlert = True
+
+ Note that you can set from none to any of these values in your config file.
+ Values you dont provide will be taken from the defaults in 'useConf'.
+
+ Here is what each of them is used for individually:
+
+ blStateDir: Blacklisted (hashed) email addresses go here
+ wlStateDir: Whitelisted (hashed) email addresses go here
+ distDir: Sent-out Tor packages are found here
+ srcEmail: The email containing the Tor package will use this as 'From:'
+ locale: Choose your default mail and log locale
+ logFile: If 'file' logging is chosen, log to this file
+ logSubSystem: This has to be one of the following strings:
+ 'nothing': Nothing is logged anywhere (Recommended)
+ 'stdout': Log to stdout
+ 'syslog': Logmessages will be written to syslog
+ 'file': Logmessages will be written to a file (Not that
+ this needs the 'logFile' option in the config file
+ also set to something useful
+ localeDir: This is where the 'en/LC_MESSAGES/gettor.mo' or
+ 'whateverlang/LC_MESSAGES/gettor.mo' should go
+ delayAlert: If set to True (the default), a message will be sent to any
+ user who has properly requested a package. The message confirms
+ that a package was selected and will be sent.
+
+ If no valid config file is provided to __init__, gettorConf will try to use
+ '~/.gettorrc' as default config file. If that fails, the default values from
+ useConf will be used.
+
+ Run this module from the commandline to have it print a useful default config
+ like so:
+
+ $ ./gettor_config.py > ~/.gettorrc
+
+'''
+
+import os
+import sys
+import ConfigParser
+
+__all__ = ["Config"]
+
+class Config:
+ '''
+ Initialize gettor with default values if one or more values are missing
+ from the config file. This will return entirely default values if the
+ configuration file is missing. Our default file location is ~/.gettorrc
+ of $USER.
+ '''
+
+ def __init__(self, path = os.path.expanduser("~/.gettorrc")):
+ '''
+ Most of the work happens here. Parse config, merge with default values,
+ prepare outConf.
+ '''
+
+ self.configFile = os.path.expanduser(path)
+
+ # Variable name | Default value | Section
+ self.useConf = {"stateDir": ("/var/lib/gettor/", "global"),
+ "blStateDir": ("/var/lib/gettor/bl/", "global"),
+ "wlStateDir": ("/var/lib/gettor/wl/", "global"),
+ "srcEmail": ("gettor@xxxxxxxxxxxxxx", "global"),
+ "distDir": ("/var/lib/gettor/dist/", "global"),
+ "packDir": ("/var/lib/gettor/pkg/", "global"),
+ "locale": ("en", "global"),
+ "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
+ self.config = ConfigParser.ConfigParser()
+ # And another to provide a useable default config as output. This is
+ # only because the user may have strange stuff inside his config file.
+ # We're trying to be failsafe here
+ self.outConf = ConfigParser.ConfigParser()
+
+ try:
+ if os.access(self.configFile, os.R_OK):
+ self.config.read(self.configFile)
+ except:
+ pass
+
+ # Main parser loop:
+ # * Merge default values with those from the config file, if there are
+ # any
+ # * Update values from config file into useConf
+ # * Ignore sections and values that are not found in useConf, but in
+ # the config file (wtf?)
+ # * Prepare outConf
+ for dkey, (dval, sec) in self.useConf.items():
+ if not self.outConf.has_section(sec):
+ self.outConf.add_section(sec)
+ try:
+ for key, val in self.config.items(sec):
+ # Unfortunatly, keys from the config are not case-sensitive
+ if key.lower() == dkey.lower():
+ self.useConf[dkey] = val, sec
+ self.outConf.set(sec, dkey, val)
+ break
+ else:
+ # Add default value for dkey
+ self.outConf.set(sec, dkey, dval)
+
+ except:
+ self.outConf.set(sec, dkey, dval)
+
+ def printConfiguration(self):
+ '''
+ Print out config file. This works even if there is none
+ '''
+ return self.outConf.write(sys.stdout)
+
+ # All getter routines live below
+ def getStateDir(self):
+ return self.useConf["stateDir"][0]
+
+ def getBlStateDir(self):
+ return self.useConf["blStateDir"][0]
+
+ def getWlStateDir(self):
+ return self.useConf["wlStateDir"][0]
+
+ def getSrcEmail(self):
+ return self.useConf["srcEmail"][0]
+
+ def getDistDir(self):
+ return self.useConf["distDir"][0]
+
+ def getPackDir(self):
+ return self.useConf["packDir"][0]
+
+ def getLocale(self):
+ return self.useConf["locale"][0]
+
+ def getLogSubSystem(self):
+ return self.useConf["logSubSystem"][0]
+
+ def getLogFile(self):
+ return self.useConf["logFile"][0]
+
+ def getLocaleDir(self):
+ return self.useConf["localeDir"][0]
+
+ def getCmdPassFile(self):
+ return self.useConf["cmdPassFile"][0]
+
+ def getDelayAlert(self):
+ return self.useConf["delayAlert"][0]
+
+if __name__ == "__main__" :
+ c = Config()
+ print "# This is a suitable default configuration. Tune to fit your needs."
+ c.printConfiguration()
Copied: projects/gettor/lib/gettor/constants.py (from rev 20885, projects/gettor/gettor/constants.py)
===================================================================
--- projects/gettor/lib/gettor/constants.py (rev 0)
+++ projects/gettor/lib/gettor/constants.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,164 @@
+#!/usr/bin/python2.5
+# -*- coding: utf-8 -*-
+"""
+ constants.py
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+"""
+
+import gettext
+
+_ = gettext.gettext
+
+helpmsg = _("""
+ 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
+ one of those.
+
+ We only process requests from email services that support "DKIM",
+ which is an email feature that lets us verify that the address in the
+ "From" line is actually the one who sent the mail.
+
+ (We apologize if you didn't ask for this mail. Since your email is from
+ a service that doesn't use DKIM, we're sending a short explanation,
+ and then we'll ignore this email address for the next day or so.)
+
+ Please note that currently, we can't process HTML emails or base 64
+ mails. You will need to send plain text.
+
+ If you have any questions or it doesn't work, you can contact a
+ human at this support email address: tor-assistants@xxxxxxxxxxxxxx
+ """)
+
+packagehelpmsg = _("""
+ 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:
+
+ tor-browser-bundle
+ macosx-universal-bundle
+ panther-bundle
+ tor-im-browser-bundle
+ source-bundle
+
+ Please reply to this mail (to gettor@xxxxxxxxxxxxxx), and tell me
+ a single package name anywhere in the body of your email.
+
+ Please note that currently we can't process HTML emails or base64
+ emails. You will need to send plain text.
+
+ If you have any questions or it doesn't work, you can contact a
+ human at this support email address: tor-assistants@xxxxxxxxxxxxxx
+
+ """)
+
+packagemsg = _("""
+ Hello! This is the "GetTor" robot.
+
+ Here's your requested software as a zip file. Please unzip the
+ package and verify the signature.
+
+ Hint: If your computer has GnuPG installed, use the gpg
+ commandline tool as follows after unpacking the zip file:
+
+ gpg --verify <packagename>.asc <packagename>
+
+ The output should look somewhat like this:
+
+ gpg: Good signature from "Roger Dingledine <arma@xxxxxxx>"
+
+ If you're not familiar with commandline tools, try looking for
+ a graphical user interface for GnuPG on this website:
+
+ http://www.gnupg.org/related_software/frontends.html
+
+ If your Internet connection blocks access to the Tor network, you
+ may need a bridge relay. Bridge relays (or "bridges" for short)
+ are Tor relays that aren't listed in the main directory. Since there
+ is no complete public list of them, even if your ISP is filtering
+ connections to all the known Tor relays, they probably won't be able
+ to block all the bridges.
+
+ You can acquire a bridge by sending an email that contains "get bridges"
+ in the body of the email to the following email address:
+ bridges@xxxxxxxxxxxxxx
+
+ It is also possible to fetch bridges with a web browser at the following
+ url: https://bridges.torproject.org/
+
+ If you have any questions or it doesn't work, you can contact a
+ human at this support email address: tor-assistants@xxxxxxxxxxxxxx
+
+ """)
+
+splitpackagemsg = _("""
+ Hello! This is the "GetTor" robot.
+
+ Here's your requested software as a zip file. Please unzip the
+ package and verify the signature.
+
+ IMPORTANT NOTE:
+ Since this is part of a split-file request, you need to wait for
+ all split files to be received by you before you can save them all
+ into the same directory and unpack them by double-clicking the
+ first file.
+
+ Packages might come out of order! Please make sure you received
+ all packages before you attempt to unpack them!
+
+ Hint: If your computer has GnuPG installed, use the gpg
+ commandline tool as follows after unpacking the zip file:
+
+ gpg --verify <packagename>.asc <packagename>
+
+ The output should look somewhat like this:
+
+ gpg: Good signature from "Roger Dingledine <arma@xxxxxxx>"
+
+ If you're not familiar with commandline tools, try looking for
+ a graphical user interface for GnuPG on this website:
+
+ http://www.gnupg.org/related_software/frontends.html
+
+ If your Internet connection blocks access to the Tor network, you
+ may need a bridge relay. Bridge relays (or "bridges" for short)
+ are Tor relays that aren't listed in the main directory. Since there
+ is no complete public list of them, even if your ISP is filtering
+ connections to all the known Tor relays, they probably won't be able
+ to block all the bridges.
+
+ You can acquire a bridge by sending an email that contains "get bridges"
+ in the body of the email to the following email address:
+ bridges@xxxxxxxxxxxxxx
+
+ It is also possible to fetch bridges with a web browser at the following
+ url: https://bridges.torproject.org/
+
+ If you have any questions or it doesn't work, you can contact a
+ human at this support email address: tor-assistants@xxxxxxxxxxxxxx
+
+ """)
+
+delayalertmsg = _("""
+ 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
+ minutes.
+
+ If it doesn't arrive, the package might be too big for your mail provider.
+ Try resending the mail from a gmail.com or yahoo.cn account. Also,
+ try asking for tor-browser-bundle rather than tor-im-browser-bundle,
+ since it's smaller.
+
+ If you have any questions or it doesn't work, you can contact a
+ human at this support email address: tor-assistants@xxxxxxxxxxxxxx
+
+ """)
Copied: projects/gettor/lib/gettor/gtlog.py (from rev 20885, projects/gettor/gettor/gtlog.py)
===================================================================
--- projects/gettor/lib/gettor/gtlog.py (rev 0)
+++ projects/gettor/lib/gettor/gtlog.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ gettor_log.py - gettor logging configuration
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+ gettor may log information, this is how we handle that logging requirement.
+ A user may log to 'syslog', a 'file', 'stdout' or 'nothing'.
+ The user can choose one of those four options in a configuration file.
+
+ Note that this module will silently fall back to 'nothing' if anything is
+ minconfigured. Might be harder to debug, but is safer for now.
+'''
+
+import os
+import sys
+from time import gmtime, strftime
+import ConfigParser
+import syslog
+import logging
+import gettor.config
+from logging import handlers
+
+__all__ = ["initalize", "getLogger", "getLogSubSystem"]
+
+# Leave this to INFO for now
+loglevel = logging.INFO
+format = '%(asctime)-15s (%(process)d) %(message)s'
+logger = None
+logSubSystem = None
+initialized = False
+
+def initialize():
+ global logger
+ global logSubSystem
+ global initialized
+ # Don't add handlers twice
+ if initialized == True:
+ return
+ conf = gettor.config.Config()
+ logger = logging.getLogger('gettor')
+ logger.setLevel(loglevel)
+ logSubSystem = conf.getLogSubSystem()
+
+ if logSubSystem == "stdout":
+ handler = logging.StreamHandler()
+ elif logSubSystem == "file":
+ # Silently fail if things are misconfigured
+ logFile = conf.getLogFile()
+ try:
+ if os.access(os.path.dirname(logFile), os.W_OK):
+ handler = logging.FileHandler(logFile)
+ else:
+ logSubSystem = "nothing"
+ except:
+ logSubSystem = "nothing"
+ elif logSubSystem == "syslog":
+ handler = logging.handlers.SysLogHandler(address="/dev/log")
+ else:
+ # Failsafe fallback
+ logSubSystem = "nothing"
+
+ # If anything went wrong or the user doesn't want to log
+ if logSubSystem == "nothing":
+ handler = logging.FileHandler(os.devnull)
+
+ formatter = logging.Formatter(fmt=format)
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ initialized = True
+
+def getLogSubSystem():
+ global logSubSystem
+ return logSubSystem
+
+def getLogger():
+ global logger
+ if logger is None:
+ initialize()
+ return logger
+
+if __name__ == "__main__" :
+ initialize()
+ print "This is the logging module. You probably do not want to call it by hand."
+ print "We'll send a test logging message now with the following subsystem: " + \
+ getLogSubSystem()
+ log = getLogger()
+ log.info("I'm a logger, logging!")
Copied: projects/gettor/lib/gettor/opt.py (from rev 20885, projects/gettor/gettor/opt.py)
===================================================================
--- projects/gettor/lib/gettor/opt.py (rev 0)
+++ projects/gettor/lib/gettor/opt.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ gettor_config.py: Command line parser for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+
+ This is the option parser module for gettor.
+'''
+
+import optparse
+
+__all__ = ["parseOpts"]
+
+def parseOpts():
+ cmdParser = optparse.OptionParser()
+ cmdParser.add_option("-c", "--config", dest="configfile",
+ default="~/.gettorrc",
+ help="set config file to FILE", metavar="FILE")
+ cmdParser.add_option("-m", "--use-mirror", dest="mirror",
+ default="rsync.torproject.org",
+ help="set Tor package mirror to MIRROR",
+ metavar="MIRROR")
+ cmdParser.add_option("-i", "--install-crontab", dest="installcron",
+ action="store_true", default=False,
+ help="install crontab to refresh packagelist")
+ cmdParser.add_option("-f", "--fetch-packages", dest="fetchpackages",
+ action="store_true", default=False,
+ help="fetch Tor packages from mirror")
+ cmdParser.add_option("-p", "--prep-packages", dest="preppackages",
+ action="store_true", default=False,
+ help="prepare packages (zip them)")
+ cmdParser.add_option("-t", "--run-tests", dest="runtests",
+ action="store_true", default=False,
+ help="run some tests")
+ cmdParser.add_option("-w", "--whitelist", dest="whitelist",
+ default="",
+ help="add an email address to the whitelist",
+ metavar="WHITELIST")
+ cmdParser.add_option("-b", "--blacklist", dest="blacklist",
+ default="",
+ help="add an email address to the blacklist",
+ metavar="BLACKLIST")
+ cmdParser.add_option("-l", "--lookup", dest="lookup",
+ default="",
+ help="check black/white list presence of address",
+ metavar="CHECKADDRESS")
+ cmdParser.add_option("-x", "--clear-whitelist", dest="clearwl",
+ action="store_true", default=False,
+ help="clear all entrys in the whitelist")
+ cmdParser.add_option("-y", "--clear-blacklist", dest="clearbl",
+ action="store_true", default=False,
+ help="clear all entrys in the blacklist")
+ 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]",
+ metavar="DIR")
+
+ return cmdParser.parse_args()
+
+if __name__ == "__main__":
+ print >> sys.stderr, "You shouldn't run this directly."
Copied: projects/gettor/lib/gettor/packages.py (from rev 20885, projects/gettor/gettor/packages.py)
===================================================================
--- projects/gettor/lib/gettor/packages.py (rev 0)
+++ projects/gettor/lib/gettor/packages.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,171 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ packages.py: Package related stuff
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+ This module handles all package related functionality
+'''
+
+import os
+import zipfile
+import subprocess
+import gettor.gtlog
+import gettor.config
+import re
+
+__all__ = ["Packages"]
+
+log = gettor.gtlog.getLogger()
+
+# XXX
+def createDir(path):
+ try:
+ log.info("Creating directory %s.." % path)
+ os.makedirs(path)
+ except OSError, e:
+ log.error("Failed to create directory %s: %s" % (path, e))
+ return False
+ return True
+
+class Packages:
+ # "bundle name": ("single file regex", "split file regex")
+ packageRegex = { "windows-bundle": ("vidalia-bundle-.*.exe$", "vidalia-bundle-.*_split"),
+ "panther-bundle": ("vidalia-bundle-.*-ppc.dmg$", "vidalia-bundle-.*-ppc_split"),
+ "macosx-universal-bundle": ("vidalia-bundle-.*-universal.dmg$", "vidalia-bundle-.*-universal_split"),
+ "source-bundle": ("tor-.*.tar.gz$", "Now to something completely different"),
+ "tor-browser-bundle": ("tor-browser-.*_en-US.exe$", "tor-browser-.*_en-US_split"),
+ "tor-im-browser-bundle": ("tor-im-browser-.*_en-US.exe$", "tor-im-browser-.*_en-US_split"),
+ # Mike won't sign Torbutton; He doesn't get gettor support
+ #"torbutton": "torbutton-current.xpi$",
+ }
+
+ def __init__(self, config):
+ self.packageList = {}
+ self.distDir = config.getDistDir()
+ try:
+ entry = os.stat(self.distDir)
+ except OSError, e:
+ if not createDir(self.distDir):
+ log.error("Bad dist dir %s: %s" % (self.distDir, e))
+ raise IOError
+ self.packDir = config.getPackDir()
+ try:
+ entry = os.stat(self.packDir)
+ except OSError, e:
+ if not createDir(self.packDir):
+ log.error("Bad pack dir %s: %s" % (self.packDir, e))
+ raise IOError
+
+ def getPackageList(self):
+ # Build dict like 'name': 'name.z'
+ try:
+ for filename in os.listdir(self.packDir):
+ self.packageList[filename[:-2]] = self.packDir + "/" + filename
+ except OSError, (strerror):
+ log.error("Failed to build package list: %s" % strerror)
+ return None
+
+ # Check sanity
+ for key, val in self.packageList.items():
+ # Remove invalid packages
+ if not os.access(val, os.R_OK):
+ log.info("Warning: %s not accessable. Removing from list." \
+ % val)
+ del self.packageList[key]
+ return self.packageList
+
+ def buildPackages(self):
+ for filename in os.listdir(self.distDir):
+ for (pack, (regex_single, regex_split)) in self.packageRegex.items():
+ # Splitfile hacks. XXX: Refactor
+ if re.compile(regex_split).match(filename):
+ packSplitDir = None
+ try:
+ packSplitDir = self.packDir + "/" + pack + ".split"
+ if not os.access(packSplitDir, os.R_OK):
+ os.mkdir(packSplitDir)
+ except OSError, e:
+ log.error("Could not create dir %s: %s" \
+ % (packSplitDir, e))
+ # Loop through split dir, look if every partXX.ZZZ has a
+ # matching signature, pack them together in a .z
+ splitdir = self.distDir + "/" + filename
+ for splitfile in os.listdir(splitdir):
+ # Skip signature files
+ if splitfile.endswith(".asc"):
+ continue
+ if re.compile(".*split.part.*").match(splitfile):
+ ascfile = splitdir + "/" + splitfile + ".asc"
+ file = splitdir + "/" + splitfile
+ zipFileName = packSplitDir + "/" + splitfile + ".z"
+ if os.access(ascfile, os.R_OK) and os.access(file, os.R_OK):
+ print "ok: ", zipFileName
+ zip = zipfile.ZipFile(zipFileName, "w")
+ zip.write(splitdir + "/" + splitfile, os.path.basename(file))
+ zip.write(ascfile, os.path.basename(ascfile))
+ zip.close()
+ else:
+ log.error("Uhm, expected signature file for %s to be: %s" % (file, ascfile))
+ return False
+ if re.compile(regex_single).match(filename):
+ file = self.distDir + "/" + filename
+ ascfile = file + ".asc"
+ zipFileName = self.packDir + "/" + pack + ".z"
+ # If .asc file is there, build Zip file
+ if os.access(ascfile, os.R_OK):
+ zip = zipfile.ZipFile(zipFileName, "w")
+ zip.write(file, os.path.basename(file))
+ zip.write(ascfile, os.path.basename(ascfile))
+ zip.close()
+ self.packageList[pack] = zipFileName
+ break
+ if len(self.packageList) > 0:
+ return True
+ else:
+ log.error("Failed to build packages")
+ return False
+
+ def syncWithMirror(self, mirror, silent):
+ rsync = ["rsync"]
+ rsync.append("-a")
+ # Don't download dotdirs
+ rsync.append("--exclude='.*'")
+ if not silent:
+ rsync.append("--progress")
+ rsync.append("rsync://%s/tor/dist/current/" % mirror)
+ rsync.append(self.distDir)
+ process = subprocess.Popen(rsync)
+ process.wait()
+ return process.returncode
+
+ def getCommandToStr(self, mirror, silent):
+ """This is useful for cronjob installations
+ """
+ rsync = ["rsync"]
+ rsync.append("-a")
+ # Don't download dotdirs
+ rsync.append("--exclude='.*'")
+ if not silent:
+ rsync.append("--progress")
+ rsync.append("rsync://%s/tor/dist/current/" % mirror)
+ rsync.append(self.distDir)
+ return ''.join(self.rsync)
+
+if __name__ == "__main__" :
+ c = gettor_config.Config()
+ p = gettorPackages("rsync.torproject.org", c)
+ print "Building packagelist.."
+ if p.syncwithMirror() != 0:
+ print "Failed."
+ exit(1)
+ if not p.buildPackageList():
+ print "Failed."
+ exit(1)
+ print "Done."
+ for (pack, file) in p.getPackageList().items():
+ print "Bundle is mapped to file: ", pack, file
Copied: projects/gettor/lib/gettor/requests.py (from rev 20885, projects/gettor/gettor/requests.py)
===================================================================
--- projects/gettor/lib/gettor/requests.py (rev 0)
+++ projects/gettor/lib/gettor/requests.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,143 @@
+#!/usr/bin/python2.5
+# -*- coding: utf-8 -*-
+"""
+ gettor_config.py - Parse configuration file for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+ This library implements all of the email parsing features needed for gettor.
+"""
+
+import sys
+import email
+import dkim
+import re
+
+import gettor.gtlog
+import gettor.packages
+
+__all__ = ["requestMail"]
+
+log = gettor.gtlog.getLogger()
+
+class requestMail:
+
+ defaultLang = "en"
+ # XXX
+ supportedLangs = { "en": "English",
+ "de": "Deutsch" }
+
+ def __init__(self, config):
+ """ Read message from stdin, parse all the stuff we want to know
+ """
+ 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
+ # We also should catch totally malformed messages here
+ try:
+ if dkim.verify(self.rawMessage):
+ self.signature = True
+ except:
+ pass
+
+ # TODO XXX:
+ # Scrub this data
+ self.replytoAddress = self.parsedMessage["from"]
+ assert self.replytoAddress is not None, "Replyto address is None"
+ # 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
+ for line in email.Iterators.body_line_iterator(self.parsedMessage):
+ # Remove quotes
+ if line.startswith(">"):
+ continue
+ # XXX This is a bit clumsy, but i cant think of a better way
+ # currently. A map also doesnt really help i think. -kaner
+ for package in self.packages.keys():
+ matchme = ".*" + package + ".*"
+ match = re.match(matchme, line)
+ 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)
+ if match:
+ self.splitDelivery = True
+ log.info("User requested a split delivery")
+ # Default locale is english
+ match = re.match(".*[Ll]ang:\s+(.*)$", line)
+ 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:
+ break
+ else:
+ log.info("Requested language %s not supported. Falling back to %s" \
+ % (self.replyLocale, self.defaultLang))
+ self.replyLocale = self.defaultLang
+
+ return (self.replytoAddress, self.replyLocale, self.returnPackage, \
+ self.splitDelivery, self.signature, self.commandaddress)
+
+ def getRawMessage(self):
+ return self.rawMessage
+
+ def hasVerifiedSignature(self):
+ return self.signature
+
+ def getParsedMessage(self):
+ return self.parsedMessage
+
+ def getReplyTo(self):
+ return self.replytoAddress
+
+ def getPackage(self):
+ return self.returnPackage
+
+ def getLocale(self):
+ return self.replyLocale
+
+ def getSplitDelivery(self):
+ return self.splitDelivery
+
+ def getAll(self):
+ return (self.replytoAddress, self.replyLocale, \
+ self.returnPackage, self.splitDelivery, self.signature)
Copied: projects/gettor/lib/gettor/responses.py (from rev 20885, projects/gettor/gettor/responses.py)
===================================================================
--- projects/gettor/lib/gettor/responses.py (rev 0)
+++ projects/gettor/lib/gettor/responses.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,247 @@
+#!/usr/bin/python2.5
+# -*- coding: utf-8 -*-
+"""
+ gettor_config.py - Parse configuration file for gettor
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+ This library implements all of the email replying features needed for gettor.
+"""
+
+import os
+import smtplib
+import MimeWriter
+import StringIO
+import base64
+import gettext
+import re
+
+import gettor.gtlog
+import gettor.blacklist
+import gettor.constants
+
+__all__ = ["Response"]
+
+log = gettor.gtlog.getLogger()
+
+class Response:
+
+ def __init__(self, config, replyto, lang, package, split, signature, caddr):
+ self.config = config
+ self.srcEmail = "GetTor <gettor@xxxxxxxxxxxxxx>"
+ self.replyTo = replyto
+ 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:
+ trans = gettext.translation("gettor", config.getLocaleDir(), [lang])
+ trans.install()
+ except IOError:
+ log.error("Translation fail. Trying running with -r.")
+ raise
+
+ def sendReply(self):
+ """All routing decisions take place here."""
+ # Check we're happy with sending this user a package
+ 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) \
+ and not re.compile(".*@gmail.com").match(self.replyTo):
+ blackListed = self.blackList.lookupListEntry(self.replyTo)
+ if blackListed:
+ log.info("Unsigned messaged to gettor by blacklisted user dropped.")
+ return False
+ else:
+ # Reply with some help and bail out
+ self.blackList.createListEntry(self.replyTo)
+ 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()
+ if delayAlert:
+ ret = self.sendDelayAlert()
+ if ret != True:
+ log.error("Failed to sent delay alert.")
+ if self.splitsend:
+ return self.sendSplitPackage()
+ else:
+ return self.sendPackage()
+
+ def sendPackage(self):
+ """ Send a message with an attachment to the user"""
+ log.info("Sending out %s to %s." % (self.package, self.sendTo))
+ packages = gettor.packages.Packages(self.config)
+ packageList = packages.getPackageList()
+ filename = packageList[self.package]
+ message = gettor.constants.packagemsg
+ package = self.constructMessage(message, "", filename)
+ try:
+ status = self.sendMessage(package)
+ except:
+ log.error("Could not send package to user")
+ status = False
+
+ log.info("Send status: %s" % status)
+ return status
+
+ def sendSplitPackage(self):
+ """XXX XXX XXX alpha state XXX XXX XXX"""
+ splitdir = self.config.getPackDir() + "/" + self.package + ".split"
+ try:
+ entry = os.stat(splitdir)
+ except OSError, e:
+ log.error("Not a valid directory: %s" % splitdir)
+ return False
+ files = os.listdir(splitdir)
+ # Sort the files, so we can send 01 before 02 and so on..
+ files.sort()
+ nFiles = len(files)
+ num = 0
+ for filename in files:
+ fullPath = splitdir + "/" + filename
+ num = num + 1
+ subj = "[GetTor] Split package [%02d / %02d] " % (num, nFiles)
+ message = gettor.constants.splitpackagemsg
+ package = self.constructMessage(message, subj, fullPath)
+ try:
+ status = self.sendMessage(package)
+ except:
+ log.error("Could not send package %s to user" % filename)
+ # XXX What now? Keep on sending? Bail out? Use might have
+ # already received 10 out of 12 packages..
+ status = False
+
+ return status
+
+ def sendDelayAlert(self):
+ """ Send a delay notification """
+ 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.sendTo)
+ return self.sendGenericMessage(gettor.constants.helpmsg)
+
+## XXX the following line was used below to automatically list the names
+## of available packages. But they were being named in an arbitrary
+## order, which caused people to always pick the first one. I listed
+## tor-browser-bundle first since that's the one they should want.
+## Somebody should figure out how to automate yet sort. -RD
+## """ + "".join([ "\t%s\n" % key for key in packageList.keys()]) + """
+
+ def sendPackageHelp(self):
+ """ Send a helpful message to the user interacting with us """
+ 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.sendTo)
+ status = False
+
+ log.info("Send status: %s" % status)
+ return status
+
+ def constructMessage(self, messageText, subj, fileName=None):
+ """ Construct a multi-part mime message, including only the first part
+ with plaintext."""
+
+ if subj == "":
+ subj =_('[GetTor] Your request')
+ message = StringIO.StringIO()
+ mime = MimeWriter.MimeWriter(message)
+ mime.addheader('MIME-Version', '1.0')
+ mime.addheader('Subject', subj)
+ mime.addheader('To', self.sendTo)
+ mime.addheader('From', self.srcEmail)
+ mime.startmultipartbody('mixed')
+
+ firstPart = mime.nextpart()
+ emailBody = firstPart.startbody('text/plain')
+ emailBody.write(messageText)
+
+ # Add a file if we have one
+ if fileName:
+ filePart = mime.nextpart()
+ filePart.addheader('Content-Transfer-Encoding', 'base64')
+ emailBody = filePart.startbody('application/zip; name=%s' % os.path.basename(fileName))
+ base64.encode(open(fileName, 'rb'), emailBody)
+
+ # Now end the mime messsage
+ mime.lastpart()
+ return message
+
+ def sendMessage(self, message, smtpserver="localhost:25"):
+ try:
+ smtp = smtplib.SMTP(smtpserver)
+ smtp.sendmail(self.srcEmail, self.sendTo, message.getvalue())
+ smtp.quit()
+ status = True
+ except smtplib.SMTPAuthenticationError:
+ log.error("SMTP authentication error")
+ return False
+ except smtplib.SMTPHeloError:
+ log.error("SMTP HELO error")
+ return False
+ except smtplib.SMTPConnectError:
+ log.error("SMTP connection error")
+ return False
+ except smtplib.SMTPDataError:
+ log.error("SMTP data error")
+ return False
+ except smtplib.SMTPRecipientsRefused:
+ log.error("SMTP refused to send to recipients")
+ return False
+ except smtplib.SMTPSenderRefused:
+ log.error("SMTP sender address refused")
+ return False
+ except smtplib.SMTPResponseException:
+ log.error("SMTP response exception received")
+ return False
+ except smtplib.SMTPServerDisconnected:
+ log.error("SMTP server disconnect exception received")
+ return False
+ except smtplib.SMTPException:
+ log.error("General SMTP error caught")
+ return False
+ except:
+ log.error("Unknown SMTP error while trying to send via local MTA")
+ return False
+
+ return status
Copied: projects/gettor/lib/gettor/utils.py (from rev 20885, projects/gettor/gettor/utils.py)
===================================================================
--- projects/gettor/lib/gettor/utils.py (rev 0)
+++ projects/gettor/lib/gettor/utils.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,280 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+'''
+ utils.py: Useful helper routines
+
+ Copyright (c) 2008, Jacob Appelbaum <jacob@xxxxxxxxxxxxx>,
+ Christian Fromme <kaner@xxxxxxxxxx>
+
+ This is Free Software. See LICENSE for license information.
+
+ This module handles all package related functionality
+'''
+
+import os
+import subprocess
+import hashlib
+
+import gettor.gtlog
+import gettor.blacklist
+import gettor.packages
+
+log = gettor.gtlog.getLogger()
+
+def createDir(path):
+ """Helper routine that creates a given directory"""
+ try:
+ log.info("Creating directory %s.." % path)
+ os.makedirs(path)
+ except OSError, e:
+ log.error("Failed to create directory %s: %s" % (path, e))
+ return False
+ return True
+
+def installTranslations(conf, localeSrcdir):
+ """Install all translation files to 'dir'"""
+ log.info("Installing translation files..")
+ hasDirs = None
+
+ if conf is None:
+ log.error("Bad arg.")
+ return False
+ if not os.path.isdir(localeSrcdir):
+ log.info("Not a directory: %s" % localeSrcdir)
+ if not createDir(localeSrcdir):
+ log.error("Giving up on %s" % localeSrcdir)
+ return False
+ localeDir = conf.getLocaleDir()
+ if not os.path.isdir(localeDir):
+ log.info("Not a directory: %s" % localeDir)
+ if not createDir(localeDir):
+ log.error("Giving up on %s" % localeDir)
+ return False
+
+ # XXX: Warn if there is no translation files anywhere..
+ for root, dirs, files in os.walk(localeSrcdir):
+ # Python lacks 'depth' feature for os.walk()
+ if root != localeSrcdir:
+ continue
+ for dir in dirs:
+ hasDirs = True
+ if dir.startswith("."):
+ continue
+ # We ignore the templates dir for now
+ if dir.startswith("templates"):
+ continue
+ try:
+ poFile = os.path.join(root, dir) + "/gettor.po"
+ # Construct target dir
+ targetDir = localeDir + "/" + dir + "/LC_MESSAGES"
+ if not os.path.isdir(targetDir):
+ log.info("Not a directory: %s" % targetDir)
+ if not createDir(targetDir):
+ log.error("Giving up on %s" % targetDir)
+ return False
+ if installMo(poFile, targetDir) == False:
+ log.error("Installing .mo files failed.")
+ return False
+ except Exception:
+ log.error("Error accessing translation files.")
+ return False
+ if hasDirs is None:
+ log.errpr("Empty locale dir: " % localeSrcdir)
+ return False
+
+ return True
+
+def fetchPackages(conf, mirror):
+ """Fetch Tor packages from a mirror"""
+ log.info("Fetching package files..")
+ try:
+ packs = gettor.packages.Packages(conf)
+ except IOError:
+ log.error("Error initiating package list.")
+ return False
+ if packs.syncWithMirror(mirror, False) != 0:
+ log.error("Syncing Tor packages failed.")
+ return False
+ else:
+ log.info("Syncing Tor packages done.")
+ return True
+
+def prepPackages(conf):
+ """Prepare the downloaded packages in a way so GetTor can work with them"""
+ log.info("Preparing package files..")
+ try:
+ packs = gettor.packages.Packages(conf)
+ except IOError:
+ log.error("Error initiating package list.")
+ return False
+ if not packs.buildPackages():
+ log.error("Building packages failed.")
+ return False
+ else:
+ log.info("Building packages done.")
+ return True
+
+def installCron():
+ log.info("Installing cronjob..")
+ # XXX: Check if cron is installed and understands our syntax?
+ currentCronTab = getCurrentCrontab()
+ path = os.getcwd() + "/" + os.path.basename(sys.argv[0])
+ args = " --clear-blacklist --fetch-packages --prep-packages"
+ newCronTab = currentCronTab + '\n' + '3 2 * * * ' + path + args
+ echoCmd = ['echo', newCronTab ]
+ cronCmd = ['crontab', '-']
+ echoProc = subprocess.Popen(echoCmd, stdout=subprocess.PIPE)
+ cronProc = subprocess.Popen(cronCmd, stdin=echoProc.stdout)
+ cronProc.communicate()[0]
+ return cronProc.returncode
+
+def addWhitelistEntry(conf, address):
+ log.info("Adding address to whitelist: %s" % address)
+ try:
+ whiteList = gettor.blacklist.BWList(conf.getWlStateDir())
+ except IOError, e:
+ log.error("Whitelist error: %s" % e)
+ return False
+ if not whiteList.createListEntry(address):
+ log.error("Creating whitelist entry failed.")
+ return False
+ else:
+ log.info("Creating whitelist entry ok.")
+ return True
+
+def addBlacklistEntry(conf, address):
+ log.info("Adding address to blacklist: %s" % address)
+ try:
+ blackList = gettor.blacklist.BWList(conf.getBlStateDir())
+ except IOError, e:
+ log.error("Blacklist error: %s" % e)
+ return False
+ if not blackList.createListEntry(address):
+ log.error("Creating blacklist entry failed.")
+ return False
+ else:
+ log.info("Creating whitelist entry ok.")
+ return True
+
+def lookupAddress(conf, address):
+ log.info("Lookup address: %s" % address)
+ found = False
+ try:
+ whiteList = gettor.blacklist.BWList(conf.getWlStateDir())
+ blackList = gettor.blacklist.BWList(conf.getBlStateDir())
+ except IOError, e:
+ log.error("White/Blacklist error: %s" % e)
+ return False
+ if whiteList.lookupListEntry(address):
+ log.info("Address '%s' is present in the whitelist." % address)
+ found = True
+ if blackList.lookupListEntry(address):
+ log.info("Address '%s' is present in the blacklist." % address)
+ found = True
+ if not found:
+ log.info("Address '%s' neither in blacklist or whitelist." % address)
+ found = True
+
+ # Always True
+ return found
+
+def clearWhitelist(conf):
+ try:
+ whiteList = gettor.blacklist.BWList(conf.getWlStateDir())
+ except IOError, e:
+ log.error("Whitelist error: %s" % e)
+ return False
+ log.info("Clearing whitelist..")
+ if not whiteList.removeAll():
+ log.error("Deleting whitelist failed.")
+ return False
+ else:
+ log.info("Deleting whitelist done.")
+ return True
+
+def clearBlacklist(conf):
+ log.info("Clearing blacklist..")
+ try:
+ blackList = gettor.blacklist.BWList(conf.getBlStateDir())
+ except IOError, e:
+ log.error("Blacklist error: %s" % e)
+ return False
+ if not blackList.removeAll():
+ log.error("Deleting blacklist failed.")
+ return False
+ else:
+ 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):
+ global log
+ args = os.getcwd() + "/" + poFile + " -o " + targetDir + "/gettor.mo"
+ try:
+ ret = subprocess.call("msgfmt" + " " + args, shell=True)
+ if ret < 0:
+ log.error("Error in msgfmt execution: %s" % ret)
+ return False
+ except OSError, e:
+ log.error("Comilation failed: " % e)
+ return False
+ return True
+
+def installTrans(config, localeSrcdir):
+ global log
+ hasDirs = None
+
+ if config is None:
+ log.error("Bad arg.")
+ return False
+ if not os.path.isdir(localeSrcdir):
+ log.info("Not a directory: %s" % localeSrcdir)
+ if not createDir(localeSrcdir):
+ log.error("Giving up on %s" % localeSrcdir)
+ return False
+ localeDir = config.getLocaleDir()
+ if not os.path.isdir(localeDir):
+ log.info("Not a directory: %s" % localeDir)
+ if not createDir(localeDir):
+ log.error("Giving up on %s" % localeDir)
+ return False
+
+def getCurrentCrontab():
+ # This returns our current crontab
+ savedTab = "# This crontab has been tampered with by gettor.py\n"
+ currentTab = os.popen("crontab -l")
+ for line in currentTab:
+ savedTab += line
+ return savedTab
+
Added: projects/gettor/setup.cfg
===================================================================
--- projects/gettor/setup.cfg (rev 0)
+++ projects/gettor/setup.cfg 2009-11-01 11:50:51 UTC (rev 20886)
@@ -0,0 +1,4 @@
+[install]
+install-purelib=~/opt/gettor
+install-scripts=~/opt/gettor
+install-data=~/opt/gettor
Modified: projects/gettor/setup.py
===================================================================
--- projects/gettor/setup.py 2009-11-01 11:45:23 UTC (rev 20885)
+++ projects/gettor/setup.py 2009-11-01 11:50:51 UTC (rev 20886)
@@ -2,6 +2,8 @@
# (c) 2009 The Tor project
# GetTor installer & packer
+import glob
+
from distutils.core import setup
setup(name='GetTor',
@@ -9,8 +11,10 @@
description='GetTor enables users to obtain Tor via email',
author='Jacob Appelbaum, Christian Fromme',
author_email='jacob at appelbaum dot net, kaner at strace dot org',
- url='https://www.torpeoject.org/gettor/',
- package_dir={'': '.'},
+ url='https://www.torproject.org/gettor/',
+ package_dir={'': 'lib'},
packages=['gettor'],
- py_modules=['GetTor']
+ scripts = ["GetTor.py"],
+ py_modules=['GetTor'],
+ long_description = """Really long text here."""
)