[tor-commits] [stem/master] Supporting '-legacy' authority entries

atagar at torproject.org atagar at torproject.org
Thu Jan 10 16:38:50 UTC 2013


commit 153ada322653f95eb21c360d3cac4fe6ad436ed7
Author: Damian Johnson <atagar at torproject.org>
Date:   Thu Jan 10 08:37:17 2013 -0800

    Supporting '-legacy' authority entries
    
    Directory authorities have an alternative format if their nickname has a
    '-legacy' suffix. Caught by Karsten on...
    
    https://trac.torproject.org/7866
---
 stem/descriptor/networkstatus.py                   |   29 ++++++++++++++++---
 .../networkstatus/directory_authority.py           |   23 +++++++++++++++
 test/unit/descriptor/networkstatus/document_v3.py  |   15 ++++++++++
 3 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 5da190a..e3d5779 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -909,17 +909,24 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
   """
   Directory authority information obtained from a v3 network status document.
 
+  Authorities can optionally use a legacy format. These are no longer found in
+  practice, but have the following differences...
+
+  * The authority's nickname ends with '-legacy'.
+  * There's no **contact** or **vote_digest** attribute.
+
   :var str nickname: **\*** authority's nickname
   :var str fingerprint: **\*** authority's fingerprint
   :var str hostname: **\*** hostname of the authority
   :var str address: **\*** authority's IP address
   :var int dir_port: **\*** authority's DirPort
   :var int or_port: **\*** authority's ORPort
-  :var str contact: **\*** contact information
+  :var bool is_legacy: **\*** if the authority's using the legacy format
+  :var str contact: contact information, this is included if is_legacy is **False**
 
   **Consensus Attributes:**
 
-  :var str vote_digest: **\*** digest of the authority that contributed to the consensus
+  :var str vote_digest: digest of the authority that contributed to the consensus, this is included if is_legacy is **False**
 
   **Vote Attributes:**
 
@@ -950,6 +957,7 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
     self.address = None
     self.dir_port = None
     self.or_port = None
+    self.is_legacy = False
     self.contact = None
 
     self.vote_digest = None
@@ -990,7 +998,15 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
     # check that we have mandatory fields
 
     if validate:
-      required_fields, excluded_fields = ["dir-source", "contact"], []
+      is_legacy, dir_source_entry = False, entries.get("dir-source")
+
+      if dir_source_entry:
+        is_legacy = dir_source_entry[0][0].split()[0].endswith("-legacy")
+
+      required_fields, excluded_fields = ["dir-source"], []
+
+      if not is_legacy:
+        required_fields += ["contact"]
 
       if is_vote:
         if not key_cert_content:
@@ -1001,7 +1017,9 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
         if key_cert_content:
           raise ValueError("Authority consensus entries shouldn't have a key certificate:\n%s" % content)
 
-        required_fields += ["vote-digest"]
+        if not is_legacy:
+          required_fields += ["vote-digest"]
+
         excluded_fields += ["legacy-dir-key"]
 
       for keyword in required_fields:
@@ -1033,7 +1051,7 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
           raise ValueError("Authority entry's 'dir-source' line must have six values: %s" % line)
 
         if validate:
-          if not stem.util.tor_tools.is_valid_nickname(dir_source_comp[0]):
+          if not stem.util.tor_tools.is_valid_nickname(dir_source_comp[0].rstrip('-legacy')):
             raise ValueError("Authority's nickname is invalid: %s" % dir_source_comp[0])
           elif not stem.util.tor_tools.is_valid_fingerprint(dir_source_comp[1]):
             raise ValueError("Authority's fingerprint is invalid: %s" % dir_source_comp[1])
@@ -1055,6 +1073,7 @@ class DirectoryAuthority(stem.descriptor.Descriptor):
         self.address = dir_source_comp[3]
         self.dir_port = None if dir_source_comp[4] == '0' else int(dir_source_comp[4])
         self.or_port = int(dir_source_comp[5])
+        self.is_legacy = self.nickname.endswith("-legacy")
       elif keyword == 'contact':
         # "contact" string
 
diff --git a/test/unit/descriptor/networkstatus/directory_authority.py b/test/unit/descriptor/networkstatus/directory_authority.py
index eb685df..539b6b1 100644
--- a/test/unit/descriptor/networkstatus/directory_authority.py
+++ b/test/unit/descriptor/networkstatus/directory_authority.py
@@ -22,6 +22,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     self.assertEqual("76.73.17.194", authority.address)
     self.assertEqual(9030, authority.dir_port)
     self.assertEqual(9090, authority.or_port)
+    self.assertEqual(False, authority.is_legacy)
     self.assertEqual("Mike Perry <email>", authority.contact)
     self.assertEqual("0B6D1E9A300B895AA2D0B427F92917B6995C3C1C", authority.vote_digest)
     self.assertEqual(None, authority.legacy_dir_key)
@@ -41,6 +42,7 @@ class TestDirectoryAuthority(unittest.TestCase):
     self.assertEqual("76.73.17.194", authority.address)
     self.assertEqual(9030, authority.dir_port)
     self.assertEqual(9090, authority.or_port)
+    self.assertEqual(False, authority.is_legacy)
     self.assertEqual("Mike Perry <email>", authority.contact)
     self.assertEqual(None, authority.vote_digest)
     self.assertEqual(None, authority.legacy_dir_key)
@@ -55,6 +57,27 @@ class TestDirectoryAuthority(unittest.TestCase):
     authority = get_directory_authority({"pepperjack": "is oh so tasty!"})
     self.assertEquals(["pepperjack is oh so tasty!"], authority.get_unrecognized_lines())
 
+  def test_legacy_authority(self):
+    """
+    Parses an authority using the '-legacy' format.
+    """
+
+    content = "dir-source gabelmoo-legacy 81349FC1F2DBA2C2C11B45CB9706637D480AB913 212.112.245.170 212.112.245.170 80 443"
+    authority = DirectoryAuthority(content, is_vote = False)
+
+    self.assertEqual("gabelmoo-legacy", authority.nickname)
+    self.assertEqual("81349FC1F2DBA2C2C11B45CB9706637D480AB913", authority.fingerprint)
+    self.assertEqual("212.112.245.170", authority.hostname)
+    self.assertEqual("212.112.245.170", authority.address)
+    self.assertEqual(80, authority.dir_port)
+    self.assertEqual(443, authority.or_port)
+    self.assertEqual(True, authority.is_legacy)
+    self.assertEqual(None, authority.contact)
+    self.assertEqual(None, authority.vote_digest)
+    self.assertEqual(None, authority.legacy_dir_key)
+    self.assertEqual(None, authority.key_certificate)
+    self.assertEqual([], authority.get_unrecognized_lines())
+
   def test_first_line(self):
     """
     Includes a non-mandatory field before the 'dir-source' line.
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index d15e88a..42603b1 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -787,6 +787,21 @@ class TestNetworkStatusDocument(unittest.TestCase):
           document = NetworkStatusDocumentV3(content, validate = False)
           self.assertEquals((authority1, authority2), document.directory_authorities)
 
+  def test_with_legacy_directory_authorities(self):
+    """
+    Includes both normal authorities and those following the '-legacy' format.
+    """
+
+    legacy_content = "dir-source gabelmoo-legacy 81349FC1F2DBA2C2C11B45CB9706637D480AB913 212.112.245.170 212.112.245.170 80 443"
+
+    authority1 = get_directory_authority({'contact': 'doctor jekyll'}, is_vote = False)
+    authority2 = DirectoryAuthority(legacy_content, validate = True, is_vote = False)
+    authority3 = get_directory_authority({'contact': 'mister hyde'}, is_vote = False)
+
+    document = get_network_status_document_v3({"vote-status": "consensus"}, authorities = (authority1, authority2, authority3))
+
+    self.assertEquals((authority1, authority2, authority3), document.directory_authorities)
+
   def test_authority_validation_flag_propagation(self):
     """
     Includes invalid certificate content in an authority entry. This is testing



More information about the tor-commits mailing list