[tor-commits] [stem/master] Validating that fields aren't duplicated

atagar at torproject.org atagar at torproject.org
Sat Oct 13 18:35:45 UTC 2012


commit db87c88965806ec13f9888c220879af45fc65e44
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Sep 8 11:54:33 2012 -0700

    Validating that fields aren't duplicated
    
    Almost all of the fields in a network status document can only appear once.
    Checking that this is a case. This also includes a unit test for the
    validation. I'm a little surprised that the old parser doesn't choke on
    duplicated content, but I'm about to replace it so probably not worth
    investigating.
---
 stem/descriptor/networkstatus.py               |   19 ++++++++++++++++
 test/unit/descriptor/networkstatus/document.py |   28 ++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 5676c16..2140b4d 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -297,8 +297,27 @@ class NetworkStatusDocument(stem.descriptor.Descriptor):
         raise ValueError("Network status documents must have a 'vote-status' line to say if they're a vote or consensus")
       
       is_consensus = header_entries['vote-status'][0][0] == "consensus"
+      is_vote = not is_consensus
       self._check_for_missing_and_disallowed_fields(is_consensus, header_entries, footer_entries)
       self._check_for_misordered_fields(is_consensus, header_entries, footer_entries)
+    
+    known_fields = [attr[0] for attr in HEADER_STATUS_DOCUMENT_FIELDS + FOOTER_STATUS_DOCUMENT_FIELDS]
+    content = header + '\n' + footer
+    
+    entries = dict()
+    entries.update(header_entries)
+    entries.update(footer_entries)
+    
+    for keyword, values in entries.items():
+      value, block_contents = values[0]
+      line = "%s %s" % (keyword, value)
+      
+      # All known fields can only appear once except...
+      # * 'directory-signature' in a consensus
+      
+      if validate and len(values) > 1 and keyword in known_fields:
+        if not (keyword == 'directory-signature' and is_consensus):
+          raise ValueError("Network status documents can only have a single '%s' line, got %i:\n%s" % (keyword, len(values), content))
   
   def _parse_old(self, raw_content, validate):
     # preamble
diff --git a/test/unit/descriptor/networkstatus/document.py b/test/unit/descriptor/networkstatus/document.py
index d2bbe90..ef77391 100644
--- a/test/unit/descriptor/networkstatus/document.py
+++ b/test/unit/descriptor/networkstatus/document.py
@@ -186,4 +186,32 @@ class TestNetworkStatusDocument(unittest.TestCase):
         content = "\n".join(test_lines)
         self.assertRaises(ValueError, NetworkStatusDocument, content)
         NetworkStatusDocument(content, False) # constructs without validation
+  
+  def test_duplicate_fields(self):
+    """
+    Almost all fields can only appear once. Checking that duplicates cause
+    validation errors.
+    """
+    
+    for is_consensus in (True, False):
+      attr = {"vote-status": "consensus"} if is_consensus else {"vote-status": "vote"}
+      lines = get_network_status_document(attr).split("\n")
+      
+      for i in xrange(len(lines)):
+        # Stop when we hit the 'directory-signature' for a couple reasons...
+        # - that is the one field that can validly appear multiple times
+        # - after it is a crypto blob, which won't trigger this kind of
+        #   validation failure
+        
+        test_lines = list(lines)
+        if test_lines[i].startswith("directory-signature "):
+          break
+        
+        # duplicates the line
+        test_lines.insert(i, test_lines[i])
+        
+        content = "\n".join(test_lines)
+        self.assertRaises(ValueError, NetworkStatusDocument, content)
+        NetworkStatusDocument(content, False) # constructs without validation
+
 





More information about the tor-commits mailing list