commit e810cc093a6469e26fe57789f064cb627f017e64 Author: Damian Johnson atagar@torproject.org Date: Mon Nov 19 10:43:00 2018 -0800
Parse 'bandwidth-file-digest' lines from votes
Parsing of a newly added field...
https://gitweb.torproject.org/torspec.git/commit/?id=1b686ef --- docs/change_log.rst | 3 ++- stem/descriptor/networkstatus.py | 21 +++++++++++++++++++ test/unit/descriptor/networkstatus/document_v3.py | 25 +++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index 0c427784..2fb3ae7e 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -53,6 +53,7 @@ The following are only available within Stem's `git repository
* Added :func:`~stem.descriptor.Descriptor.type_annotation` method (:trac:`28397`) * Added the **hash_type** and **encoding** arguments to `ServerDescriptor <api/descriptor/server_descriptor.html#stem.descriptor.server_descriptor.ServerDescriptor.digest>`_ and `ExtraInfo's <api/descriptor/extrainfo_descriptor.html#stem.descriptor.extrainfo_descriptor.ExtraInfoDescriptor.digest>`_ digest methods (:trac:`28398`) + * Added the network status vote's new bandwidth_file_digest attribute (:spec:`1b686ef`) * Added :func:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3.is_valid` and :func:`~stem.descriptor.networkstatus.NetworkStatusDocumentV3.is_fresh` methods (:trac:`28448`) * DescriptorDownloader crashed if **use_mirrors** is set (:trac:`28393`) * Don't download from Serge, a bridge authority that frequently timeout @@ -102,7 +103,7 @@ and the `stem.directory module <api/directory.html>`_. * `Fallback directory v2 support https://lists.torproject.org/pipermail/tor-dev/2017-December/012721.html`_, which adds *nickname* and *extrainfo* * Added the *orport_v6* attribute to the :class:`~stem.directory.Authority` class * Added server descriptor's new is_hidden_service_dir attribute - * Added the network status vote's new bandwidth_file attribute (:spec:`84591df`) + * Added the network status vote's new bandwidth_file_headers attribute (:spec:`84591df`) * Added the microdescriptor router status entry's new or_addresses attribute (:trac:`26405`, :spec:`fdc8f3e8`) * Don't retry downloading descriptors when we've timed out * Don't download from tor26, an authority that frequently timeout diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py index 6c14097f..bc34f5b4 100644 --- a/stem/descriptor/networkstatus.py +++ b/stem/descriptor/networkstatus.py @@ -135,6 +135,7 @@ HEADER_STATUS_DOCUMENT_FIELDS = ( ('shared-rand-previous-value', True, True, False), ('shared-rand-current-value', True, True, False), ('bandwidth-file-headers', True, False, False), + ('bandwidth-file-digest', True, False, False), ('recommended-client-protocols', True, True, False), ('recommended-relay-protocols', True, True, False), ('required-client-protocols', True, True, False), @@ -796,6 +797,18 @@ def _parse_bandwidth_file_headers(descriptor, entries): descriptor.bandwidth_file_headers = results
+def _parse_bandwidth_file_digest(descriptor, entries): + # "bandwidth-file-digest" 1*(SP algorithm "=" digest) + + value = _value('bandwidth-file-digest', entries) + results = {} + + for key, val in _mappings_for('bandwidth-file-digest', value): + results[key] = val + + descriptor.bandwidth_file_digest = results + + _parse_header_valid_after_line = _parse_timestamp_line('valid-after', 'valid_after') _parse_header_fresh_until_line = _parse_timestamp_line('fresh-until', 'fresh_until') _parse_header_valid_until_line = _parse_timestamp_line('valid-until', 'valid_until') @@ -867,6 +880,9 @@ class NetworkStatusDocumentV3(NetworkStatusDocument): :var dict required_relay_protocols: required protocols for relays :var dict bandwidth_file_headers: headers from the bandwidth authority that generated this vote + :var dict bandwidth_file_digest: hashes of the bandwidth authority file used + to generate this vote, this is a mapping of hash functions to their resulting + digest value
***** attribute is either required when we're parsed with validation or has a default value, others are left as None if undefined @@ -898,6 +914,9 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
.. versionchanged:: 1.7.0 Added the bandwidth_file_headers attributbute. + + .. versionchanged:: 1.8.0 + Added the bandwidth_file_digest attributbute. """
ATTRIBUTES = { @@ -929,6 +948,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument): 'shared_randomness_current_reveal_count': (None, _parse_shared_rand_current_value), 'shared_randomness_current_value': (None, _parse_shared_rand_current_value), 'bandwidth_file_headers': ({}, _parse_bandwidth_file_headers), + 'bandwidth_file_digest': ({}, _parse_bandwidth_file_digest),
'signatures': ([], _parse_footer_directory_signature_line), 'bandwidth_weights': ({}, _parse_footer_bandwidth_weights_line), @@ -957,6 +977,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument): 'shared-rand-previous-value': _parse_shared_rand_previous_value, 'shared-rand-current-value': _parse_shared_rand_current_value, 'bandwidth-file-headers': _parse_bandwidth_file_headers, + 'bandwidth-file-digest': _parse_bandwidth_file_digest, }
FOOTER_PARSER_FOR_LINE = { diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py index a9e5f35b..92100141 100644 --- a/test/unit/descriptor/networkstatus/document_v3.py +++ b/test/unit/descriptor/networkstatus/document_v3.py @@ -1312,6 +1312,31 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w= document = NetworkStatusDocumentV3(content, False) self.assertEqual({}, document.bandwidth_file_headers)
+ def test_bandwidth_file_digest(self): + """ + Parses a 'bandwidth-file-digest' line of votes. + """ + + test_values = { + '': {}, + 'sha1=': {'sha1': ''}, + 'sha1=abc=def': {'sha1': 'abc=def'}, + 'sha1=123': {'sha1': '123'}, + 'sha1=123 sha256=456': {'sha1': '123', 'sha256': '456'}, + } + + for test_value, expected_value in test_values.items(): + document = NetworkStatusDocumentV3.create({'vote-status': 'vote', 'bandwidth-file-digest': test_value}) + self.assertEqual(expected_value, document.bandwidth_file_digest) + + # field must be key=value mappings + + content = NetworkStatusDocumentV3.content({'vote-status': 'vote', 'bandwidth-file-digest': 'key_without_value'}) + self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True) + + document = NetworkStatusDocumentV3(content, False) + self.assertEqual({}, document.bandwidth_file_digest) + def test_with_legacy_directory_authorities(self): """ Includes both normal authorities and those following the '-legacy' format.