[tor-commits] [stem/master] Supporting footers in pre-version 9 method documents

atagar at torproject.org atagar at torproject.org
Sat Jan 12 18:50:02 UTC 2013


commit 98a8842c9ab800f9891a01caf35d02f2dfc60809
Author: Damian Johnson <atagar at torproject.org>
Date:   Sat Jan 12 10:46:39 2013 -0800

    Supporting footers in pre-version 9 method documents
    
    All version 3 network status documents can have a footer. The caveat is that
    prior to consensus method 9 they just contained signatures, and after that they
    were a properly marked 'directory-footer' section.
    
    Reproed the issue that Karsten discovered in 'https://trac.torproject.org/7932'
    via our unit tests then fixed.
---
 stem/descriptor/networkstatus.py                  |   22 +++++++++++++++-----
 test/mocking.py                                   |   22 +++++++++++++++++++-
 test/unit/descriptor/networkstatus/document_v3.py |   17 ++++++++++++++++
 3 files changed, 53 insertions(+), 8 deletions(-)

diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index e3d5779..cef668a 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -115,7 +115,7 @@ HEADER_STATUS_DOCUMENT_FIELDS = (
 )
 
 FOOTER_STATUS_DOCUMENT_FIELDS = (
-  ("directory-footer", True, True, True),
+  ("directory-footer", True, True, False),
   ("bandwidth-weights", False, True, False),
   ("directory-signature", True, True, True),
 )
@@ -482,7 +482,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
       validate,
       entry_class = DirectoryAuthority,
       entry_keyword = AUTH_START,
-      section_end_keywords = (ROUTERS_START, FOOTER_START),
+      section_end_keywords = (ROUTERS_START, FOOTER_START, V2_FOOTER_START),
       extra_args = (self._header.is_vote,),
     ))
 
@@ -496,7 +496,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
       validate,
       entry_class = router_type,
       entry_keyword = ROUTERS_START,
-      section_end_keywords = (FOOTER_START,),
+      section_end_keywords = (FOOTER_START, V2_FOOTER_START),
       extra_args = (self,),
     ))
 
@@ -746,15 +746,25 @@ class _DocumentFooter(object):
     self._unrecognized_lines = []
 
     content = document_file.read()
-    if validate and content and not header.meets_consensus_method(9):
-      raise ValueError("Network status document's footer should only appear in consensus-method 9 or later")
-    elif not content and not header.meets_consensus_method(9):
+
+    if not content:
       return  # footer is optional and there's nothing to parse
 
     entries = stem.descriptor._get_descriptor_components(content, validate)
     self._parse(entries, validate, header)
 
     if validate:
+      # Check that the footer has the right initial line. Prior to consensus
+      # method 9 it's a 'directory-signature' and after that footers start with
+      # 'directory-footer'.
+
+      if header.meets_consensus_method(9):
+        if entries.keys()[0] != 'directory-footer':
+          raise ValueError("Network status document's footer should start with a 'directory-footer' line in consensus-method 9 or later")
+      else:
+        if entries.keys()[0] != 'directory-signature':
+          raise ValueError("Network status document's footer should start with a 'directory-signature' line prior to consensus-method 9")
+
       _check_for_missing_and_disallowed_fields(header, entries, FOOTER_STATUS_DOCUMENT_FIELDS)
       _check_for_misordered_fields(entries, FOOTER_FIELDS)
 
diff --git a/test/mocking.py b/test/mocking.py
index e92bacd..82b9790 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -864,12 +864,30 @@ def get_network_status_document_v3(attr = None, exclude = (), authorities = None
 
   # inject the authorities and/or routers between the header and footer
   if authorities:
-    footer_div = desc_content.find("\ndirectory-footer") + 1
+    if "directory-footer" in desc_content:
+      footer_div = desc_content.find("\ndirectory-footer") + 1
+    elif "directory-signature" in desc_content:
+      footer_div = desc_content.find("\ndirectory-signature") + 1
+    else:
+      if routers:
+        desc_content += "\n"
+
+      footer_div = len(desc_content) + 1
+
     authority_content = "\n".join([str(a) for a in authorities]) + "\n"
     desc_content = desc_content[:footer_div] + authority_content + desc_content[footer_div:]
 
   if routers:
-    footer_div = desc_content.find("\ndirectory-footer") + 1
+    if "directory-footer" in desc_content:
+      footer_div = desc_content.find("\ndirectory-footer") + 1
+    elif "directory-signature" in desc_content:
+      footer_div = desc_content.find("\ndirectory-signature") + 1
+    else:
+      if routers:
+        desc_content += "\n"
+
+      footer_div = len(desc_content) + 1
+
     router_content = "\n".join([str(r) for r in routers]) + "\n"
     desc_content = desc_content[:footer_div] + router_content + desc_content[footer_div:]
 
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index 42603b1..4ea6347 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -549,6 +549,23 @@ class TestNetworkStatusDocument(unittest.TestCase):
     self.assertEqual([], document.signatures)
     self.assertEqual([], document.get_unrecognized_lines())
 
+    # Prior to conensus method 9 votes can still have a signature in their
+    # footer...
+    #
+    # https://trac.torproject.org/7932
+
+    document = get_network_status_document_v3(
+      {
+        "vote-status": "vote",
+        "consensus-methods": "1 8",
+      },
+      exclude = ("directory-footer",),
+      authorities = (get_directory_authority(is_vote = True),)
+    )
+
+    self.assertEqual([DOC_SIG], document.signatures)
+    self.assertEqual([], document.get_unrecognized_lines())
+
   def test_footer_with_value(self):
     """
     Tries to parse a descriptor with content on the 'directory-footer' line.



More information about the tor-commits mailing list