[tor-commits] [stem/master] Handling the server descriptor's fingerprint line

atagar at torproject.org atagar at torproject.org
Mon Mar 26 00:10:01 UTC 2012


commit 4ae18ed246b8f9f762df154ea493adb5cfbf1e80
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Mar 18 15:08:57 2012 -0700

    Handling the server descriptor's fingerprint line
---
 stem/descriptor/server_descriptor.py |   34 ++++++++++++++++++++++++++--------
 stem/util/tor_tools.py               |   15 +++++++++++----
 test/unit/util/tor_tools.py          |    4 ++--
 3 files changed, 39 insertions(+), 14 deletions(-)

diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 2b92f5c..cee2bcd 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -70,6 +70,7 @@ class ServerDescriptorV2(Descriptor):
     platform (str)           - operating system and tor version
     tor_version (stem.version.Version) - version of tor
     published (datetime.datetime) - time in GMT when the descriptor was generated (*)
+    fingerprint (str)        - fourty hex digits that make up the relay's fingerprint
     
     * required fields, others are left as None if undefined
   """
@@ -77,7 +78,7 @@ class ServerDescriptorV2(Descriptor):
   nickname = address = or_port = socks_port = dir_port = None
   average_bandwidth = burst_bandwidth = observed_bandwidth = None
   platform = tor_version = None
-  published = None
+  published = fingerprint = None
   
   def __init__(self, contents):
     Descriptor.__init__(self, contents)
@@ -127,12 +128,15 @@ class ServerDescriptorV2(Descriptor):
     # parse all the entries into our attributes
     
     for keyword, values in entres.items():
+      value = values[0] # most just work with the first (and only) value
+      line = "%s %s" % (keyword, value) # original line
+      
       if keyword == "router":
         # "router" nickname address ORPort SocksPort DirPort
-        router_comp = values[0].split()
+        router_comp = value.split()
         
         if len(router_comp) != 5:
-          raise ValueError("Router line must have five values: router %s" % values[0]
+          raise ValueError("Router line must have five values: %s" % line
         elif not stem.util.tor_tools.is_valid_nickname(router_comp[0]):
           raise TypeError("Router line entry isn't a valid nickname: %s" % router_comp[0])
         elif not stem.util.connection.is_valid_ip_address(router_comp[1]):
@@ -151,10 +155,10 @@ class ServerDescriptorV2(Descriptor):
         self.dir_port   = router_comp[4]
       elif keyword == "bandwidth":
         # "bandwidth" bandwidth-avg bandwidth-burst bandwidth-observed
-        bandwidth_comp = values[0].split()
+        bandwidth_comp = value.split()
         
         if len(bandwidth_comp) != 3:
-          raise ValueError("Bandwidth line must have three values: bandwidth %s" % values[0]
+          raise ValueError("Bandwidth line must have three values: %s" % line
         elif not bandwidth_comp[0].isdigit()):
           raise TypeError("Bandwidth line's average rate isn't numeric: %s" % bandwidth_comp[0])
         elif not bandwidth_comp[1].isdigit()):
@@ -168,7 +172,7 @@ class ServerDescriptorV2(Descriptor):
       elif keyword == "platform":
         # "platform" string
         
-        self.platform = values[0]
+        self.platform = value
         
         # This line can contain any arbitrary data, but tor seems to report its
         # version followed by the os like the following...
@@ -186,7 +190,21 @@ class ServerDescriptorV2(Descriptor):
         # "published" YYYY-MM-DD HH:MM:SS
         
         try:
-          self.published = datetime.datetime.strptime(values[0], "%Y-%m-%d %H:%M:%S")
+          self.published = datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
         except ValueError:
-          raise TypeError("Published line's time wasn't parseable: %s" % values[0])
+          raise TypeError("Published line's time wasn't parseable: %s" % line)
+      elif keyword == "fingerprint":
+        # This is fourty hex digits split into space separated groups of four.
+        # Checking that we match this pattern.
+        
+        fingerprint = value.replace(" ", "")
+        
+        for grouping in value.split(" "):
+          if len(grouping) != 4:
+            raise TypeError("Fingerprint line should have groupings of four hex digits: %s" % value)
+        
+        if not stem.util.tor_tools.is_valid_fingerprint(fingerprint):
+          raise TypeError("Tor relay fingerprints consist of fourty hex digits: %s" % value)
+        
+        self.fingerprint = fingerprint
 
diff --git a/stem/util/tor_tools.py b/stem/util/tor_tools.py
index 5e468c3..3c0e88a 100644
--- a/stem/util/tor_tools.py
+++ b/stem/util/tor_tools.py
@@ -13,20 +13,27 @@ import re
 # case insensitive. Tor doesn't define this in the spec so flipping a coin
 # and going with case insensitive.
 
-FINGERPRINT_PATTERN = re.compile("^\$[0-9a-fA-F]{40}$")
+FINGERPRINT_PATTERN = re.compile("^[0-9a-fA-F]{40}$")
 NICKNAME_PATTERN = re.compile("^[a-zA-Z0-9]{1,19}$")
 
-def is_valid_fingerprint(entry):
+def is_valid_fingerprint(entry, check_prefix = False):
   """
-  Checks if a string is a properly formatted relay fingerprint.
+  Checks if a string is a properly formatted relay fingerprint. This checks for
+  a '$' prefix if check_prefix is true, otherwise this only validates the hex
+  digits.
   
   Arguments:
-    entry (str) - string to be checked
+    entry (str)         - string to be checked
+    check_prefix (bool) - checks for a '$' prefix
   
   Returns:
     True if the string could be a relay fingerprint, False otherwise.
   """
   
+  if check_prefix:
+    if not entry or entry[0] != "$": return False
+    entry = entry[1:]
+  
   return bool(FINGERPRINT_PATTERN.match(entry))
 
 def is_valid_nickname(entry):
diff --git a/test/unit/util/tor_tools.py b/test/unit/util/tor_tools.py
index 5dd1abb..2ff3058 100644
--- a/test/unit/util/tor_tools.py
+++ b/test/unit/util/tor_tools.py
@@ -25,10 +25,10 @@ class TestTorTools(unittest.TestCase):
     )
     
     for fingerprint in valid_fingerprints:
-      self.assertTrue(stem.util.tor_tools.is_valid_fingerprint(fingerprint))
+      self.assertTrue(stem.util.tor_tools.is_valid_fingerprint(fingerprint, True))
     
     for fingerprint in invalid_fingerprints:
-      self.assertFalse(stem.util.tor_tools.is_valid_fingerprint(fingerprint))
+      self.assertFalse(stem.util.tor_tools.is_valid_fingerprint(fingerprint, True))
   
   def test_is_valid_nickname(self):
     """





More information about the tor-commits mailing list