[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r23867: {arm} Expanding the torrc validation added: checking if torrc entr (in arm/trunk: . src/interface src/util)



Author: atagar
Date: 2010-11-28 03:17:11 +0000 (Sun, 28 Nov 2010)
New Revision: 23867

Modified:
   arm/trunk/TODO
   arm/trunk/armrc.sample
   arm/trunk/src/interface/controller.py
   arm/trunk/src/interface/torrcPanel.py
   arm/trunk/src/util/torConfig.py
Log:
Expanding the torrc validation
added: checking if torrc entries are pointless due to matching their default value
added: validation warning when custom entries are missing from the torrc
fix: validation wasn't taking option aliases into consideration



Modified: arm/trunk/TODO
===================================================================
--- arm/trunk/TODO	2010-11-28 00:03:03 UTC (rev 23866)
+++ arm/trunk/TODO	2010-11-28 03:17:11 UTC (rev 23867)
@@ -1,6 +1,6 @@
 TODO
 
-- Roadmap and completed work for next release (1.3.8)
+- Roadmap and completed work for next release (1.4.2)
   [ ] refactor panels
       Currently the interface is a bit of a rat's nest (especially the
       controller). The goal is to use better modularization to both simplify
@@ -9,15 +9,6 @@
       progress - /init and /util are done and /interface is partly done. Known
       bugs are being fixed while refactoring.
       
-      [ ] conf panel
-        - display and validation needs to recognize config entries that span
-          multiple lines
-        - option to display the armrc configuration
-        - [validation] check if there's missing entries
-          might be able to use "GETINFO config-text" to determine entries that
-          differ from the defaults, then see if they're all in the torrc
-        - [validation] tor provides the types for config options, so I might be
-          able to use these instead of hardcoding the multiline values.
       [ ] conn panel
         - expand client connections and note location in circuit (entry-exit)
         - for clients give an option to list all connections, to tell which are
@@ -37,17 +28,35 @@
         - pick apart applications like iftop and pktstat to see how they get
           per-connection bandwidth usage. Forum thread discussing it:
           https://bbs.archlinux.org/viewtopic.php?pid=715906
-      [X] attempt to clear controller password from memory
+      [ ] control port interpreter (interactive prompt)
+          Panel and startup option (-t maybe?) for providing raw control port
+          access along with usability improvements (piggybacking on the arm
+          connection):
+          - irc like help (ex "/help GETINFO" could provide a summary of
+            getinfo commands, partly using the results from
+            "GETINFO info/names")
+          - tab completion and up/down for previous commands
+          - warn and get confirmation if command would disrupt arm (for
+            instance 'SETEVENTS')
+          - 'safe' option that restricts to read-only access (start with this)
+          - issue sighup reset
+      [ ] low hanging fruit from the "client mode use cases" below
   * release prep
     * pylint --indent-string="  " --disable=C,R interface/foo.py | less
     * double check __init__.py and README for changes
 
-- Roadmap for version 1.3.9
+- Roadmap for version 1.4.3
   [ ] refactor panels
       [ ] controller and popup panels
         - allow arm to resume after restarting tor
             This requires a full move to the torTools controller.
         - provide measurements for startup time, and try to improve bottlenecks
+  [ ] menus
+      - http://gnosis.cx/publish/programming/charming_python_6.html ?
+      - additional options:
+        - make update rates configurable via the ui
+        - dialog with flag descriptions and other help
+        - menu with all torrc options (making them editable/toggleable)
   [ ] setup scripts for arm
       [ ] updater (checks for a new tarball and installs it automatically)
         - attempt to verify download signature, providing a warning if unable
@@ -63,11 +72,6 @@
     large logs (for instance, when at the DEBUG runlevel). Currently we're
     timing out the function if it takes too long, but a more efficient method
     for deduplication would be preferable.
-  * The log panel gets cripplingly slow if the log grows to be even moderately
-    large (200 entries or so). This is most likely due to the hack for
-    dynamically determining the content height. Check if a solution like the
-    one for the confFilePanel will work.
-  * path for sample armrc in man page is wrong
   * when in client mode and tor stops the header panel doesn't say so
   * util are assuming that tor is running under the default command name
       attempt to determine the command name at runtime (if the pid is available
@@ -108,22 +112,6 @@
     * connections aren't cleared when control port closes
 
 - Future Features
-  * control port interpreter (interactive prompt)
-    Panel and startup option (-t maybe?) for providing raw control port access
-    along with usability improvements (piggybacking on the arm connection):
-      * irc like help (ex "/help GETINFO" could provide a summary of getinfo
-        commands, partly using the results from "GETINFO info/names")
-      * tab completion and up/down for previous commands
-      * warn and get confirmation if command would disrupt arm (for instance
-        'SETEVENTS')
-      * 'safe' option that restricts to read-only access (start with this)
-      * issue sighup reset
-  * menus
-    * http://gnosis.cx/publish/programming/charming_python_6.html ?
-    * additional options:
-      * make update rates configurable via the ui
-      * dialog with flag descriptions and other help
-      * menu with all torrc options (making them editable/toggleable)
   * client mode use cases
     * not sure what sort of information would be useful in the header (to
       replace the orport, fingerprint, flags, etc)
@@ -150,6 +138,10 @@
     * dialog with bridge statuses (idea by mikeperry)
       https://trac.vidalia-project.net/ticket/570
       https://trac.torproject.org/projects/tor/ticket/2068
+  * feature parity for arm's config values (armrc entries)
+    * editability
+    * parse descriptions from the man page? autogeneration of the man page from
+      something storing the descriptions
   * handle mutiple tor instances
     * screen style (dialog for switching between instances)
     * extra window with whatever stats can be aggregated over all instances
@@ -177,6 +169,7 @@
         Plugin for distutils. Like most mac packaging, this can only run on a
         mac. It also requires setuptools:
         http://www.errorhelp.com/search/details/74034/importerror-no-module-named-setuptools
+  * tab completion for input fields that expect a filesystem path
   * look through vidalia's tickets for more ideas
     https://trac.vidalia-project.net/
   * look into additions to the used apis

Modified: arm/trunk/armrc.sample
===================================================================
--- arm/trunk/armrc.sample	2010-11-28 00:03:03 UTC (rev 23866)
+++ arm/trunk/armrc.sample	2010-11-28 03:17:11 UTC (rev 23867)
@@ -211,6 +211,9 @@
 log.torrc.readFailed WARN
 log.torrc.validation.duplicateEntries NOTICE
 log.torrc.validation.torStateDiffers NOTICE
+log.torrc.validation.missingTorrcEntries NOTICE
+log.torrc.validation.valueIsDefault NOTICE
+log.torrc.validation.unnecessaryTorrcEntries WARN
 log.configDescriptions.readManPageSuccess INFO
 log.configDescriptions.readManPageFailed WARN
 log.configDescriptions.unrecognizedCategory NOTICE

Modified: arm/trunk/src/interface/controller.py
===================================================================
--- arm/trunk/src/interface/controller.py	2010-11-28 00:03:03 UTC (rev 23866)
+++ arm/trunk/src/interface/controller.py	2010-11-28 03:17:11 UTC (rev 23867)
@@ -56,7 +56,10 @@
           "log.refreshRate": log.DEBUG,
           "log.configEntryUndefined": log.NOTICE,
           "log.torrc.validation.duplicateEntries": log.NOTICE,
-          "log.torrc.validation.torStateDiffers": log.NOTICE}
+          "log.torrc.validation.torStateDiffers": log.NOTICE,
+          "log.torrc.validation.missingTorrcEntries": log.NOTICE,
+          "log.torrc.validation.valueIsDefault": log.NOTICE,
+          "log.torrc.validation.unnecessaryTorrcEntries": log.WARN}
 
 class ControlPanel(panel.Panel):
   """ Draws single line label for interface controls. """
@@ -468,21 +471,25 @@
   
   if loadedTorrc.isLoaded():
     corrections = loadedTorrc.getCorrections()
-    irrelevantLines, mismatchLines = [], []
+    duplicateOptions, mismatchLines, missingOptions, defaultOptions = [], [], [], []
     
-    for lineNum in corrections:
-      problem = corrections[lineNum][0]
-      if problem == torConfig.VAL_DUPLICATE: irrelevantLines.append(lineNum)
-      elif problem == torConfig.VAL_MISMATCH: mismatchLines.append(lineNum)
+    for lineNum, issue, msg in corrections:
+      if issue == torConfig.VAL_DUPLICATE:
+        duplicateOptions.append("%s (line %i)" % (msg, lineNum))
+      elif issue == torConfig.VAL_MISMATCH: mismatchLines.append(lineNum)
+      elif issue == torConfig.VAL_MISSING: missingOptions.append(msg)
+      elif issue == torConfig.VAL_IS_DEFAULT:
+        defaultOptions.append("%s (line %i)" % (msg, lineNum))
     
-    if irrelevantLines:
-      irrelevantLines.sort()
+    if duplicateOptions:
+      duplicateOptions.sort()
       
-      if len(irrelevantLines) > 1: first, second, third = "Entries", "are", ", including lines"
-      else: first, second, third = "Entry", "is", " on line"
-      msgStart = "%s in your torrc %s ignored due to duplication%s" % (first, second, third)
-      msgLines = ", ".join([str(val + 1) for val in irrelevantLines])
-      msg = "%s: %s (highlighted in blue)" % (msgStart, msgLines)
+      if len(duplicateOptions) > 1:
+        msgStart = "Entries in your torrc are being ignored due to having duplicates"
+      else:
+        msgStart = "An entry in your torrc are being ignored due to having a duplicate"
+      
+      msg = "%s: %s" % (msgStart, ", ".join(duplicateOptions))
       log.log(CONFIG["log.torrc.validation.duplicateEntries"], msg)
     
     if mismatchLines:
@@ -491,6 +498,31 @@
       msgLines = ", ".join([str(val + 1) for val in mismatchLines])
       msg = "%s: %s" % (msgStart, msgLines)
       log.log(CONFIG["log.torrc.validation.torStateDiffers"], msg)
+    
+    if missingOptions:
+      missingOptions.sort()
+      
+      if len(missingOptions) > 1:
+        msgStart = "Configuration options differ from their defaults but aren't in the torrc"
+      else:
+        msgStart = "Configuration option differs from its defaults but isn't in the torrc"
+      
+      msg = "%s: %s" % (msgStart, ", ".join(missingOptions))
+      log.log(CONFIG["log.torrc.validation.missingTorrcEntries"], msg)
+    
+    if defaultOptions:
+      defaultOptions.sort()
+      
+      if len(defaultOptions) > 1:
+        msgStart = "Entries in your torrc match their default values"
+      else:
+        msgStart = "An entry in your torrc matches its default value"
+      
+      msg = "%s: %s" % (msgStart, ", ".join(defaultOptions))
+      log.log(CONFIG["log.torrc.validation.valueIsDefault"], msg)
+    
+    if duplicateOptions or defaultOptions:
+      log.log(CONFIG["log.torrc.validation.unnecessaryTorrcEntries"], "Unneeded torrc entries found. They've been highlighted in blue on the torrc page.")
   
   loadedTorrc.getLock().release()
   

Modified: arm/trunk/src/interface/torrcPanel.py
===================================================================
--- arm/trunk/src/interface/torrcPanel.py	2010-11-28 00:03:03 UTC (rev 23866)
+++ arm/trunk/src/interface/torrcPanel.py	2010-11-28 03:17:11 UTC (rev 23867)
@@ -81,7 +81,9 @@
         renderedContents = ["### Unable to load the torrc ###"]
       else:
         renderedContents = loadedTorrc.getDisplayContents(self.stripComments)
-        corrections = loadedTorrc.getCorrections()
+        
+        # constructs a mapping of line numbers to the issue on it
+        corrections = dict((lineNum, (issue, msg)) for lineNum, issue, msg in loadedTorrc.getCorrections())
       
       loadedTorrc.getLock().release()
     else:
@@ -155,7 +157,7 @@
       if lineNumber in corrections:
         lineIssue, lineIssueMsg = corrections[lineNumber]
         
-        if lineIssue == torConfig.VAL_DUPLICATE:
+        if lineIssue in (torConfig.VAL_DUPLICATE, torConfig.VAL_IS_DEFAULT):
           lineComp["option"][1] = curses.A_BOLD | uiTools.getColor("blue")
           lineComp["argument"][1] = curses.A_BOLD | uiTools.getColor("blue")
         elif lineIssue == torConfig.VAL_MISMATCH:

Modified: arm/trunk/src/util/torConfig.py
===================================================================
--- arm/trunk/src/util/torConfig.py	2010-11-28 00:03:03 UTC (rev 23866)
+++ arm/trunk/src/util/torConfig.py	2010-11-28 03:17:11 UTC (rev 23867)
@@ -28,9 +28,11 @@
 TIME_MULT = {"sec": 1, "min": 60, "hour": 3600, "day": 86400, "week": 604800}
 
 # enums for issues found during torrc validation:
-# VAL_DUPLICATE - entry is ignored due to being a duplicate
-# VAL_MISMATCH  - the value doesn't match tor's current state
-VAL_DUPLICATE, VAL_MISMATCH = range(1, 3)
+# VAL_DUPLICATE  - entry is ignored due to being a duplicate
+# VAL_MISMATCH   - the value doesn't match tor's current state
+# VAL_MISSING    - value differs from its default but is missing from the torrc
+# VAL_IS_DEFAULT - the configuration option matches tor's default
+VAL_DUPLICATE, VAL_MISMATCH, VAL_MISSING, VAL_IS_DEFAULT = range(1, 5)
 
 # descriptions of tor's configuration options fetched from its man page
 CONFIG_DESCRIPTIONS_LOCK = threading.RLock()
@@ -326,16 +328,22 @@
 
 def validate(contents = None):
   """
-  Performs validation on the given torrc contents, providing back a mapping of
-  line numbers to tuples of the (issue, msg) found on them.
+  Performs validation on the given torrc contents, providing back a listing of
+  (line number, issue, msg) tuples for issues found. If the issue occures on a
+  multiline torrc entry then the line number is for the last line of the entry.
   
   Arguments:
     contents - torrc contents
   """
   
   conn = torTools.getConn()
-  issuesFound, seenOptions = {}, []
+  issuesFound, seenOptions = [], []
   
+  # used later to check if either any options match their defaults or custom
+  # options aren't in the torrc
+  configTextQuery = conn.getInfo("config-text", "").strip().split("\n")
+  customOptions = [entry[:entry.find(" ")] for entry in configTextQuery]
+  
   # Strips comments and collapses multiline multi-line entries, for more
   # information see:
   # https://trac.torproject.org/projects/tor/ticket/1929
@@ -360,12 +368,20 @@
     if len(lineComp) == 2: option, value = lineComp
     else: option, value = lineText, ""
     
+    # if an aliased option then use its real name
+    if option in CONFIG["torrc.alias"]:
+      option = CONFIG["torrc.alias"][option]
+    
     # most parameters are overwritten if defined multiple times
     if option in seenOptions and not option in getMultilineParameters():
-      issuesFound[lineNumber] = (VAL_DUPLICATE, "")
+      issuesFound.append((lineNumber, VAL_DUPLICATE, option))
       continue
     else: seenOptions.append(option)
     
+    # checks if the value isn't necessary due to matching the defaults
+    if not option in customOptions:
+      issuesFound.append((lineNumber, VAL_IS_DEFAULT, option))
+    
     # replace aliases with their recognized representation
     if option in CONFIG["torrc.alias"]:
       option = CONFIG["torrc.alias"][option]
@@ -412,8 +428,16 @@
         elif valueType == TIME_VALUE:
           displayValues = [uiTools.getTimeLabel(int(val)) for val in torValues]
         
-        issuesFound[lineNumber] = (VAL_MISMATCH, ", ".join(displayValues))
+        issuesFound.append((lineNumber, VAL_MISMATCH, ", ".join(displayValues)))
   
+  # checks if any options that differ from their defaults aren't in the torrc
+  configTextQuery = conn.getInfo("config-text", "").strip().split("\n")
+  configOptions = [entry[:entry.find(" ")] for entry in configTextQuery]
+  
+  for option in customOptions:
+    if not option in seenOptions:
+      issuesFound.append((None, VAL_MISSING, option))
+  
   return issuesFound
 
 def _parseConfValue(confArg):
@@ -586,7 +610,7 @@
       if self.corrections == None:
         self.corrections = validate(self.contents)
       
-      returnVal = dict(self.corrections)
+      returnVal = list(self.corrections)
     
     self.valsLock.release()
     return returnVal