[tor-commits] [arm/master] Dropping the tor setup wizard

atagar at torproject.org atagar at torproject.org
Tue Dec 18 16:59:54 UTC 2012


commit 26ea3b0e690bbbfaf992be19829ac2fa65fc0cc7
Author: Damian Johnson <atagar at torproject.org>
Date:   Tue Dec 18 08:46:37 2012 -0800

    Dropping the tor setup wizard
    
    Arm's setup wizard was an interesting idea, and absurdly meticulously
    engineered. However, I've *NEVER* heard of someone using it, and even I
    wouldn't trust such a complicated and unsused code path to reliably do the
    right thing.
    
    There is little point in continuing to support it. It's a ton of code
    complicating our codebase for no good reason, and only serves to confuse users
    when they're greeted with the setup dialog.
    
    Main takeaway: poll users before building a feature, otherwise you're likely
    just wasting your time.
---
 README                                           |    1 -
 armrc.sample                                     |    6 +-
 src/cli/__init__.py                              |    2 +-
 src/cli/controller.py                            |  120 ---
 src/cli/headerPanel.py                           |    9 -
 src/cli/menu/actions.py                          |    5 -
 src/cli/wizard.py                                | 1014 ----------------------
 src/resources/exitNotice/how_tor_works_thumb.png |  Bin 8147 -> 0 bytes
 src/resources/exitNotice/index.html              |  143 ---
 src/resources/startTor                           |   28 -
 src/resources/torrcOverride/override.c           |   50 --
 src/resources/torrcOverride/override.h           |    1 -
 src/resources/torrcOverride/override.py          |  363 --------
 src/resources/torrcTemplate.txt                  |   90 --
 src/settings.cfg                                 |  235 -----
 src/starter.py                                   |   21 +-
 16 files changed, 4 insertions(+), 2084 deletions(-)

diff --git a/README b/README
index 4d0b4c1..8050657 100644
--- a/README
+++ b/README
@@ -201,7 +201,6 @@ Layout:
       controller.py          - main display loop, handling input and layout
       headerPanel.py         - top of all pages, providing general information
       popups.py              - toolkit providing display popups
-      wizard.py              - provides the relay setup wizard
       
       logPanel.py            - (page 1) displays tor, arm, and stem events
       configPanel.py         - (page 3) editor panel for the tor configuration
diff --git a/armrc.sample b/armrc.sample
index 458fcbe..9072713 100644
--- a/armrc.sample
+++ b/armrc.sample
@@ -36,10 +36,6 @@ features.acsSupport true
 # none, red, green, yellow, blue, cyan, magenta, black, white
 features.colorOverride none
 
-# If arm is attached to an arm started tor instance when it shuts down then
-# offers to shut down tor too if true, otherwise skips this prompt.
-features.offerTorShutdownOnQuit false
-
 # Includes unicode characters in the interface.
 features.printUnicode true
 
@@ -74,7 +70,7 @@ features.confirmQuit true
 # we terminate right away. This is ignored if the user provides an option
 # specifying how to connect to tor (ie, a 'startup.interface.*' option or
 # startup argument).
-features.allowDetachedStartup true
+features.allowDetachedStartup false
 
 # Paremters for the log panel
 # ---------------------------
diff --git a/src/cli/__init__.py b/src/cli/__init__.py
index b0d6bd8..052e06c 100644
--- a/src/cli/__init__.py
+++ b/src/cli/__init__.py
@@ -2,5 +2,5 @@
 Panels, popups, and handlers comprising the arm user interface.
 """
 
-__all__ = ["configPanel", "controller", "headerPanel", "logPanel", "popups", "torrcPanel", "wizard"]
+__all__ = ["configPanel", "controller", "headerPanel", "logPanel", "popups", "torrcPanel"]
 
diff --git a/src/cli/controller.py b/src/cli/controller.py
index 1f2bf2b..478bc02 100644
--- a/src/cli/controller.py
+++ b/src/cli/controller.py
@@ -9,7 +9,6 @@ import curses
 import threading
 
 import cli.menu.menu
-import cli.wizard
 import cli.popups
 import cli.headerPanel
 import cli.logPanel
@@ -30,7 +29,6 @@ ARM_CONTROLLER = None
 CONFIG = {"startup.events": "N3",
           "startup.dataDirectory": "~/.arm",
           "startup.blindModeEnabled": False,
-          "features.offerTorShutdownOnQuit": False,
           "features.panels.show.graph": True,
           "features.panels.show.log": True,
           "features.panels.show.connection": True,
@@ -41,7 +39,6 @@ CONFIG = {"startup.events": "N3",
           "features.confirmQuit": True,
           "features.graph.type": 1,
           "features.graph.bw.prepopulate": True,
-          "wizard.default": {},
           "log.startTime": log.INFO,
           "log.torEventTypeUnrecognized": log.INFO,
           "log.configEntryUndefined": log.NOTICE,
@@ -171,7 +168,6 @@ class Controller:
     self._isPaused = False
     self._forceRedraw = False
     self._isDone = False
-    self._torManager = TorManager(self)
     self._lastDrawn = 0
     self.setMsg() # initializes our control message
   
@@ -401,13 +397,6 @@ class Controller:
     if not os.path.exists(dataDir): os.makedirs(dataDir)
     return dataDir
   
-  def getTorManager(self):
-    """
-    Provides management utils for an arm managed tor instance.
-    """
-    
-    return self._torManager
-  
   def isDone(self):
     """
     True if arm should be terminated, false otherwise.
@@ -439,111 +428,6 @@ class Controller:
     if isShutdownFlagPresent:
       try: torTools.getConn().shutdown()
       except IOError, exc: cli.popups.showMsg(str(exc), 3, curses.A_BOLD)
-    
-    if CONFIG["features.offerTorShutdownOnQuit"]:
-      conn = torTools.getConn()
-      
-      if self.getTorManager().isManaged(conn):
-        while True:
-          msg = "Shut down the Tor instance arm started (y/n)?"
-          confirmationKey = cli.popups.showMsg(msg, attr = curses.A_BOLD)
-          
-          if confirmationKey in (ord('y'), ord('Y')):
-            # attempts a graceful shutdown of tor, showing the issue if
-            # unsuccessful then continuing the shutdown
-            try: conn.shutdown()
-            except IOError, exc: cli.popups.showMsg(str(exc), 3, curses.A_BOLD)
-            
-            break
-          elif confirmationKey in (ord('n'), ord('N')):
-            break
-
-class TorManager:
-  """
-  Bundle of utils for starting and manipulating an arm generated tor instance.
-  """
-  
-  def __init__(self, controller):
-    self._controller = controller
-  
-  def getTorrcPath(self):
-    """
-    Provides the path to a wizard generated torrc.
-    """
-    
-    return self._controller.getDataDirectory() + "torrc"
-  
-  def isTorrcAvailable(self):
-    """
-    True if a wizard generated torrc exists and the user has permissions to
-    run it, false otherwise.
-    """
-    
-    torrcLoc = self.getTorrcPath()
-    if os.path.exists(torrcLoc):
-      # If we aren't running as root and would be trying to bind to low ports
-      # then the startup will fail due to permissons. Attempts to check for
-      # this in the torrc. If unable to read the torrc then we probably
-      # wouldn't be able to use it anyway with our permissions.
-      
-      if os.getuid() != 0:
-        try:
-          return not torConfig.isRootNeeded(torrcLoc)
-        except IOError, exc:
-          log.log(log.INFO, "Failed to read torrc at '%s': %s" % (torrcLoc, exc))
-          return False
-      else: return True
-    
-    return False
-  
-  def isManaged(self, conn):
-    """
-    Returns true if the given tor instance is managed by us, false otherwise.
-    
-    Arguments:
-      conn - controller instance to be checked
-    """
-    
-    return conn.getInfo("config-file", None) == self.getTorrcPath()
-  
-  def startManagedInstance(self):
-    """
-    Starts a managed instance of tor, logging a warning if unsuccessful. This
-    returns True if successful and False otherwise.
-    """
-    
-    torrcLoc = self.getTorrcPath()
-    os.system("tor --quiet -f %s&" % torrcLoc)
-    startTime = time.time()
-    
-    # attempts to connect for five seconds (tor might or might not be
-    # immediately available)
-    raisedExc = None
-    
-    while time.time() - startTime < 5:
-      try:
-        self.connectManagedInstance()
-        return True
-      except IOError, exc:
-        raisedExc = exc
-        time.sleep(0.5)
-    
-    if raisedExc: log.log(log.WARN, str(raisedExc))
-    return False
-  
-  def connectManagedInstance(self):
-    """
-    Attempts to connect to a managed tor instance, raising an IOError if
-    unsuccessful.
-    """
-    
-    try:
-      controller = Controller.from_port(control_port = int(CONFIG["wizard.default"]["Control"]))
-      controller.authenticate()
-      
-      torTools.getConn().init(controller)
-    except Exception, exc:
-      raise IOError("Unable to connect to Tor: %s" % exc)
 
 def shutdownDaemons():
   """
@@ -631,7 +515,6 @@ def startTorMonitor(startTime):
   
   cli.graphing.graphPanel.loadConfig(config)
   cli.connections.connEntry.loadConfig(config)
-  cli.wizard.loadConfig(config)
   
   # attempts to fetch the tor pid, warning if unsuccessful (this is needed for
   # checking its resource usage, among other things)
@@ -728,7 +611,6 @@ def drawTorMonitor(stdscr, startTime):
   # main draw loop
   overrideKey = None     # uses this rather than waiting on user input
   isUnresponsive = False # flag for heartbeat responsiveness check
-  if not torTools.getConn().isAlive(): overrideKey = ord('w') # shows wizard
   
   while not control.isDone():
     displayPanels = control.getDisplayPanels()
@@ -777,8 +659,6 @@ def drawTorMonitor(stdscr, startTime):
           log.log(log.ERR, "Error detected when reloading tor: %s" % sysTools.getFileErrorMsg(exc))
     elif key == ord('h') or key == ord('H'):
       overrideKey = cli.popups.showHelpPopup()
-    elif key == ord('w') or key == ord('W'):
-      cli.wizard.showWizard()
     elif key == ord('l') - 96:
       # force redraw when ctrl+l is pressed
       control.redraw(True)
diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py
index cf37ac1..4ab3daf 100644
--- a/src/cli/headerPanel.py
+++ b/src/cli/headerPanel.py
@@ -170,15 +170,6 @@ class HeaderPanel(panel.Panel, threading.Thread):
             controller.authenticate(authValue) # already got the password above
         except Exception, exc:
           controller = None
-          
-          # attempts to use the wizard port too
-          try:
-            cli.controller.getController().getTorManager().connectManagedInstance()
-            log.log(log.NOTICE, "Reconnected to Tor's control port")
-            cli.popups.showMsg("Tor reconnected", 1)
-          except:
-            # displays notice for the first failed connection attempt
-            if exc.args: cli.popups.showMsg("Unable to reconnect (%s)" % exc, 3)
       
       if controller:
         torTools.getConn().init(controller)
diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py
index 7f63b1b..30dff69 100644
--- a/src/cli/menu/actions.py
+++ b/src/cli/menu/actions.py
@@ -5,7 +5,6 @@ Generates the menu for arm, binding options with their related actions.
 import functools
 
 import cli.popups
-import cli.wizard
 import cli.controller
 import cli.menu.item
 import cli.graphing.graphPanel
@@ -50,7 +49,6 @@ def makeActionsMenu():
   """
   
   control = cli.controller.getController()
-  manager = control.getTorManager()
   conn = torTools.getConn()
   headerPanel = control.getPanel("header")
   actionsMenu = cli.menu.item.Submenu("Actions")
@@ -59,11 +57,8 @@ def makeActionsMenu():
   
   if conn.isAlive():
     actionsMenu.add(cli.menu.item.MenuItem("Stop Tor", conn.shutdown))
-  elif manager.isTorrcAvailable():
-    actionsMenu.add(cli.menu.item.MenuItem("Start Tor", manager.startManagedInstance))
   
   actionsMenu.add(cli.menu.item.MenuItem("Reset Tor", conn.reload))
-  actionsMenu.add(cli.menu.item.MenuItem("Setup Wizard", cli.wizard.showWizard))
   
   if control.isPaused(): label, arg = "Unpause", False
   else: label, arg = "Pause", True
diff --git a/src/cli/wizard.py b/src/cli/wizard.py
deleted file mode 100644
index 02a1f17..0000000
--- a/src/cli/wizard.py
+++ /dev/null
@@ -1,1014 +0,0 @@
-"""
-Provides user prompts for setting up a new relay. This autogenerates a torrc
-that's used by arm to run its own tor instance.
-"""
-
-import re
-import os
-import sys
-import random
-import shutil
-import getpass
-import platform
-import functools
-import curses
-
-import cli.popups
-import cli.controller
-
-import stem.version
-
-from util import connections, enum, log, sysTools, torConfig, torTools, uiTools
-
-# template used to generate the torrc
-TORRC_TEMPLATE = "resources/torrcTemplate.txt"
-
-# basic configuration types we can run as
-RelayType = enum.Enum("RESUME", "RELAY", "EXIT", "BRIDGE", "CLIENT")
-
-# all options that can be configured
-Options = enum.Enum("DIVIDER", "CONTROL", "NICKNAME", "CONTACT", "NOTIFY", "BANDWIDTH", "LIMIT", "CLIENT", "LOWPORTS", "PORTFORWARD", "SYSTEM", "STARTUP", "RSHUTDOWN", "CSHUTDOWN", "NOTICE", "POLICY", "WEBSITES", "EMAIL", "IM", "MISC", "PLAINTEXT", "DISTRIBUTE", "BRIDGED", "BRIDGE1", "BRIDGE2", "BRIDGE3", "REUSE")
-RelayOptions = {RelayType.RELAY:   (Options.NICKNAME,
-                                    Options.CONTACT,
-                                    Options.NOTIFY,
-                                    Options.BANDWIDTH,
-                                    Options.LIMIT,
-                                    Options.CLIENT,
-                                    Options.LOWPORTS,
-                                    Options.PORTFORWARD,
-                                    Options.STARTUP,
-                                    Options.RSHUTDOWN,
-                                    Options.SYSTEM),
-                RelayType.EXIT:    (Options.NICKNAME,
-                                    Options.CONTACT,
-                                    Options.NOTIFY,
-                                    Options.BANDWIDTH,
-                                    Options.LIMIT,
-                                    Options.CLIENT,
-                                    Options.LOWPORTS,
-                                    Options.PORTFORWARD,
-                                    Options.STARTUP,
-                                    Options.RSHUTDOWN,
-                                    Options.SYSTEM,
-                                    Options.DIVIDER,
-                                    Options.NOTICE,
-                                    Options.POLICY,
-                                    Options.WEBSITES,
-                                    Options.EMAIL,
-                                    Options.IM,
-                                    Options.MISC,
-                                    Options.PLAINTEXT),
-                RelayType.BRIDGE:  (Options.DISTRIBUTE,
-                                    Options.BANDWIDTH,
-                                    Options.LIMIT,
-                                    Options.CLIENT,
-                                    Options.LOWPORTS,
-                                    Options.PORTFORWARD,
-                                    Options.STARTUP,
-                                    Options.RSHUTDOWN,
-                                    Options.SYSTEM),
-                RelayType.CLIENT:  (Options.BRIDGED,
-                                    Options.BRIDGE1,
-                                    Options.BRIDGE2,
-                                    Options.BRIDGE3,
-                                    Options.REUSE,
-                                    Options.CSHUTDOWN,
-                                    Options.SYSTEM)}
-
-# option sets
-CUSTOM_POLICIES = (Options.WEBSITES, Options.EMAIL, Options.IM, Options.MISC, Options.PLAINTEXT)
-BRIDGE_ENTRIES = (Options.BRIDGE1, Options.BRIDGE2, Options.BRIDGE3)
-
-# other options provided in the prompts
-CANCEL, NEXT, BACK = "Cancel", "Next", "Back"
-
-DESC_SIZE = 5 # height of the description field
-MSG_COLOR = "green"
-OPTION_COLOR = "yellow"
-DISABLED_COLOR = "cyan"
-
-# bracketing pairs used in email address obscuring
-BRACKETS = ((' ', ' '),
-            ('<', '>'),
-            ('[', ']'),
-            ('(', ')'),
-            ('{', '}'),
-            ('|', '|'))
-
-# version requirements for options
-VERSION_REQUIREMENTS = {
-  Options.PORTFORWARD: stem.version.Requirement.TORRC_PORT_FORWARDING,
-}
-
-# tor's defaults for config options, used to filter unneeded options
-TOR_DEFAULTS = {Options.BANDWIDTH: "5 MB",
-                Options.REUSE: "10 minutes"}
-
-# path for the torrc to be placed if replacing the torrc for the system wide
-# tor instance
-SYSTEM_DROP_PATH = "/var/lib/tor-arm/torrc"
-OVERRIDE_SCRIPT = "/usr/share/arm/resources/torrcOverride/override.py"
-OVERRIDE_SETUID_SCRIPT = "/usr/bin/torrc-override"
-
-CONFIG = {"wizard.message.role": "",
-          "wizard.message.relay": "",
-          "wizard.message.exit": "",
-          "wizard.message.bridge": "",
-          "wizard.message.client": "",
-          "wizard.toggle": {},
-          "wizard.disabled": [],
-          "wizard.suboptions": [],
-          "wizard.default": {},
-          "wizard.blankValue": {},
-          "wizard.label.general": {},
-          "wizard.label.role": {},
-          "wizard.label.opt": {},
-          "wizard.description.general": {},
-          "wizard.description.role": {},
-          "wizard.description.opt": {},
-          "port.category": {},
-          "port.exit.all": [],
-          "port.exit.web": [],
-          "port.exit.mail": [],
-          "port.exit.im": [],
-          "port.exit.misc": [],
-          "port.encrypted": []}
-
-def loadConfig(config):
-  config.update(CONFIG)
-
-class ConfigOption:
-  """
-  Attributes of a configuraition option.
-  """
-  
-  def __init__(self, key, group, default):
-    """
-    Configuration option constructor.
-    
-    Arguments:
-      key     - configuration option identifier used when querying attributes
-      group   - configuration attribute group this belongs to
-      default - initial value, uses the config default if unset
-    """
-    
-    self.key = key
-    self.group = group
-    self.descriptionCache = None
-    self.descriptionCacheArg = None
-    self.value = default
-    self.validator = None
-    self._isEnabled = True
-  
-  def getKey(self):
-    return self.key
-  
-  def getValue(self):
-    return self.value
-  
-  def getDisplayValue(self):
-    if not self.value and self.key in CONFIG["wizard.blankValue"]:
-      return CONFIG["wizard.blankValue"][self.key]
-    else: return self.value
-  
-  def getDisplayAttr(self):
-    myColor = OPTION_COLOR if self.isEnabled() else DISABLED_COLOR
-    return curses.A_BOLD | uiTools.getColor(myColor)
-  
-  def isEnabled(self):
-    return self._isEnabled
-  
-  def setEnabled(self, isEnabled):
-    self._isEnabled = isEnabled
-  
-  def setValidator(self, validator):
-    """
-    Custom function used to check that a value is valid before setting it.
-    This functor should accept two arguments: this option and the value we're
-    attempting to set. If its invalid then a ValueError with the reason is
-    expected.
-    
-    Arguments:
-      validator - functor for checking the validitiy of values we set
-    """
-    
-    self.validator = validator
-  
-  def setValue(self, value):
-    """
-    Attempts to set our value. If a validator has been set then we first check
-    if it's alright, raising a ValueError with the reason if not.
-    
-    Arguments:
-      value - value we're attempting to set
-    """
-    
-    if self.validator: self.validator(self, value)
-    self.value = value
-  
-  def getLabel(self, prefix = ""):
-    return prefix + CONFIG["wizard.label.%s" % self.group].get(self.key, "")
-  
-  def getDescription(self, width, prefix = ""):
-    if not self.descriptionCache or self.descriptionCacheArg != width:
-      optDescription = CONFIG["wizard.description.%s" % self.group].get(self.key, "")
-      self.descriptionCache = _splitStr(optDescription, width)
-      self.descriptionCacheArg = width
-    
-    return [prefix + line for line in self.descriptionCache]
-
-class ToggleConfigOption(ConfigOption):
-  """
-  Configuration option representing a boolean.
-  """
-  
-  def __init__(self, key, group, default, trueLabel, falseLabel):
-    ConfigOption.__init__(self, key, group, default)
-    self.trueLabel = trueLabel
-    self.falseLabel = falseLabel
-  
-  def getDisplayValue(self):
-    return self.trueLabel if self.value else self.falseLabel
-  
-  def toggle(self):
-    # This isn't really here to validate the value (after all this is a
-    # boolean, the options are limited!), but rather give a method for functors
-    # to be triggered when selected.
-    
-    if self.validator: self.validator(self, not self.value)
-    self.value = not self.value
-
-def showWizard():
-  """
-  Provides a series of prompts, allowing the user to spawn a customized tor
-  instance.
-  """
-  
-  if not sysTools.isAvailable("tor"):
-    msg = "Unable to run the setup wizard. Is tor installed?"
-    log.log(log.WARN, msg)
-    return
-  
-  try:
-    torVersion = stem.version.get_system_tor_version()
-  except IOError, exc:
-    torVersion = None
-    log.log(log.INFO, "'tor --version' query failed: %s" % exc)
-  
-  relayType, config = None, {}
-  for option in Options.values():
-    if option == Options.DIVIDER:
-      config[option] = option
-      continue
-    
-    toggleValues = CONFIG["wizard.toggle"].get(option)
-    default = CONFIG["wizard.default"].get(option, "")
-    
-    if toggleValues:
-      if "," in toggleValues:
-        trueLabel, falseLabel = toggleValues.split(",", 1)
-      else: trueLabel, falseLabel = toggleValues, ""
-      
-      isSet = default.lower() == "true"
-      config[option] = ToggleConfigOption(option, "opt", isSet, trueLabel.strip(), falseLabel.strip())
-    else: config[option] = ConfigOption(option, "opt", default)
-  
-  # sets input validators
-  config[Options.BANDWIDTH].setValidator(_relayRateValidator)
-  config[Options.LIMIT].setValidator(_monthlyLimitValidator)
-  config[Options.BRIDGE1].setValidator(_bridgeDestinationValidator)
-  config[Options.BRIDGE2].setValidator(_bridgeDestinationValidator)
-  config[Options.BRIDGE3].setValidator(_bridgeDestinationValidator)
-  config[Options.REUSE].setValidator(_circDurationValidator)
-  
-  # enables custom policies when 'custom' is selected and disables otherwise
-  policyOpt = config[Options.POLICY]
-  customPolicies = [config[opt] for opt in CUSTOM_POLICIES]
-  policyOpt.setValidator(functools.partial(_toggleEnabledAction, customPolicies))
-  _toggleEnabledAction(customPolicies, policyOpt, policyOpt.getValue())
-  
-  lowPortsOpt = config[Options.LOWPORTS]
-  disclaimerNotice = [config[Options.NOTICE]]
-  lowPortsOpt.setValidator(functools.partial(_toggleEnabledAction, disclaimerNotice))
-  _toggleEnabledAction(disclaimerNotice, lowPortsOpt, lowPortsOpt.getValue())
-  
-  # enables bridge entries when "Use Bridges" is set and disables otherwise
-  useBridgeOpt = config[Options.BRIDGED]
-  bridgeEntries = [config[opt] for opt in BRIDGE_ENTRIES]
-  useBridgeOpt.setValidator(functools.partial(_toggleEnabledAction, bridgeEntries))
-  _toggleEnabledAction(bridgeEntries, useBridgeOpt, useBridgeOpt.getValue())
-  
-  # enables running at startup when 'Use System Instance' is deselected and
-  # disables otherwise
-  systemOpt = config[Options.SYSTEM]
-  startupOpt = [config[Options.STARTUP]]
-  systemOpt.setValidator(functools.partial(_toggleEnabledAction, startupOpt, True))
-  _toggleEnabledAction(startupOpt, systemOpt, not systemOpt.getValue())
-  
-  # remembers the last selection made on the type prompt page
-  controller = cli.controller.getController()
-  manager = controller.getTorManager()
-  relaySelection = RelayType.RESUME if manager.isTorrcAvailable() else RelayType.RELAY
-  
-  # excludes options that are either disabled or for a future tor version
-  disabledOpt = list(CONFIG["wizard.disabled"])
-  
-  for opt, optVersion in VERSION_REQUIREMENTS.items():
-    if torVersion is None or not torVersion.meets_requirements(optVersion):
-      disabledOpt.append(opt)
-  
-  # the port forwarding option would only work if tor-fw-helper is in the path
-  if not Options.PORTFORWARD in disabledOpt:
-    if not sysTools.isAvailable("tor-fw-helper"):
-      disabledOpt.append(Options.PORTFORWARD)
-  
-  # If we haven't run 'resources/torrcOverride/override.py --init' or lack
-  # permissions then we aren't able to deal with the system wide tor instance.
-  # Also drop the option if we aren't installed since override.py won't be at
-  # the expected path.
-  if not os.path.exists(os.path.dirname(SYSTEM_DROP_PATH)) or not os.path.exists(OVERRIDE_SCRIPT):
-    disabledOpt.append(Options.SYSTEM)
-  
-  # TODO: The STARTUP option is currently disabled in the 'settings.cfg', and I
-  # don't currently have plans to implement it (it would be a big pita, and the
-  # tor deb already handles it). *If* it is implemented then I'd limit support
-  # for the option to Debian and Ubuntu to start with, via the following...
-  
-  # Running at startup is currently only supported for Debian and Ubuntu.
-  # Patches welcome for supporting other platforms.
-  #if not platform.dist()[0] in ("debian", "Ubuntu"):
-  #  disabledOpt.append(Options.STARTUP)
-  
-  while True:
-    if relayType == None:
-      selection = promptRelayType(relaySelection)
-      
-      if selection == CANCEL: break
-      elif selection == RelayType.RESUME:
-        if not manager.isManaged(torTools.getConn()):
-          manager.startManagedInstance()
-        
-        break
-      else: relayType, relaySelection = selection, selection
-    else:
-      selection = promptConfigOptions(relayType, config, disabledOpt)
-      
-      if selection == BACK: relayType = None
-      elif selection == CANCEL: break
-      elif selection == NEXT:
-        generatedTorrc = getTorrc(relayType, config, disabledOpt)
-        
-        torrcLocation = manager.getTorrcPath()
-        isSystemReplace = not Options.SYSTEM in disabledOpt and config[Options.SYSTEM].getValue()
-        if isSystemReplace: torrcLocation = SYSTEM_DROP_PATH
-        
-        controller.redraw()
-        confirmationSelection = showConfirmationDialog(generatedTorrc, torrcLocation)
-        
-        if confirmationSelection == NEXT:
-          log.log(log.INFO, "Writing torrc to '%s':\n%s" % (torrcLocation, generatedTorrc))
-          
-          # if the torrc already exists then save it to a _bak file
-          isBackedUp = False
-          if os.path.exists(torrcLocation) and not isSystemReplace:
-            try:
-              shutil.copy(torrcLocation, torrcLocation + "_bak")
-              isBackedUp = True
-            except IOError, exc:
-              log.log(log.WARN, "Unable to backup the torrc: %s" % exc)
-          
-          # writes the torrc contents
-          try:
-            torrcFile = open(torrcLocation, "w")
-            torrcFile.write(generatedTorrc)
-            torrcFile.close()
-          except IOError, exc:
-            log.log(log.ERR, "Unable to make torrc: %s" % exc)
-            break
-          
-          # logs where we placed the torrc
-          msg = "Tor configuration placed at '%s'" % torrcLocation
-          if isBackedUp:
-            msg += " (the previous torrc was moved to 'torrc_bak')"
-          
-          log.log(log.NOTICE, msg)
-          
-          dataDir = cli.controller.getController().getDataDirectory()
-          
-          pathPrefix = os.path.dirname(sys.argv[0])
-          if pathPrefix and not pathPrefix.endswith("/"):
-            pathPrefix = pathPrefix + "/"
-          
-          # copies exit notice into data directory if it's being used
-          if Options.NOTICE in RelayOptions[relayType] and config[Options.NOTICE].getValue() and config[Options.LOWPORTS].getValue():
-            src = "%sresources/exitNotice" % pathPrefix
-            dst = "%sexitNotice" % dataDir
-            
-            if not os.path.exists(dst):
-              shutil.copytree(src, dst)
-            
-            # providing a notice that it has sections specific to us operators
-            msg = "Exit notice placed at '%s/index.html'. Some of the sections are specific to US relay operators so please change the \"FIXME\" sections if this is inappropriate." % dst
-            log.log(log.NOTICE, msg)
-          
-          runCommand, exitCode = None, 1
-          
-          if isSystemReplace:
-            # running override.py needs root so...
-            # - if running as root (bad user, no biscuit!) then run it directly
-            # - if the setuid binary is available at '/usr/bin/torrc-override'
-            #   then use that
-            # - attempt sudo in case passwordless sudo is available
-            # - if all of the above fail then log instructions
-            
-            if os.geteuid() == 0: runCommand = OVERRIDE_SCRIPT
-            elif os.path.exists(OVERRIDE_SETUID_SCRIPT): runCommand = OVERRIDE_SETUID_SCRIPT
-            else:
-              # The -n argument to sudo is *supposed* to be available starting
-              # with 1.7.0 [1] however this is a dirty lie (Ubuntu 9.10 uses
-              # 1.7.0 and even has the option in its man page, but it doesn't
-              # work). Instead checking for version 1.7.1.
-              #
-              # [1] http://www.sudo.ws/pipermail/sudo-users/2009-January/003889.html
-              
-              sudoVersionResult = sysTools.call("sudo -V")
-              
-              # version output looks like "Sudo version 1.7.2p7"
-              if len(sudoVersionResult) == 1 and sudoVersionResult[0].count(" ") >= 2:
-                versionNum = 0
-                
-                for comp in sudoVersionResult[0].split(" ")[2].split("."):
-                  if comp and comp[0].isdigit():
-                    versionNum = (10 * versionNum) + int(comp)
-                  else:
-                    # invalid format
-                    log.log(log.INFO, "Unrecognized sudo version string: %s" % sudoVersionResult[0])
-                    versionNum = 0
-                    break
-                
-                if versionNum >= 171:
-                  runCommand = "sudo -n %s" % OVERRIDE_SCRIPT
-                else:
-                  log.log(log.INFO, "Insufficient sudo version for the -n argument")
-            
-            if runCommand: exitCode = os.system("%s > /dev/null 2>&1" % runCommand)
-            
-            if exitCode != 0:
-              msg = "Tor needs root permissions to replace the system wide torrc. To continue...\n- open another terminal\n- run \"sudo %s\"\n- press 'x' here to tell tor to reload" % OVERRIDE_SCRIPT
-              log.log(log.NOTICE, msg)
-            else: torTools.getConn().reload()
-          elif manager.isTorrcAvailable():
-            # If we're connected to a managed instance then just need to
-            # issue a sighup to pick up the new settings. Otherwise starts
-            # a new tor instance.
-            
-            conn = torTools.getConn()
-            if manager.isManaged(conn): conn.reload()
-            else: manager.startManagedInstance()
-          else:
-            # If we don't have permissions to run the torrc we just made then
-            # makes a shell script they can run as root to start tor.
-            
-            src = "%sresources/startTor" % pathPrefix
-            dst = "%sstartTor" % dataDir
-            if not os.path.exists(dst): shutil.copy(src, dst)
-            
-            msg = "Tor needs root permissions to start with this configuration (it will drop itself to the current user afterward). To continue...\n- open another terminal\n- run \"sudo %s\"\n- press 'r' here to tell arm to reconnect" % dst
-            log.log(log.NOTICE, msg)
-          
-          break
-        elif confirmationSelection == CANCEL: break
-    
-    # redraws screen to clear away the dialog we just showed
-    cli.controller.getController().redraw()
-
-def promptRelayType(initialSelection):
-  """
-  Provides a prompt for selecting the general role we'd like Tor to run with.
-  This returns a RelayType enumeration for the selection, or CANCEL if the
-  dialog was canceled.
-  """
-  
-  options = [ConfigOption(opt, "role", opt) for opt in RelayType.values()]
-  options.append(ConfigOption(CANCEL, "general", CANCEL))
-  selection = RelayType.indexOf(initialSelection)
-  height = 28
-  
-  # drops the resume option if it isn't applicable
-  control = cli.controller.getController()
-  if not control.getTorManager().isTorrcAvailable():
-    options.pop(0)
-    height -= 3
-    selection -= 1
-  
-  popup, _, _ = cli.popups.init(height, 58)
-  if not popup: return
-  
-  try:
-    popup.win.box()
-    curses.cbreak()
-    
-    # provides the welcoming message
-    topContent = _splitStr(CONFIG["wizard.message.role"], 54)
-    for i in range(len(topContent)):
-      popup.addstr(i + 1, 2, topContent[i], curses.A_BOLD | uiTools.getColor(MSG_COLOR))
-    
-    while True:
-      y, offset = len(topContent) + 1, 0
-      
-      for opt in options:
-        optionFormat = uiTools.getColor(MSG_COLOR)
-        if opt == options[selection]: optionFormat |= curses.A_STANDOUT
-        
-        # Curses has a weird bug where there's a one-pixel alignment
-        # difference between bold and regular text, so it looks better
-        # to render the whitespace here as not being bold.
-        
-        offset += 1
-        label = opt.getLabel(" ")
-        popup.addstr(y + offset, 2, label, optionFormat | curses.A_BOLD)
-        popup.addstr(y + offset, 2 + len(label), " " * (54 - len(label)), optionFormat)
-        offset += 1
-        
-        for line in opt.getDescription(52, " "):
-          popup.addstr(y + offset, 2, uiTools.padStr(line, 54), optionFormat)
-          offset += 1
-      
-      popup.win.refresh()
-      key = control.getScreen().getch()
-      
-      if key == curses.KEY_UP: selection = (selection - 1) % len(options)
-      elif key == curses.KEY_DOWN: selection = (selection + 1) % len(options)
-      elif uiTools.isSelectionKey(key): return options[selection].getValue()
-      elif key in (27, ord('q'), ord('Q')): return CANCEL # esc or q - cancel
-  finally:
-    cli.popups.finalize()
-
-def promptConfigOptions(relayType, config, disabledOpt):
-  """
-  Prompts the user for the configuration of an internal relay.
-  """
-  
-  topContent = _splitStr(CONFIG.get("wizard.message.%s" % relayType.lower(), ""), 54)
-  
-  options = [config[opt] for opt in RelayOptions[relayType] if not opt in disabledOpt]
-  options.append(Options.DIVIDER)
-  options.append(ConfigOption(BACK, "general", "(to role selection)"))
-  options.append(ConfigOption(NEXT, "general", "(to confirm options)"))
-  
-  popupHeight = len(topContent) + len(options) + DESC_SIZE + 5
-  popup, _, _ = cli.popups.init(popupHeight, 58)
-  if not popup: return
-  control = cli.controller.getController()
-  key, selection = 0, 0
-  
-  try:
-    curses.cbreak()
-    
-    while True:
-      popup.win.erase()
-      popup.win.box()
-      
-      # provides the description for the relay type
-      for i in range(len(topContent)):
-        popup.addstr(i + 1, 2, topContent[i], curses.A_BOLD | uiTools.getColor(MSG_COLOR))
-      
-      y, offset = len(topContent) + 1, 0
-      for opt in options:
-        if opt == Options.DIVIDER:
-          offset += 1
-          continue
-        
-        optionFormat = opt.getDisplayAttr()
-        if opt == options[selection]: optionFormat |= curses.A_STANDOUT
-        
-        offset, indent = offset + 1, 0
-        if opt.getKey() in CONFIG["wizard.suboptions"]:
-          # If the next entry is also a suboption then show a 'T', otherwise
-          # end the bracketing.
-          
-          bracketChar, nextIndex = curses.ACS_LLCORNER, options.index(opt) + 1
-          if nextIndex < len(options) and isinstance(options[nextIndex], ConfigOption):
-            if options[nextIndex].getKey() in CONFIG["wizard.suboptions"]:
-              bracketChar = curses.ACS_LTEE
-          
-          popup.addch(y + offset, 3, bracketChar, opt.getDisplayAttr())
-          popup.addch(y + offset, 4, curses.ACS_HLINE, opt.getDisplayAttr())
-          
-          indent = 3
-        
-        labelFormat = " %%-%is%%s" % (30 - indent)
-        label = labelFormat % (opt.getLabel(), opt.getDisplayValue())
-        popup.addstr(y + offset, 2 + indent, uiTools.padStr(label, 54 - indent), optionFormat)
-        
-        # little hack to make "Block" policies red
-        if opt != options[selection] and not opt.getValue() and opt.getKey() in CUSTOM_POLICIES:
-          optionFormat = curses.A_BOLD | uiTools.getColor("red")
-          popup.addstr(y + offset, 33, opt.getDisplayValue(), optionFormat)
-      
-      # divider between the options and description
-      offset += 2
-      popup.addch(y + offset, 0, curses.ACS_LTEE)
-      popup.addch(y + offset, popup.getWidth() - 1, curses.ACS_RTEE)
-      popup.hline(y + offset, 1, popup.getWidth() - 2)
-      
-      # description for the currently selected option
-      for line in options[selection].getDescription(54, " "):
-        offset += 1
-        popup.addstr(y + offset, 1, line, uiTools.getColor(MSG_COLOR))
-      
-      popup.win.refresh()
-      key = control.getScreen().getch()
-      
-      if key in (curses.KEY_UP, curses.KEY_DOWN):
-        posOffset = -1 if key == curses.KEY_UP else 1
-        selection = (selection + posOffset) % len(options)
-        
-        # skips disabled options and dividers
-        while options[selection] == Options.DIVIDER or not options[selection].isEnabled():
-          selection = (selection + posOffset) % len(options)
-      elif uiTools.isSelectionKey(key):
-        if selection == len(options) - 2: return BACK # selected back
-        elif selection == len(options) - 1: return NEXT # selected next
-        elif isinstance(options[selection], ToggleConfigOption):
-          options[selection].toggle()
-        else:
-          newValue = popup.getstr(y + selection + 1, 33, options[selection].getValue(), curses.A_STANDOUT | uiTools.getColor(OPTION_COLOR), 23)
-          if newValue:
-            try: options[selection].setValue(newValue.strip())
-            except ValueError, exc:
-              cli.popups.showMsg(str(exc), 3)
-              cli.controller.getController().redraw()
-      elif key in (27, ord('q'), ord('Q')): return CANCEL
-  finally:
-    cli.popups.finalize()
-
-def getTorrc(relayType, config, disabledOpt):
-  """
-  Provides the torrc generated for the given options.
-  """
-  
-  # TODO: When Robert's 'ownership' feature is available take advantage of it
-  # for the RSHUTDOWN and CSHUTDOWN options.
-  
-  pathPrefix = os.path.dirname(sys.argv[0])
-  if pathPrefix and not pathPrefix.endswith("/"):
-    pathPrefix = pathPrefix + "/"
-  
-  templateFile = open("%s%s" % (pathPrefix, TORRC_TEMPLATE), "r")
-  template = templateFile.readlines()
-  templateFile.close()
-  
-  # generates the options the template expects
-  templateOptions = {}
-  
-  for key, value in config.items():
-    if isinstance(value, ConfigOption):
-      value = value.getValue()
-    
-    if key == Options.BANDWIDTH and value.endswith("/s"):
-      # truncates "/s" from the rate for RelayBandwidthRate entry
-      value = value[:-2]
-    elif key == Options.NOTICE:
-      # notice option is only applied if using low ports
-      value &= config[Options.LOWPORTS].getValue()
-    elif key == Options.CONTACT and _isEmailAddress(value):
-      # obscures the email address
-      value = _obscureEmailAddress(value)
-    
-    templateOptions[key.upper()] = value
-  
-  templateOptions[relayType.upper()] = True
-  templateOptions["LOW_PORTS"] = config[Options.LOWPORTS].getValue()
-  
-  # uses double the relay rate for bursts
-  bwOpt = Options.BANDWIDTH.upper()
-  
-  if templateOptions[bwOpt] != TOR_DEFAULTS[Options.BANDWIDTH]:
-    relayRateComp = templateOptions[bwOpt].split(" ")
-    templateOptions["BURST"] = "%i %s" % (int(relayRateComp[0]) * 2, " ".join(relayRateComp[1:]))
-  
-  # paths for our tor related resources
-  
-  dataDir = cli.controller.getController().getDataDirectory()
-  templateOptions["NOTICE_PATH"] = "%sexitNotice/index.html" % dataDir
-  templateOptions["LOG_ENTRY"] = "notice file %stor_log" % dataDir
-  templateOptions["USERNAME"] = getpass.getuser()
-  
-  # using custom data directory, unless this is for a system wide instance
-  if not config[Options.SYSTEM].getValue() or Options.SYSTEM in disabledOpt:
-    templateOptions["DATA_DIR"] = "%stor_data" % dataDir
-  
-  policyCategories = []
-  if not config[Options.POLICY].getValue():
-    policyCategories = ["web", "mail", "im", "misc"]
-  else:
-    if config[Options.WEBSITES].getValue(): policyCategories.append("web")
-    if config[Options.EMAIL].getValue(): policyCategories.append("mail")
-    if config[Options.IM].getValue(): policyCategories.append("im")
-    if config[Options.MISC].getValue(): policyCategories.append("misc")
-  
-  # uses the CSHUTDOWN or RSHUTDOWN option based on if we're running as a
-  # client or not
-  if relayType == RelayType.CLIENT:
-    templateOptions["SHUTDOWN"] = templateOptions[Options.CSHUTDOWN.upper()]
-  else:
-    templateOptions["SHUTDOWN"] = templateOptions[Options.RSHUTDOWN.upper()]
-  
-  if policyCategories:
-    isEncryptedOnly = not config[Options.PLAINTEXT].getValue()
-    
-    policyLines = []
-    for category in ["all"] + policyCategories:
-      # shows a comment at the start of the section saying what it's for
-      topicComment = CONFIG["port.category"].get(category)
-      if topicComment:
-        for topicComp in _splitStr(topicComment, 78):
-          policyLines.append("# " + topicComp)
-      
-      for portEntry in CONFIG.get("port.exit.%s" % category, []):
-        # port entry might be an individual port or a range
-        
-        if isEncryptedOnly and (not portEntry in CONFIG["port.encrypted"]):
-          continue # opting to not include plaintext port and ranges
-        
-        if "-" in portEntry:
-          # if this is a range then use the first port's description
-          comment = connections.PORT_USAGE.get(portEntry[:portEntry.find("-")])
-        else: comment = connections.PORT_USAGE.get(portEntry)
-        
-        entry = "ExitPolicy accept *:%s" % portEntry
-        if comment: policyLines.append("%-30s# %s" % (entry, comment))
-        else: policyLines.append(entry)
-      
-      if category != policyCategories[-1]:
-        policyLines.append("") # newline to split categories
-    
-    templateOptions["EXIT_POLICY"] = "\n".join(policyLines)
-  
-  # includes input bridges
-  bridgeLines = []
-  for bridgeOpt in [Options.BRIDGE1, Options.BRIDGE2, Options.BRIDGE3]:
-    bridgeValue = config[bridgeOpt].getValue()
-    if bridgeValue: bridgeLines.append("Bridge %s" % bridgeValue)
-  
-  templateOptions["BRIDGES"] = "\n".join(bridgeLines)
-  
-  # removes disabled options
-  for opt in disabledOpt:
-    if opt.upper() in templateOptions:
-      del templateOptions[opt.upper()]
-  
-  startupOpt = Options.STARTUP.upper()
-  if not config[Options.STARTUP].isEnabled() and startupOpt in templateOptions:
-    del templateOptions[startupOpt]
-  
-  # removes options if they match the tor defaults
-  for opt in TOR_DEFAULTS:
-    if templateOptions[opt.upper()] == TOR_DEFAULTS[opt]:
-      del templateOptions[opt.upper()]
-  
-  return torConfig.renderTorrc(template, templateOptions)
-
-def showConfirmationDialog(torrcContents, torrcLocation):
-  """
-  Shows a confirmation dialog with the given torrc contents, returning CANCEL,
-  NEXT, or BACK based on the selection.
-  
-  Arguments:
-    torrcContents - lines of torrc contents to be presented
-    torrcLocation - path where the torrc will be placed
-  """
-  
-  torrcLines = torrcContents.split("\n")
-  options = ["Cancel", "Back to Setup", "Start Tor"]
-  
-  control = cli.controller.getController()
-  screenHeight = control.getScreen().getmaxyx()[0]
-  stickyHeight = sum([stickyPanel.getHeight() for stickyPanel in control.getStickyPanels()])
-  isScrollbarVisible = len(torrcLines) + stickyHeight + 5 > screenHeight
-  
-  xOffset = 3 if isScrollbarVisible else 0
-  popup, width, height = cli.popups.init(len(torrcLines) + 5, 84 + xOffset)
-  if not popup: return False
-  
-  try:
-    scroll, selection = 0, 2
-    curses.cbreak()
-    
-    while True:
-      popup.win.erase()
-      popup.win.box()
-      
-      # renders the scrollbar
-      if isScrollbarVisible:
-        popup.addScrollBar(scroll, scroll + height - 5, len(torrcLines), 1, height - 4, 1)
-      
-      # shows the path where the torrc will be placed
-      titleMsg = "The following will be placed at '%s':" % torrcLocation
-      popup.addstr(0, 0, titleMsg, curses.A_STANDOUT)
-      
-      # renders the torrc contents
-      for i in range(scroll, min(len(torrcLines), height - 5 + scroll)):
-        # parses the argument and comment from options
-        option, arg, comment = uiTools.cropStr(torrcLines[i], width - 4 - xOffset), "", ""
-        
-        div = option.find("#")
-        if div != -1: option, comment = option[:div], option[div:]
-        
-        div = option.strip().find(" ")
-        if div != -1: option, arg = option[:div], option[div:]
-        
-        drawX = 2 + xOffset
-        popup.addstr(i + 1 - scroll, drawX, option, curses.A_BOLD | uiTools.getColor("green"))
-        drawX += len(option)
-        popup.addstr(i + 1 - scroll, drawX, arg, curses.A_BOLD | uiTools.getColor("cyan"))
-        drawX += len(arg)
-        popup.addstr(i + 1 - scroll, drawX, comment, uiTools.getColor("white"))
-      
-      # divider between the torrc and the options
-      popup.addch(height - 4, 0, curses.ACS_LTEE)
-      popup.addch(height - 4, width, curses.ACS_RTEE)
-      popup.hline(height - 4, 1, width - 1)
-      if isScrollbarVisible: popup.addch(height - 4, 2, curses.ACS_BTEE)
-      
-      # renders the selection options
-      confirmationMsg = "Run tor with the above configuration?"
-      popup.addstr(height - 3, width - len(confirmationMsg) - 1, confirmationMsg, uiTools.getColor("green") | curses.A_BOLD)
-      
-      drawX = width - 1
-      for i in range(len(options) - 1, -1, -1):
-        optionLabel = " %s " % options[i]
-        drawX -= (len(optionLabel) + 4)
-        
-        selectionFormat = curses.A_STANDOUT if i == selection else curses.A_NORMAL
-        popup.addstr(height - 2, drawX, "[", uiTools.getColor("green"))
-        popup.addstr(height - 2, drawX + 1, optionLabel, uiTools.getColor("green") | selectionFormat | curses.A_BOLD)
-        popup.addstr(height - 2, drawX + len(optionLabel) + 1, "]", uiTools.getColor("green"))
-        
-        drawX -= 1 # space gap between the options
-      
-      popup.win.refresh()
-      key = cli.controller.getController().getScreen().getch()
-      
-      if key == curses.KEY_LEFT:
-        selection = (selection - 1) % len(options)
-      elif key == curses.KEY_RIGHT:
-        selection = (selection + 1) % len(options)
-      elif uiTools.isScrollKey(key):
-        scroll = uiTools.getScrollPosition(key, scroll, height - 5, len(torrcLines))
-      elif uiTools.isSelectionKey(key):
-        if selection == 0: return CANCEL
-        elif selection == 1: return BACK
-        else: return NEXT
-      elif key in (27, ord('q'), ord('Q')): return CANCEL
-  finally:
-    cli.popups.finalize()
-
-def _splitStr(msg, width):
-  """
-  Splits a string into substrings of a given length.
-  
-  Arguments:
-    msg   - string to be broken up
-    width - max length of any returned substring
-  """
-  
-  results = []
-  while msg:
-    msgSegment, msg = uiTools.cropStr(msg, width, None, endType = None, getRemainder = True)
-    if not msgSegment: break # happens if the width is less than the first word
-    results.append(msgSegment.strip())
-  
-  return results
-
-def _isEmailAddress(address):
-  """
-  True if the input is an email address, false otherwise.
-  """
-  
-  # just checks if there's an '@' and '.' in the input w/o whitespace
-  emailMatcher = re.compile("\S*@\S*\.\S*")
-  return emailMatcher.match(address)
-
-def _obscureEmailAddress(address):
-  """
-  Makes some effort to obscure an email address while keeping it readable.
-  
-  Arguments:
-    address - actual email address
-  """
-  
-  address = _obscureChar(address, '@', (_randomCase("at"), ))
-  address = _obscureChar(address, '.', (_randomCase("dot"), ))
-  return address
-
-def _randomCase(word):
-  """
-  Provides a word back with the case of its letters randomized.
-  
-  Arguments:
-    word - word for which to randomize the case
-  """
-  
-  result = []
-  for letter in word:
-    result.append(random.choice((letter.lower(), letter.upper())))
-  
-  return "".join(result)
-
-def _obscureChar(inputText, target, options):
-  """
-  Obscures the given character from the input, replacing it with something
-  from a set of options and bracketing the selection.
-  
-  Arguments:
-    inputText - text to be obscured
-    target    - character to be replaced
-    options   - replacement options for the character
-  """
-  
-  leftSpace = random.randint(0, 3)
-  leftFill = random.choice((' ', '_', '-', '=', '<'))
-  
-  rightSpace = random.randint(0, 3)
-  rightFill = random.choice((' ', '_', '-', '=', '>'))
-  
-  bracketLeft, bracketRight = random.choice(BRACKETS)
-  optSelection = random.choice(options)
-  replacement = "".join((bracketLeft, leftFill * leftSpace, optSelection, rightFill * rightSpace, bracketRight))
-  
-  return inputText.replace(target, replacement)
-
-def _toggleEnabledAction(toggleOptions, option, value, invert = False):
-  """
-  Enables or disables custom exit policy options based on our selection.
-  
-  Arguments:
-    toggleOptions - configuration options to be toggled to match our our
-                    selection (ie, true -> enabled, false -> disabled)
-    options       - our config option
-    value         - the value we're being set to
-    invert        - inverts selection if true
-  """
-  
-  if invert: value = not value
-  
-  for opt in toggleOptions:
-    opt.setEnabled(value)
-
-def _relayRateValidator(option, value):
-  if value.count(" ") != 1:
-    msg = "This should be a rate measurement (for instance, \"5 MB/s\")"
-    raise ValueError(msg)
-  
-  rate, units = value.split(" ", 1)
-  acceptedUnits = ("KB/s", "MB/s", "GB/s")
-  if not rate.isdigit():
-    raise ValueError("'%s' isn't an integer" % rate)
-  elif not units in acceptedUnits:
-    msg = "'%s' is an invalid rate, options include \"%s\"" % (units, "\", \"".join(acceptedUnits))
-    raise ValueError(msg)
-  elif (int(rate) < 20 and units == "KB/s") or int(rate) < 1:
-    raise ValueError("To be usable as a relay the rate must be at least 20 KB/s")
-
-def _monthlyLimitValidator(option, value):
-  if value.count(" ") != 1:
-    msg = "This should be a traffic size (for instance, \"5 MB\")"
-    raise ValueError(msg)
-  
-  rate, units = value.split(" ", 1)
-  acceptedUnits = ("MB", "GB", "TB")
-  if not rate.isdigit():
-    raise ValueError("'%s' isn't an integer" % rate)
-  elif not units in acceptedUnits:
-    msg = "'%s' is an invalid unit, options include \"%s\"" % (units, "\", \"".join(acceptedUnits))
-    raise ValueError(msg)
-  elif (int(rate) < 50 and units == "MB") or int(rate) < 1:
-    raise ValueError("To be usable as a relay's monthly limit should be at least 50 MB")
-
-def _bridgeDestinationValidator(option, value):
-  if value.count(":") != 1:
-    raise ValueError("Bridges are of the form '<ip address>:<port>'")
-  
-  ipAddr, port = value.split(":", 1)
-  if not connections.isValidIpAddress(ipAddr):
-    raise ValueError("'%s' is not a valid ip address" % ipAddr)
-  elif not port.isdigit() or int(port) < 0 or int(port) > 65535:
-    raise ValueError("'%s' isn't a valid port number" % port)
-
-def _circDurationValidator(option, value):
-  if value.count(" ") != 1:
-    msg = "This should be a time measurement (for instance, \"10 minutes\")"
-    raise ValueError(msg)
-  
-  rate, units = value.split(" ", 1)
-  acceptedUnits = ("minute", "minutes", "hour", "hours")
-  if not rate.isdigit():
-    raise ValueError("'%s' isn't an integer" % rate)
-  elif not units in acceptedUnits:
-    msg = "'%s' is an invalid rate, options include \"minutes\" or \"hours\""
-    raise ValueError(msg)
-  elif (int(rate) < 5 and units in ("minute", "minutes")) or int(rate) < 1:
-    raise ValueError("This would cause high network load, don't set this to less than five minutes")
-
diff --git a/src/resources/exitNotice/how_tor_works_thumb.png b/src/resources/exitNotice/how_tor_works_thumb.png
deleted file mode 100644
index b9ffe0d..0000000
Binary files a/src/resources/exitNotice/how_tor_works_thumb.png and /dev/null differ
diff --git a/src/resources/exitNotice/index.html b/src/resources/exitNotice/index.html
deleted file mode 100644
index 7475984..0000000
--- a/src/resources/exitNotice/index.html
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
-<title>This is a Tor Exit Router</title>
-
-<!--
-
-This notice is intended to be placed on a virtual host for a domain that
-your Tor exit node IP reverse resolves to so that people who may be about
-to file an abuse complaint would check it first before bothering you or
-your ISP. Ex:
-http://tor-exit.yourdomain.org or http://tor-readme.yourdomain.org.
-
-This type of setup has proven very effective at reducing abuse complaints
-for exit node operators.
-
-There are a few places in this document that you may want to customize.
-They are marked with FIXME.
-
-Notice Source:
-https://gitweb.torproject.org/tor.git/blob_plain/HEAD:/contrib/tor-exit-notice.html
-
--->
-
-</head>
-<body>
-
-<p style="text-align:center; font-size:xx-large; font-weight:bold">This is a
-Tor Exit Router</p>
-
-<p>
-Most likely you are accessing this website because you had some issue with
-the traffic coming from this IP. This router is part of the <a
-href="https://www.torproject.org/">Tor Anonymity Network</a>, which is
-dedicated to <a href="https://www.torproject.org/about/overview">providing
-privacy</a> to people who need it most: average computer users. This
-router IP should be generating no other traffic, unless it has been
-compromised.</p>
-
-
-<p style="text-align:center">
-<a href="https://www.torproject.org/about/overview">
-<img src="how_tor_works_thumb.png" alt="How Tor works" style="border-style:none"/>
-</a></p>
-
-<p>
-Tor sees use by <a href="https://www.torproject.org/about/torusers">many
-important segments of the population</a>, including whistle blowers,
-journalists, Chinese dissidents skirting the Great Firewall and oppressive
-censorship, abuse victims, stalker targets, the US military, and law
-enforcement, just to name a few.  While Tor is not designed for malicious
-computer users, it is true that they can use the network for malicious ends.
-In reality however, the actual amount of <a
-href="https://www.torproject.org/docs/faq-abuse">abuse</a> is quite low. This
-is largely because criminals and hackers have significantly better access to
-privacy and anonymity than do the regular users whom they prey upon. Criminals
-can and do <a
-href="http://voices.washingtonpost.com/securityfix/2008/08/web_fraud_20_tools.html">build,
-sell, and trade</a> far larger and <a
-href="http://voices.washingtonpost.com/securityfix/2008/08/web_fraud_20_distributing_your.html">more
-powerful networks</a> than Tor on a daily basis. Thus, in the mind of this
-operator, the social need for easily accessible censorship-resistant private,
-anonymous communication trumps the risk of unskilled bad actors, who are
-almost always more easily uncovered by traditional police work than by
-extensive monitoring and surveillance anyway.</p>
-
-<p>
-In terms of applicable law, the best way to understand Tor is to consider it a
-network of routers operating as common carriers, much like the Internet
-backbone. However, unlike the Internet backbone routers, Tor routers
-explicitly do not contain identifiable routing information about the source of
-a packet, and no single Tor node can determine both the origin and destination
-of a given transmission.</p>
-
-<p>
-As such, there is little the operator of this router can do to help you track
-the connection further. This router maintains no logs of any of the Tor
-traffic, so there is little that can be done to trace either legitimate or
-illegitimate traffic (or to filter one from the other).  Attempts to
-seize this router will accomplish nothing.</p>
-
-<!-- FIXME: US-Only section. Remove if you are a non-US operator -->
-
-<p>
-Furthermore, this machine also serves as a carrier of email, which means that
-its contents are further protected under the ECPA. <a
-href="http://www4.law.cornell.edu/uscode/html/uscode18/usc_sec_18_00002707----000-.html">18
-USC 2707</a> explicitly allows for civil remedies ($1000/account
-<i><b>plus</b></i>  legal fees)
-in the event of a seizure executed without good faith or probable cause (it
-should be clear at this point that traffic with this originating IP address
-should not constitute probable cause to seize the machine). Similar
-considerations exist for 1st amendment content on this machine.</p>
-
-<!-- FIXME: May or may not be US-only. Some non-US tor nodes have in
-     fact reported DMCA harassment... -->
-
-<p>
-If you are a representative of a company who feels that this router is being
-used to violate the DMCA, please be aware that this machine does not host or
-contain any illegal content. Also be aware that network infrastructure
-maintainers are not liable for the type of content that passes over their
-equipment, in accordance with <a
-href="http://www4.law.cornell.edu/uscode/html/uscode17/usc_sec_17_00000512----000-.html">DMCA
-"safe harbor" provisions</a>. In other words, you will have just as much luck
-sending a takedown notice to the Internet backbone providers. Please consult
-<a href="https://www.torproject.org/eff/tor-dmca-response">EFF's prepared
-response</a> for more information on this matter.</p>
-
-<p>For more information, please consult the following documentation:</p>
-
-<ol>
-<li><a href="https://www.torproject.org/about/overview">Tor Overview</a></li>
-<li><a href="https://www.torproject.org/docs/faq-abuse">Tor Abuse FAQ</a></li>
-<li><a href="https://www.torproject.org/eff/tor-legal-faq">Tor Legal FAQ</a></li>
-</ol>
-
-<p>
-That being said, if you still have a complaint about the router,  you may
-email the <a href="mailto:FIXME_YOUR_EMAIL_ADDRESS">maintainer</a>. If
-complaints are related to a particular service that is being abused, I will
-consider removing that service from my exit policy, which would prevent my
-router from allowing that traffic to exit through it. I can only do this on an
-IP+destination port basis, however. Common P2P ports are
-already blocked.</p>
-
-<p>
-You also have the option of blocking this IP address and others on
-the Tor network if you so desire. The Tor project provides a <a
-href="https://check.torproject.org/cgi-bin/TorBulkExitList.py">web service</a>
-to fetch a list of all IP addresses of Tor exit nodes that allow exiting to a
-specified IP:port combination, and an official <a
-href="https://www.torproject.org/tordnsel/dist/">DNSRBL</a> is also available to
-determine if a given IP address is actually a Tor exit server. Please
-be considerate
-when using these options. It would be unfortunate to deny all Tor users access
-to your site indefinitely simply because of a few bad apples.</p>
-
-</body>
-</html>
diff --git a/src/resources/startTor b/src/resources/startTor
deleted file mode 100755
index 812a75a..0000000
--- a/src/resources/startTor
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/sh
-
-# When binding to privileged ports the tor process needs to start with root
-# permissions, then lower the user it's running as afterward.
-
-# checks that we're running as root
-
-if [ "$(id -u)" != "0" ]; then
-  printf "This script needs root permissions to run. Try again with \"sudo ${0}\".\n\n"
-  exit 1
-fi
-
-# Checks that the torrc in this directory has a "User <username>" entry. If 
-# they ran the wizard multiple times then we might currently have a torrc
-# without it, causing this to run tor as root (... not what we wanted).
-
-torrcLoc=$( dirname "$0" )/torrc
-if ! `grep -q "^User " ${torrcLoc}`; then
-  printf "The tor configuration file (${torrcLoc}) doesn't lower its\n"
-  printf "permissions. You should only be using this script to run tor instances that\n"
-  printf "need root permissions to start.\n\n"
-  exit 1
-fi
-
-# starts the tor process
-
-tor --quiet -f $torrcLoc&
-
diff --git a/src/resources/torrcOverride/override.c b/src/resources/torrcOverride/override.c
deleted file mode 100644
index b989584..0000000
--- a/src/resources/torrcOverride/override.c
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// This is a very small C wrapper that invokes
-// $(DESTDIR)/usr/bin/tor-arm-replace-torrc.py to work around setuid scripting
-// issues on the Gnu/Linux operating system.
-//
-// We assume you have installed it as such for GROUP
-// "debian-arm" - This should ensure that only members of the GROUP group will
-// be allowed to run this program. When run this program will execute the
-// $(DESTDIR)/usr/bin/tor-arm-replace-torrc.py program and will run with the
-// uid and group as marked by the OS.
-//
-// Compile it like so:
-// 
-//  make
-//
-// Or by hand like so:
-//
-//  gcc -o tor-arm-replace-torrc tor-arm-replace-torrc.c
-// 
-// Make it useful like so:
-//
-//  chown root:debian-arm tor-arm-replace-torrc
-//  chmod 04750 tor-arm-replace-torrc
-//
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-//
-// If you place a user inside of the $GROUP - they are now able to reconfigure
-// Tor. This may lead them to do nasty things on your system. If you start Tor
-// as root,  you should consider that adding a user to $GROUP is similar to
-// giving those users root directly.
-//
-// This program was written simply to help a users who run arm locally and is
-// not required if arm is communicating with a remote Tor process.
-//
-// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-//
-//
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "tor-arm-replace-torrc.h"
-
-int main()
-{
-   return execve(TOR_ARM_REPLACE_TORRC, NULL, NULL);
-}
diff --git a/src/resources/torrcOverride/override.h b/src/resources/torrcOverride/override.h
deleted file mode 100644
index 8bb8869..0000000
--- a/src/resources/torrcOverride/override.h
+++ /dev/null
@@ -1 +0,0 @@
-#define TOR_ARM_REPLACE_TORRC /usr/share/arm/resources/torrcOverride/override.py
diff --git a/src/resources/torrcOverride/override.py b/src/resources/torrcOverride/override.py
deleted file mode 100755
index 8261eab..0000000
--- a/src/resources/torrcOverride/override.py
+++ /dev/null
@@ -1,363 +0,0 @@
-#!/usr/bin/python
-
-"""
-This overwrites the system wide torrc, located at /etc/tor/torrc, with the
-contents of the ARM_CONFIG_FILE. The system wide torrc is owned by root so
-this will effectively need root permissions and for us to be in GROUP.
-
-This file is completely unusable until we make a tor-arm user and perform
-other prep by running with the '--init' argument.
-
-After that's done this is meant to either be used by arm automatically after
-writing a torrc to ARM_CONFIG_FILE or by users manually. For arm to use this
-automatically you'll either need to...
-
-- compile override.c, setuid on the binary, and move it to your path
-  cd /usr/share/arm/resources/torrcOverride
-  make
-  chown root:tor-arm override
-  chmod 04750 override
-  mv override /usr/bin/torrc-override
-
-- allow passwordless sudo for this script
-  edit /etc/sudoers and add a line with:
-  <arm user> ALL= NOPASSWD: /usr/share/arm/resources/torrcOverride/override.py
-
-To perform this manually run:
-/usr/share/arm/resources/torrcOverride/override.py
-pkill -sighup tor
-"""
-
-import os
-import re
-import sys
-import grp
-import pwd
-import time
-import shutil
-import tempfile
-import signal
-
-USER = "tor-arm"
-GROUP = "tor-arm"
-TOR_CONFIG_FILE = "/etc/tor/torrc"
-ARM_CONFIG_FILE = "/var/lib/tor-arm/torrc"
-RUN_VERIFY = True # use 'tor --verify-config' to check the torrc
-
-# regex patterns for options the wizard may include
-WIZARD_OPT = ("^DataDirectory \S+$",
-              "^Log notice file \S+$",
-              "^ControlPort 9052$",
-              "^CookieAuthentication 1$",
-              "^RunAsDaemon 1$",
-              "^User \S+$",
-              "^ORPort (443|9001)$",
-              "^DirPort (80|9030)$",
-              "^Nickname ",
-              "^ContactInfo ",
-              "^BridgeRelay 1$",
-              "^PublishServerDescriptor 0$",
-              "^RelayBandwidthRate ",
-              "^RelayBandwidthBurst ",
-              "^AccountingMax ",
-              "^SocksPort 0$",
-              "^PortForwarding 1$",
-              "^ExitPolicy (accept|reject) \S+$",
-              "^DirPortFrontPage \S+$",
-              "^ClientOnly 1$",
-              "^MaxCircuitDirtiness ",
-              "^UseBridges 1$",
-              "^Bridge ")
-
-HELP_MSG = """Usage %s [OPTION]
-  Backup the system wide torrc (%s) and replace it with the
-  contents of %s.
-
-  --init            creates the necessary user and paths
-  --remove          reverts changes made with --init
-  --validate PATH   checks if the given file is wizard generated
-""" % (os.path.basename(sys.argv[0]), TOR_CONFIG_FILE, ARM_CONFIG_FILE)
-
-def init():
-  """
-  Performs system preparation needed for this script to run, adding the tor-arm
-  user and setting up paths/permissions.
-  """
-  
-  # the following is just here if we have a custom destination directory (which
-  # arm doesn't currently account for)
-  if not os.path.exists("/bin/"):
-    print "making '/bin'..."
-    os.mkdir("/bin")
-  
-  if not os.path.exists("/var/lib/tor-arm/"):
-    print "making '/var/lib/tor-arm'..."
-    os.makedirs("/var/lib/tor-arm")
-  
-  if not os.path.exists("/var/lib/tor-arm/torrc"):
-    print "making '/var/lib/tor-arm/torrc'..."
-    open("/var/lib/tor-arm/torrc", 'w').close()
-  
-  try: gid = grp.getgrnam(GROUP).gr_gid
-  except KeyError:
-    print "adding %s group..." % GROUP
-    os.system("addgroup --quiet --system %s" % GROUP)
-    gid = grp.getgrnam(GROUP).gr_gid
-    print "  done, gid: %s" % gid
-  
-  try: pwd.getpwnam(USER).pw_uid
-  except KeyError:
-    print "adding %s user..." % USER
-    os.system("adduser --quiet --ingroup %s --no-create-home --home /var/lib/tor-arm/ --shell /bin/sh --system %s" % (GROUP, USER))
-    uid = pwd.getpwnam(USER).pw_uid
-    print "  done, uid: %s" % uid
-  
-  os.chown("/bin", 0, 0)
-  os.chown("/var/lib/tor-arm", 0, gid)
-  os.chmod("/var/lib/tor-arm", 0750)
-  os.chown("/var/lib/tor-arm/torrc", 0, gid)
-  os.chmod("/var/lib/tor-arm/torrc", 0760)
-
-def remove():
-  """
-  Reverts the changes made by init, and also removes the optional
-  /bin/torrc-override binary if it exists.
-  """
-  
-  print "removing %s user..." % USER
-  os.system("deluser --quiet %s" % USER)
-  
-  print "removing %s group..." % GROUP
-  os.system("delgroup --quiet %s" % GROUP)
-  
-  if os.path.exists("/bin/torrc-override"):
-    try:
-      print "removing '/bin/torrc-override'..."
-      os.remove("/bin/torrc-override")
-    except OSError, exc:
-      print "  unsuccessful: %s" % exc
-  
-  if os.path.exists("/var/lib/tor-arm/"):
-    try:
-      print "removing '/var/lib/tor-arm'..."
-      shutil.rmtree("/var/lib/tor-arm/")
-    except Exception, exc:
-      print "  unsuccessful: %s" % exc
-
-def replaceTorrc():
-  # TODO: The setresgid and setresuid functions are only available in
-  # python 2.7 (arm aims for 2.5 compatability). I'm not spotting a method
-  # for setting the saved user id without it, though. :/
-  
-  majorVersion, minorVersion = sys.version_info[:2]
-  canSetSavedUid = majorVersion >= 3 or (majorVersion == 2 and minorVersion >= 7)
-  
-  orig_uid = os.getuid()
-  orig_euid = os.geteuid()
-  
-  # the USER and GROUP must exist on this system
-  try:
-    dropped_uid = pwd.getpwnam(USER).pw_uid
-    dropped_gid = grp.getgrnam(GROUP).gr_gid
-    dropped_euid, dropped_egid = dropped_uid, dropped_gid
-  except KeyError:
-    print "tor-arm user and group was not found, have you run this script with '--init'?"
-    exit(1)
-  
-  # if we're actually root, we skip this group check
-  # root can get away with all of this
-  if orig_uid != 0:
-    # check that the user is in GROUP
-    if not dropped_gid in os.getgroups():
-      print "Your user needs to be a member of the %s group for this to work" % GROUP
-      sys.exit(1)
-  
-  # drop to the unprivileged group, and lose the rest of the groups
-  os.setgid(dropped_gid)
-  os.setegid(dropped_egid)
-  
-  if canSetSavedUid:
-    # only usable in python 2.7 or later
-    os.setresgid(dropped_gid, dropped_egid, dropped_gid)
-  else:
-    os.setregid(dropped_gid, dropped_egid)
-  
-  os.setgroups([dropped_gid])
-  
-  # make a tempfile and write out the contents
-  try:
-    tf = tempfile.NamedTemporaryFile(delete=False) # uses mkstemp internally
-    
-    # allows our child process to write to tf.name (not only if their uid matches, not their gid) 
-    os.chown(tf.name, dropped_uid, orig_euid)
-  except:
-    print "We were unable to make a temporary file"
-    sys.exit(1)
-  
-  fork_pid = os.fork()
-  
-  # open the suspect config after we drop privs
-  # we assume the dropped privs are still enough to write to the tf
-  if (fork_pid == 0):
-    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
-    
-    # Drop privs forever in the child process
-    # I believe this drops os.setfsuid os.setfsgid stuff
-    # Clear all other supplemental groups for dropped_uid
-    os.setgroups([dropped_gid])
-    
-    if canSetSavedUid:
-      # only usable in python 2.7 or later
-      os.setresgid(dropped_gid, dropped_egid, dropped_gid)
-      os.setresuid(dropped_uid, dropped_euid, dropped_uid)
-    else:
-      os.setregid(dropped_gid, dropped_egid)
-      os.setreuid(dropped_uid, dropped_euid)
-    
-    os.setgid(dropped_gid)
-    os.setegid(dropped_egid)
-    os.setuid(dropped_uid)
-    os.seteuid(dropped_euid)
-    
-    try:
-      af = open(ARM_CONFIG_FILE) # this is totally unpriv'ed
-      
-      # ensure that the fd we opened has the properties we requrie
-      configStat = os.fstat(af.fileno()) # this happens on the unpriv'ed FD
-      if configStat.st_gid != dropped_gid:
-        print "Arm's configuration file (%s) must be owned by the group %s" % (ARM_CONFIG_FILE, GROUP)
-        sys.exit(1)
-      
-      # if everything checks out, we're as safe as we're going to get
-      armConfig = af.read(1024 * 1024) # limited read but not too limited
-      af.close()
-      tf.file.write(armConfig)
-      tf.flush()
-    except:
-      print "Unable to open the arm config as unpriv'ed user"
-      sys.exit(1)
-    finally:
-      tf.close()
-      sys.exit(0)
-  else:
-    # If we're here, we're in the parent waiting for the child's death
-    # man, unix is really weird...
-    _, status = os.waitpid(fork_pid, 0)
-  
-  if status != 0 or not os.path.exists(tf.name):
-    print "The child seems to have failed; exiting!"
-    tf.close()
-    sys.exit(1)
-  
-  # attempt to verify that the config is OK
-  if RUN_VERIFY:
-    # raise privilages to drop them with 'su'
-    os.setuid(0)
-    os.seteuid(0)
-    os.setgid(0)
-    os.setegid(0)
-    
-    # drop privilages and exec tor to verify it as the dropped_uid 
-    print "Using Tor to verify that arm will not break Tor's config:"
-    verifyCmd = "su -c 'tor --verify-config -f %s' %s" % (tf.name, USER)
-    success = os.system(verifyCmd)
-    
-    if success != 0:
-      print "Tor says the new configuration file is invalid: %s (%s)" % (ARM_CONFIG_FILE, tf.name)
-      sys.exit(1)
-  
-  # validates that the torrc matches what the wizard could produce
-  torrcFile = open(tf.name)
-  torrcContents = torrcFile.readlines()
-  torrcFile.close()
-  
-  if not isWizardGenerated(torrcContents):
-    print "torrc doesn't match what we'd expect from the setup wizard"
-    sys.exit(1)
-  
-  # backup the previous tor config
-  if os.path.exists(TOR_CONFIG_FILE):
-    try:
-      backupFilename = "%s_backup_%i" % (TOR_CONFIG_FILE, int(time.time()))
-      shutil.copy(TOR_CONFIG_FILE, backupFilename)
-    except IOError, exc:
-      print "Unable to backup %s (%s)" % (TOR_CONFIG_FILE, exc)
-      sys.exit(1)
-  
-  # overwrites TOR_CONFIG_FILE with ARM_CONFIG_FILE as loaded into tf.name
-  try:
-    shutil.copy(tf.name, TOR_CONFIG_FILE)
-    print "Successfully reconfigured Tor"
-  except IOError, exc:
-    print "Unable to copy %s to %s (%s)" % (tf.name, TOR_CONFIG_FILE, exc)
-    sys.exit(1)
-  
-  # unlink our temp file
-  try:
-    os.remove(tf.name)
-  except:
-    print "Unable to close temp file %s" % tf.name
-    sys.exit(1)
-  
-  sys.exit(0)
-
-def isWizardGenerated(torrcLines):
-  """
-  True if the given torrc contents could be generated by the wizard, false
-  otherwise. This just checks the basic format and options used, not the
-  validity of most generated values so this could still be rejected by tor.
-  """
-  
-  wizardPatterns = [re.compile(opt) for opt in WIZARD_OPT]
-  
-  for line in torrcLines:
-    commentStart = line.find("#")
-    if commentStart != -1: line = line[:commentStart]
-    
-    line = line.strip()
-    if not line: continue # blank line
-    
-    isRecognized = False
-    for pattern in wizardPatterns:
-      if pattern.match(line):
-        isRecognized = True
-        break
-    
-    if not isRecognized:
-      print "Unrecognized torrc contents: %s" % line
-      return False
-  
-  return True
-
-if __name__ == "__main__":
-  # sanity check that we're on linux
-  if os.name != "posix":
-    print "This is a script specifically for configuring Linux"
-    sys.exit(1)
-  
-  if len(sys.argv) == 3 and sys.argv[1] == "--validate":
-    torrcFile = open(sys.argv[2])
-    torrcContents = torrcFile.readlines()
-    torrcFile.close()
-    
-    isValid = isWizardGenerated(torrcContents)
-    if isValid: print "torrc validated"
-    else: print "torrc invalid"
-    
-    sys.exit(0)
-  
-  # check that we're running effectively as root
-  if os.geteuid() != 0:
-    print "This script needs to be run as root"
-    sys.exit(1)
-  
-  if len(sys.argv) < 2:
-    replaceTorrc()
-  elif len(sys.argv) == 2 and sys.argv[1] == "--init":
-    init()
-  elif len(sys.argv) == 2 and sys.argv[1] == "--remove":
-    remove()
-  else:
-    print HELP_MSG
-    sys.exit(1)
-
diff --git a/src/resources/torrcTemplate.txt b/src/resources/torrcTemplate.txt
deleted file mode 100644
index c6e61f0..0000000
--- a/src/resources/torrcTemplate.txt
+++ /dev/null
@@ -1,90 +0,0 @@
-# This is a tor configuration made by arm. To change the configuration by hand
-# edit this file then either...
-# - tell arm to reset tor by pressing 'x'
-# - run 'pkill -sighup tor'
-# - or restart tor
-#
-# Descriptions of all of these configuration attributes (and many more) are
-# available in the tor man page.
-
-[IF SHUTDOWN]
-  [NEWLINE]
-  # The following flag tells arm to shut down tor when it quits.
-  # ARM_SHUTDOWN
-[END IF]
-
-[NEWLINE]
-DataDirectory [DATA_DIR]      # location to store runtime data
-Log [LOG_ENTRY]               # location to log notices, warnings, and errors
-ControlPort 9052              # port controllers can connect to
-CookieAuthentication 1        # method for controller authentication
-
-[IF RELAY | EXIT | BRIDGE]
-  RunAsDaemon 1               # runs as a background process
-  
-  [IF LOWPORTS | STARTUP]
-    User [USERNAME]           # lowers our permissions to this user
-  [END IF]
-[END IF]
-[NEWLINE]
-
-[IF RELAY | EXIT | BRIDGE]
-  [IF LOWPORTS]
-    ORPort 443                # port used for relaying traffic
-  [ELSE]
-    ORPort 9001               # port used for relaying traffic
-  [END IF]
-  
-  [IF RELAY | EXIT]
-    [IF LOWPORTS]
-      DirPort 80              # port used for mirroring directory information
-    [ELSE]
-      DirPort 9030            # port used for mirroring directory information
-    [END IF]
-    
-    Nickname [NICKNAME]       # name for this relay
-    ContactInfo [CONTACT]     # contact information in case there's an issue
-  [END IF]
-  
-  [IF BRIDGE]
-    BridgeRelay 1             # makes us a bridge rather than a public relay
-    
-    [IF NOT DISTRIBUTE]
-      PublishServerDescriptor 0 # keeps our bridge descriptor private
-    [END IF]
-  [END IF]
-  
-  RelayBandwidthRate [BANDWIDTH] # limit for the bandwidth we'll use to relay
-  RelayBandwidthBurst [BURST] # maximum rate when relaying bursts of traffic
-  AccountingMax [LIMIT]       # maximum amount of traffic we'll relay per month
-  
-  [IF NOT CLIENT]
-    SocksPort 0               # prevents tor from being used as a client
-  [END IF]
-  
-  [IF PORTFORWARD]
-    PortForwarding 1          # negotiates UPnP and NAT-PMP if needed
-  [END IF]
-  
-  [IF RELAY | BRIDGE]
-    ExitPolicy reject *:*     # prevents us from connecting to non-relays
-  [ELSE]
-    [IF NOTICE]
-      DirPortFrontPage [NOTICE_PATH] # disclaimer saying that this is an exit
-    [END IF]
-    
-    [NEWLINE]
-    [EXIT_POLICY]
-    ExitPolicy reject *:*     # prevents any exit traffic not permitted above
-  [END IF]
-[ELSE]
-  ClientOnly 1                # prevents us from ever being used as a relay
-  MaxCircuitDirtiness [REUSE] # duration that circuits can be reused
-  
-  [IF BRIDGED]
-    UseBridges 1              # uses the following bridges to connect
-    [BRIDGES]
-  [END IF]
-[END IF]
-[NEWLINE]
-
diff --git a/src/settings.cfg b/src/settings.cfg
index 606ae43..8cd92c1 100644
--- a/src/settings.cfg
+++ b/src/settings.cfg
@@ -351,136 +351,6 @@ msg.ARM_DEBUG GETINFO traffic/written
 msg.ARM_DEBUG GETCONF
 msg.ARM_DEBUG Unable to query process resource usage from ps
 
-# configuration option attributes used in the relay setup wizard
-wizard.message.role Welcome to the Tor network! This will step you through the configuration process for becoming a part of it. To start with, what role would you like to have?
-wizard.message.relay Internal relays provide connections within the Tor network. Since you will only be connecting to Tor users and relays this is an easy, hassle free way of helping to make the network better.
-wizard.message.exit Exits connect between the Tor network and the outside Internet. This is the most vitally important role you can take, but it also needs some forethought. Please read 'http://www.atagar.com/torExitTips/' before proceeding further to avoid any nasty surprises!
-wizard.message.bridge Bridges are non-public relays used as stepping stones for censored users for accessing the Tor network.
-wizard.message.client This will make use of the Tor network without contributing to it. For easy, pre-configured setups that will help you to use Tor safely see 'http://www.atagar.com/torUsageTips/'.
-
-wizard.toggle Notify => Yes, No
-wizard.toggle Client => Enabled, Disabled
-wizard.toggle Lowports => Yes, No
-wizard.toggle Portforward => Enabled, Disabled
-wizard.toggle Startup => Yes, No
-wizard.toggle Rshutdown => Yes, No
-wizard.toggle Cshutdown => Yes, No
-wizard.toggle System => Yes, No
-wizard.toggle Notice => Yes, No
-wizard.toggle Policy => Custom, Default
-wizard.toggle Websites => Allow, Block
-wizard.toggle Email => Allow, Block
-wizard.toggle Im => Allow, Block
-wizard.toggle Misc => Allow, Block
-wizard.toggle Plaintext => Allow, Block
-wizard.toggle Distribute => Automated, Manual
-wizard.toggle Bridged => Yes, No
-
-# the following options haven't been implemented yet
-wizard.disabled Notify
-wizard.disabled Startup
-
-wizard.suboptions Websites
-wizard.suboptions Email
-wizard.suboptions Im
-wizard.suboptions Misc
-wizard.suboptions Plaintext
-wizard.suboptions Bridge1
-wizard.suboptions Bridge2
-wizard.suboptions Bridge3
-
-wizard.default Control => 9052
-wizard.default Notify => true
-wizard.default Bandwidth => 5 MB/s
-wizard.default Startup => true
-wizard.default Rshutdown => false
-wizard.default Cshutdown => true
-wizard.default System => true
-wizard.default Client => false
-wizard.default Lowports => true
-wizard.default Portforward => true
-wizard.default Notice => true
-wizard.default Policy => false
-wizard.default Websites => true
-wizard.default Email => true
-wizard.default Im => true
-wizard.default Misc => true
-wizard.default Plaintext => true
-wizard.default Distribute => true
-wizard.default Bridged => false
-wizard.default Reuse => 10 minutes
-
-wizard.blankValue Nickname => Unnamed
-wizard.blankValue Bridge1 => <ip address>:<port>
-wizard.blankValue Bridge2 => <ip address>:<port>
-wizard.blankValue Bridge3 => <ip address>:<port>
-
-wizard.label.general Cancel => Cancel
-wizard.label.general Back => Previous
-wizard.label.general Next => Next
-wizard.label.role Resume => Use Last Configuration
-wizard.label.role Relay => Internal Relay
-wizard.label.role Exit => Exit Relay
-wizard.label.role Bridge => Bridge
-wizard.label.role Client => Client
-wizard.label.opt Nickname => Nickname
-wizard.label.opt Contact => Contact Information
-wizard.label.opt Notify => Issue Notification
-wizard.label.opt Bandwidth => Relay Speed
-wizard.label.opt Limit => Monthly Limit
-wizard.label.opt Client => Client Usage
-wizard.label.opt Lowports => Use Popular Ports
-wizard.label.opt Portforward => Port Forwarding
-wizard.label.opt Startup => Run At Startup
-wizard.label.opt Rshutdown => Shutdown With Arm
-wizard.label.opt Cshutdown => Shutdown With Arm
-wizard.label.opt System => Use System Instance
-wizard.label.opt Notice => Disclaimer Notice
-wizard.label.opt Policy => Exit Policy
-wizard.label.opt Websites => Web Browsing
-wizard.label.opt Email => Receiving Email
-wizard.label.opt Im => Instant Messaging
-wizard.label.opt Misc => Other Services
-wizard.label.opt Plaintext => Unencrypted Traffic
-wizard.label.opt Distribute => Distribution
-wizard.label.opt Bridged => Use Bridges
-wizard.label.opt Bridge1 => First Bridge
-wizard.label.opt Bridge2 => Second Bridge
-wizard.label.opt Bridge3 => Third Bridge
-wizard.label.opt Reuse => Circuit Duration
-
-wizard.description.general Cancel => Close without starting Tor.
-wizard.description.role Resume => Start Tor with the last configuration you made.
-wizard.description.role Relay => Provides interconnections with other Tor relays. This is a safe and easy way of making the network better.
-wizard.description.role Exit => Connects between Tor network and the outside Internet. This is a vital role, but can lead to abuse complaints.
-wizard.description.role Bridge => Non-public relay specifically for helping censored users.
-wizard.description.role Client => Use the network without contributing to it.
-wizard.description.opt Nickname => Human friendly name for your relay. If this is unique then it's used instead of your fingerprint (a forty character hex string) when pages like TorStatus refer to you.
-wizard.description.opt Contact => Address we can contact you at if there's a problem with your relay. This is public information so, if it looks like an email address, we'll obscure it a bit.
-wizard.description.opt Notify => Sends automated email notifications to the above address if your relay is unreachable or out of date. This service is provided by Tor Weather (https://weather.torproject.org/) and will send you a confirmation email before it's started.
-wizard.description.opt Bandwidth => Limit for the average rate at which you relay traffic.
-wizard.description.opt Limit => Maximum amount of traffic to relay each month. Some ISPs, like Comcast, cap their customer's Internet usage so this is an easy way of staying below that limit.
-wizard.description.opt Client => Enable this if you would like to use Tor yourself. This opens or closes the SOCKS port used by applications for connecting to Tor.
-wizard.description.opt Lowports => Relays using port 443 rather than 9001. This helps some users that would otherwise be blocked, but requires that tor is started with root permissions (after that it lowers itself to those of the current user).
-wizard.description.opt Portforward => If needed, attempts NAT traversal using UPnP and NAT-PMP. This allows for automatic port forwarding on most home routers.
-wizard.description.opt Startup => Runs Tor in the background when the system starts.
-wizard.description.opt Rshutdown => When you quit arm the Tor process is stopped thirty seconds later. This delay is so people using you can gracefully switch their circuits.
-wizard.description.opt Cshutdown => Stops the Tor process when you quit arm.
-wizard.description.opt System => Use the system wide tor instance rather than making one of our own.
-wizard.description.opt Notice => Provides a disclaimer that this is an exit on port 80 (http://www.atagar.com/exitNotice).
-wizard.description.opt Policy => Ports allowed to exit from your relay. The default policy allows for common services while limiting the chance of getting a DMCA takedown for torrent traffic (http://www.atagar.com/exitPolicy).
-wizard.description.opt Websites => General Internet browsing including HTTP (80), HTTPS (443), common alternatives (81, 8008), and proxies (3128, 8080)
-wizard.description.opt Email => Protocols for receiving, but not sending email. This includes POP3 (110), POP3S (995), IMAP (143, 220), and IMAPS (993).
-wizard.description.opt Im => Common instant messaging protocols including Jabber, IRC, ICQ, AIM, Yahoo, MSN, SILC, GroupWise, Gadu-Gadu, Sametime, and Zephyr.
-wizard.description.opt Misc => Protocols from the default policy that aren't among the above.
-wizard.description.opt Plaintext => When blocked the policy will exclude ports that aren't commonly encrypted.
-wizard.description.opt Distribute => If automated then we'll attempt to get your bridge to censored users (email auto-responders, activist networks, etc). Otherwise it'll be up to you to distribute the bridge address to people who need it.
-wizard.description.opt Bridged => If you're being blocked from Tor then bridges provide a stepping stone you can use to connect. To get bridges visit 'https://bridges.torproject.org/' and enter the IP/port into the following entries (for instance "141.201.27.48:443").
-wizard.description.opt Bridge1 => Bridge used to connect to the Tor network.
-wizard.description.opt Bridge2 => Fallback bridge used for connecting if the first is unavailable.
-wizard.description.opt Bridge3 => Fallback bridge used for connecting if neither of the first two are available.
-wizard.description.opt Reuse => Duration that circuits will be reused before replacements are made for new connections. It's good to periodically change the route you use, but making circuits takes a fair bit of work so don't set this to be too low.
-
 # valid torrc aliases from the _option_abbrevs struct of src/or/config.c
 # These couldn't be requested via GETCONF (in 0.2.1.19), but I think this has
 # been fixed. Discussion is in:
@@ -835,108 +705,3 @@ port.label.23399 Skype
 port.label.30301 BitTorrent
 port.label.33434 traceroute
 
-# Exit policy categories and attributes used by the relay setup wizard. The
-# full policy is the Reduced Exit Policy, revision 9 (edited 6/28/11):
-# https://trac.torproject.org/projects/tor/wiki/doc/ReducedExitPolicy?version=9
-
-port.category all => The following sets which ports can exit the tor network through you. For more information and updates on the suggested policy see: https://trac.torproject.org/projects/tor/wiki/doc/ReducedExitPolicy
-port.category web => ports for general internet browsing
-port.category mail => ports for receiving email
-port.category im => ports for instant messaging
-port.category misc => ports for other services
-
-port.exit.misc 20-23      # FTP, SSH, Telnet
-port.exit.misc 43         # WHOIS
-port.exit.all 53          # DNS
-port.exit.misc 79         # Finger
-port.exit.web 80          # HTTP
-port.exit.web 81          # HTTP alternate?
-port.exit.misc 88         # Kerberos
-port.exit.mail 110        # POP3
-port.exit.mail 143        # IMAP
-port.exit.im 194          # IRC
-port.exit.mail 220        # IMAP3
-port.exit.web 443         # HTTPS
-port.exit.misc 464        # Kerberos
-port.exit.im 531          # AIM/IRC
-port.exit.misc 543-544    # Kerberos
-port.exit.misc 563        # NNTPS
-port.exit.im 706          # SILC
-port.exit.misc 749        # Kerberos
-port.exit.misc 873        # rsync
-port.exit.misc 902-904    # VMware
-port.exit.misc 981        # SofaWare Firewall Administration
-port.exit.misc 989-990    # FTPS
-port.exit.misc 991        # NAS
-port.exit.misc 992        # Telnet
-port.exit.mail 993        # IMAPS
-port.exit.im 994          # IRC over SSL
-port.exit.mail 995        # POP3S
-port.exit.misc 1194       # OpenVPN
-port.exit.misc 1220       # QuickTime
-port.exit.misc 1293       # PKT-KRB-IPSec
-port.exit.misc 1500       # NetGuard GuardianPro Firewall Administration / VLSI License Manager
-port.exit.im 1533         # Sametime
-port.exit.im 1677         # GroupWise
-port.exit.misc 1723       # Microsoft Point-to-Point Tunneling Protocol
-port.exit.misc 1863       # MSNP
-port.exit.misc 2082       # Infowave Mobility Server
-port.exit.misc 2083       # Secure Radius Service
-port.exit.misc 2086       # GNUnet
-port.exit.misc 2087       # Event Logging Integration
-port.exit.misc 2095-2096  # NBX SER / DIR
-port.exit.im 2102-2104    # Zephyr
-port.exit.web 3128        # Squid Proxy
-port.exit.misc 3389       # Windows Based Terminal
-port.exit.misc 3690       # SVN
-port.exit.misc 4321       # RWHOIS
-port.exit.misc 4643       # Virtuozzo Power Panel
-port.exit.im 5050         # Yahoo IM
-port.exit.im 5190         # AIM/ICQ
-port.exit.im 5222         # Jabber
-port.exit.im 5223         # Jabber over SSL
-port.exit.misc 5228       # Android Market
-port.exit.misc 5900       # VNC
-port.exit.im 6660-6669    # IRC
-port.exit.im 6679         # IRC over SSL
-port.exit.im 6697         # IRC over SSL
-port.exit.misc 8000       # Intel Remote Desktop Management Interface
-port.exit.web 8008        # HTTP alternate
-port.exit.im 8074         # Gadu-Gadu
-port.exit.web 8080        # HTTP Proxies
-port.exit.misc 8087       # Simplify Media SPP Protocol
-port.exit.misc 8088       # Radan HTTP
-port.exit.misc 8443       # PCsync HTTPS
-port.exit.misc 8888       # NewsEDGE
-port.exit.misc 9418       # Git
-port.exit.misc 9999       # distinct
-port.exit.misc 10000      # Web-based Linux admin tool
-port.exit.misc 19294      # Google Voice
-port.exit.misc 19638      # Ensim Control Panel
-
-# Commonly encrypted ports (used to allow for policies that only include
-# encrypted traffic)
-
-port.encrypted 22
-port.encrypted 53         # dns - not really encrypted but want it anyway
-port.encrypted 88
-port.encrypted 443
-port.encrypted 464
-port.encrypted 543
-port.encrypted 544
-port.encrypted 563
-port.encrypted 749
-port.encrypted 981
-port.encrypted 989
-port.encrypted 990
-port.encrypted 993
-port.encrypted 995
-port.encrypted 1194
-port.encrypted 1293
-port.encrypted 1723
-port.encrypted 2083
-port.encrypted 5223
-port.encrypted 6679
-port.encrypted 6697
-port.encrypted 8443
-
diff --git a/src/starter.py b/src/starter.py
index 2b5063e..ccf7aad 100644
--- a/src/starter.py
+++ b/src/starter.py
@@ -40,8 +40,7 @@ CONFIG = {"startup.controlPassword": None,
           "startup.blindModeEnabled": False,
           "startup.events": "N3",
           "startup.dataDirectory": "~/.arm",
-          "wizard.default": {},
-          "features.allowDetachedStartup": True,
+          "features.allowDetachedStartup": False,
           "features.config.descriptions.enabled": True,
           "features.config.descriptions.persist": True,
           "log.configDescriptions.readManPageSuccess": util.log.INFO,
@@ -123,8 +122,7 @@ def allowConnectionTypes():
   skipSocketConnection = isPortArgPresent and not isSocketArgPresent
   
   # Flag to indicate if we'll start arm reguardless of being unable to connect
-  # to Tor. This is the default behavior if the user hasn't provided a port or
-  # socket to connect to, so we can show the relay setup wizard.
+  # to Tor.
   
   allowDetachedStart = CONFIG["features.allowDetachedStartup"] and not isPortArgPresent and not isSocketArgPresent
   
@@ -227,21 +225,6 @@ def _getController(controlAddr="127.0.0.1", controlPort=9051, passphrase=None, i
   except Exception, exc:
     if controller: controller.close()
     
-    # attempts to connect with the default wizard address too
-    wizardPort = CONFIG["wizard.default"].get("Control")
-    
-    if wizardPort and wizardPort.isdigit():
-      wizardPort = int(wizardPort)
-      
-      # Attempt to connect to the wizard port. If the connection fails then
-      # don't print anything and continue with the error case for the initial
-      # connection failure. Otherwise, return the connection result.
-      
-      if controlPort != wizardPort:
-        controller = _getController(controlAddr, wizardPort)
-        if controller != None: return controller
-      else: return None # wizard connection attempt, don't print anything
-    
     if passphrase and str(exc) == "Unable to authenticate: password incorrect":
       # provide a warning that the provided password didn't work, then try
       # again prompting for the user to enter it



More information about the tor-commits mailing list