[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Supporting bridge descriptor's router-digest field
commit e7e03d2f61d6dcc7bc5e5ad4dee91c37a814ee16
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Wed May 23 09:52:23 2012 -0700
Supporting bridge descriptor's router-digest field
Scrubbed bridge server and extra-info descriptors will soon have a
'router-digest' line which contains the server digest. This is a value that we
can't calculate for ourselves because, of course, the descriptor's contents
have been modified.
I'm flagging this as being a required field. This does not yet parse it in
extra-info descriptors since it neither has a digest() method nor did I realize
that bridge extra-info descriptors were special.
---
stem/descriptor/server_descriptor.py | 52 ++++++++++++++++++--------
test/integ/descriptor/data/bridge_descriptor | 1 +
test/integ/descriptor/server_descriptor.py | 1 +
test/unit/descriptor/server_descriptor.py | 41 ++++++++++++++++++++-
4 files changed, 78 insertions(+), 17 deletions(-)
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 9a91d60..0014ff5 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -11,13 +11,13 @@ etc). This information is provided from a few sources...
parse_file - Iterates over the server descriptors in a file.
ServerDescriptor - Tor server descriptor.
| |- RelayDescriptor - Server descriptor for a relay.
- | | |- is_valid - checks the signature against the descriptor content
- | | +- digest - calculates the digest value for our content
+ | | +- is_valid - checks the signature against the descriptor content
| |
| +- BridgeDescriptor - Scrubbed server descriptor for a bridge.
| |- is_scrubbed - checks if our content has been properly scrubbed
| +- get_scrubbing_issues - description of issues with our scrubbing
|
+ |- digest - calculates the digest value for our content
|- get_unrecognized_lines - lines with unrecognized content
|- get_annotations - dictionary of content prior to the descriptor entry
+- get_annotation_lines - lines that provided the annotations
@@ -248,6 +248,21 @@ class ServerDescriptor(stem.descriptor.Descriptor):
self._parse(entries, validate)
if validate: self._check_constraints(entries, first_keyword, last_keyword)
+ def digest(self):
+ """
+ Provides the base64 encoded sha1 of our content. This value is part of the
+ server descriptor entry for this relay.
+
+ Note that network status entries exclude the padding, so you'll need to add
+ a '=' to it so they'll match...
+ https://en.wikipedia.org/wiki/Base64#Padding
+
+ Returns:
+ str with the digest value for this server descriptor
+ """
+
+ raise NotImplementedError("Unsupported Operation: this should be implemented by the ServerDescriptor subclass")
+
def get_unrecognized_lines(self):
return list(self._unrecognized_lines)
@@ -566,18 +581,6 @@ class RelayDescriptor(ServerDescriptor):
raise NotImplementedError # TODO: implement
def digest(self):
- """
- Provides the base64 encoded sha1 of our content. This value is part of the
- server descriptor entry for this relay.
-
- Note that network status entries exclude the padding, so you'll need to add
- a '=' to it so they'll match...
- https://en.wikipedia.org/wiki/Base64#Padding
-
- Returns:
- str with the digest value for this server descriptor
- """
-
if self._digest is None:
# our digest is calculated from everything except our signature
raw_content, ending = str(self), "\nrouter-signature\n"
@@ -642,15 +645,28 @@ class BridgeDescriptor(ServerDescriptor):
def __init__(self, raw_contents, validate = True, annotations = None):
self.address_alt = []
+ self._digest = None
self._scrubbing_issues = None
ServerDescriptor.__init__(self, raw_contents, validate, annotations)
+ def digest(self):
+ return self._digest
+
def _parse(self, entries, validate):
entries = dict(entries)
# handles fields only in bridge descriptors
for keyword, values in entries.items():
- if keyword == "or-address":
+ value, block_contents = values[0]
+ line = "%s %s" % (keyword, value)
+
+ if keyword == "router-digest":
+ if validate and not re.match("^[0-9a-fA-F]{40}$", value):
+ raise ValueError("Router digest line had an invalid sha1 digest: %s" % line)
+
+ self._digest = value
+ del entries["router-digest"]
+ elif keyword == "or-address":
or_address_entries = [value for (value, _) in values]
for entry in or_address_entries:
@@ -741,7 +757,11 @@ class BridgeDescriptor(ServerDescriptor):
"router-signature",
)
- return filter(lambda e: not e in excluded_fields, REQUIRED_FIELDS)
+ included_fields = (
+ "router-digest",
+ )
+
+ return included_fields + filter(lambda e: not e in excluded_fields, REQUIRED_FIELDS)
def _single_fields(self):
return self._required_fields() + SINGLE_FIELDS
diff --git a/test/integ/descriptor/data/bridge_descriptor b/test/integ/descriptor/data/bridge_descriptor
index 07dffe2..b7dbd92 100644
--- a/test/integ/descriptor/data/bridge_descriptor
+++ b/test/integ/descriptor/data/bridge_descriptor
@@ -1,5 +1,6 @@
@type bridge-server-descriptor 1.0
router Unnamed 10.45.227.253 9001 0 0
+router-digest 006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4
or-address [fd9f:2e19:3bcf::02:9970]:9001
platform Tor 0.2.3.12-alpha (git-800942b4176ca31c) on Linux x86_64
opt protocols Link 1 2 Circuit 1
diff --git a/test/integ/descriptor/server_descriptor.py b/test/integ/descriptor/server_descriptor.py
index afe3c93..180e82c 100644
--- a/test/integ/descriptor/server_descriptor.py
+++ b/test/integ/descriptor/server_descriptor.py
@@ -307,5 +307,6 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
self.assertEquals(819200, desc.burst_bandwidth)
self.assertEquals(5120, desc.observed_bandwidth)
self.assertEquals(["reject *:*"], desc.exit_policy)
+ self.assertEquals("006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4", desc.digest())
self.assertEquals([], desc.get_unrecognized_lines())
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index e381318..0eb4891 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -27,6 +27,7 @@ RELAY_DESCRIPTOR_ATTR = (
BRIDGE_DESCRIPTOR_ATTR = (
("router", "Unnamed 10.45.227.253 9001 0 0"),
+ ("router-digest", "006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4"),
("published", "2012-03-22 17:34:38"),
("bandwidth", "409600 819200 5120"),
("reject", "*:*"),
@@ -319,6 +320,7 @@ class TestServerDescriptor(unittest.TestCase):
self.assertEquals("Unnamed", desc.nickname)
self.assertEquals("10.45.227.253", desc.address)
self.assertEquals(None, desc.fingerprint)
+ self.assertEquals("006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4", desc.digest())
# check that we don't have crypto fields
self.assertRaises(AttributeError, getattr, desc, "onion_key")
@@ -352,10 +354,47 @@ class TestServerDescriptor(unittest.TestCase):
its unsanatized content.
"""
- desc_text = _make_descriptor()
+ desc_text = _make_descriptor({"router-digest": "006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4"})
desc = BridgeDescriptor(desc_text)
self.assertFalse(desc.is_scrubbed())
+ def test_router_digest(self):
+ """
+ Constructs with a router-digest line with both valid and invalid contents.
+ """
+
+ # checks with valid content
+
+ router_digest = "068A2E28D4C934D9490303B7A645BA068DCA0504"
+ desc_text = _make_descriptor({"router-digest": router_digest}, is_bridge = True)
+ desc = BridgeDescriptor(desc_text)
+ self.assertEquals(router_digest, desc.digest())
+
+ # checks when missing
+
+ desc_text = _make_descriptor(exclude = ["router-digest"], is_bridge = True)
+ self.assertRaises(ValueError, BridgeDescriptor, desc_text)
+
+ # check that we can still construct it without validation
+ desc = BridgeDescriptor(desc_text, validate = False)
+ self.assertEquals(None, desc.digest())
+
+ # checks with invalid content
+
+ test_values = (
+ "",
+ "006FD96BA35E7785A6A3B8B75FE2E2435A13BDB44",
+ "006FD96BA35E7785A6A3B8B75FE2E2435A13BDB",
+ "006FD96BA35E7785A6A3B8B75FE2E2435A13BDBH",
+ )
+
+ for value in test_values:
+ desc_text = _make_descriptor({"router-digest": value}, is_bridge = True)
+ self.assertRaises(ValueError, BridgeDescriptor, desc_text)
+
+ desc = BridgeDescriptor(desc_text, validate = False)
+ self.assertEquals(value, desc.digest())
+
def test_or_address_v4(self):
"""
Constructs a bridge descriptor with a sanatized IPv4 or-address entry.
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits