commit 4863c2281c26660a249378e65354a00e406fffbc
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Aug 19 18:15:47 2013 -0700
Validating that votes only have a single authority entry
Vote documents should only contain an entry from the authority that issued it.
I was checking this in my consensus-checker monitor but Karsten made the good
point that the check belongs in stem.
---
stem/descriptor/networkstatus.py | 3 +++
test/mocking.py | 5 +++++
test/unit/descriptor/networkstatus/document_v3.py | 21 ++++++++++++++++-----
3 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index 6258fdc..9142e63 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -518,6 +518,9 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
extra_args = (self._header.is_vote,),
))
+ if validate and self._header.is_vote and len(self.directory_authorities) != 1:
+ raise ValueError("Votes should only have an authority entry for the one that issued it, got %i: %s" % (len(self.directory_authorities), self.directory_authorities))
+
if not self._header.is_microdescriptor:
router_type = stem.descriptor.router_status_entry.RouterStatusEntryV3
else:
diff --git a/test/mocking.py b/test/mocking.py
index aebbaac..0d0c2e6 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -589,6 +589,11 @@ def get_network_status_document_v3(attr = None, exclude = (), authorities = None
"consensus-methods": "1 9",
"published": "2012-09-02 22:00:00",
}
+
+ # votes need an authority to be valid
+
+ if authorities is None:
+ authorities = [get_directory_authority(is_vote = True)]
else:
extra_defaults = {
"consensus-method": "9",
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index ece95de..71ef8b6 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -105,7 +105,6 @@ class TestNetworkStatusDocument(unittest.TestCase):
self.assertEqual(expected_known_flags, document.known_flags)
self.assertEqual({}, document.flag_thresholds)
self.assertEqual(DEFAULT_PARAMS, document.params)
- self.assertEqual((), document.directory_authorities)
self.assertEqual({}, document.bandwidth_weights)
self.assertEqual([DOC_SIG], document.signatures)
self.assertEqual([], document.get_unrecognized_lines())
@@ -218,10 +217,12 @@ class TestNetworkStatusDocument(unittest.TestCase):
lines = get_network_status_document_v3(attr, content = True).split(b"\n")
for index in xrange(len(lines) - 1):
- # once we reach the crypto blob we're done since swapping those won't
- # be detected
+ # once we reach the authority entry or later we're done since swapping
+ # those won't be detected
- if lines[index].startswith(stem.util.str_tools._to_bytes(CRYPTO_BLOB[1:10])):
+ if is_consensus and lines[index].startswith(stem.util.str_tools._to_bytes(CRYPTO_BLOB[1:10])):
+ break
+ elif not is_consensus and lines[index].startswith('dir-source'):
break
# swaps this line with the one after it
@@ -243,6 +244,9 @@ class TestNetworkStatusDocument(unittest.TestCase):
lines = get_network_status_document_v3(attr, content = True).split(b"\n")
for index, line in enumerate(lines):
+ if not is_consensus and lines[index].startswith('dir-source'):
+ break
+
# 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
@@ -856,7 +860,14 @@ class TestNetworkStatusDocument(unittest.TestCase):
content = get_network_status_document_v3({"vote-status": vote_status}, authorities = (authority1, authority2), content = True)
if is_document_vote == is_authorities_vote:
- document = NetworkStatusDocumentV3(content)
+ if is_document_vote:
+ # votes can only have a single authority
+
+ self.assertRaises(ValueError, NetworkStatusDocumentV3, content)
+ document = NetworkStatusDocumentV3(content, validate = False)
+ else:
+ document = NetworkStatusDocumentV3(content)
+
self.assertEquals((authority1, authority2), document.directory_authorities)
else:
# authority votes in a consensus or consensus authorities in a vote