[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Support for consensus' new package attribute
commit 51750b88553158d581bd1860a4c140d8f1336f9e
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Thu Mar 5 09:33:39 2015 -0800
Support for consensus' new package attribute
Support for the newly added pacakge field...
https://gitweb.torproject.org/torspec.git/commit/?id=ab6453476066fd1bf5c8cb577863c0cdd5079e0f
These don't appear to be in the actual consensus yet, but likely will soon. I
still have some questions about this field but this parsing apprach should work
for now.
https://trac.torproject.org/projects/tor/ticket/15157
---
docs/change_log.rst | 3 +-
stem/descriptor/hidden_service_descriptor.py | 2 +
stem/descriptor/microdescriptor.py | 3 ++
stem/descriptor/networkstatus.py | 55 ++++++++++++++++++++-
test/mocking.py | 1 +
test/unit/descriptor/networkstatus/document_v3.py | 42 ++++++++++++++++
6 files changed, 104 insertions(+), 2 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst
index c181fea..cdd7311 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -60,6 +60,7 @@ conversion (:trac:`14075`).
* Lazy-loading descriptors, improving performance by 25-70% depending on what type it is (:trac:`14011`)
* Added `support for hidden service descriptors <api/descriptor/hidden_service_descriptor.html>`_ (:trac:`15004`)
* The :class:`~stem.descriptor.networkstatus.DirectoryAuthority` 'fingerprint' attribute was actually its 'v3ident'
+ * Added consensus' new package attribute (:spec:`ab64534`)
* Updating Faravahar's address (:trac:`14487`)
* **Utilities**
@@ -155,7 +156,7 @@ among numerous other improvements and fixes. Released on **June 1st, 2014**.
* **Descriptors**
* Added tarfile support to :func:`~stem.descriptor.__init__.parse_file` (:trac:`10977`)
- * Added microdescriptor's new identity and identity_type attributes (:spec:`22cda72`)
+ * Added microdescriptor's new identifier and identifier_type attributes (:spec:`22cda72`)
* **Utilities**
diff --git a/stem/descriptor/hidden_service_descriptor.py b/stem/descriptor/hidden_service_descriptor.py
index 73f5edf..1292189 100644
--- a/stem/descriptor/hidden_service_descriptor.py
+++ b/stem/descriptor/hidden_service_descriptor.py
@@ -14,6 +14,8 @@ the HSDir flag.
::
HiddenServiceDescriptor - Tor hidden service descriptor.
+
+.. versionadded:: 1.4.0
"""
# TODO: Add a description for how to retrieve them when tor supports that
diff --git a/stem/descriptor/microdescriptor.py b/stem/descriptor/microdescriptor.py
index f4ffe94..ffbec43 100644
--- a/stem/descriptor/microdescriptor.py
+++ b/stem/descriptor/microdescriptor.py
@@ -196,6 +196,9 @@ class Microdescriptor(Descriptor):
:var str identifier: base64 encoded identity digest, this is only used for collision prevention (:trac:`11743`)
**\*** attribute is required when we're parsed with validation
+
+ .. versionchanged:: 1.1.0
+ Added the identifier and identifier_type attributes.
"""
ATTRIBUTES = {
diff --git a/stem/descriptor/networkstatus.py b/stem/descriptor/networkstatus.py
index f465e6f..a162e2e 100644
--- a/stem/descriptor/networkstatus.py
+++ b/stem/descriptor/networkstatus.py
@@ -47,8 +47,19 @@ For more information see :func:`~stem.descriptor.__init__.DocumentHandler`...
KeyCertificate - Certificate used to authenticate an authority
DocumentSignature - Signature of a document by a directory authority
DirectoryAuthority - Directory authority as defined in a v3 network status document
+
+
+.. data:: PackageVersion
+
+ Latest recommended version of a package that's available.
+
+ :var str name: name of the package
+ :var str version: latest recommended version
+ :var str url: package's url
+ :var dict digests: mapping of digest types to their value
"""
+import collections
import io
import stem.descriptor.router_status_entry
@@ -75,6 +86,13 @@ from stem.descriptor.router_status_entry import (
RouterStatusEntryMicroV3,
)
+PackageVersion = collections.namedtuple('PackageVersion', [
+ 'name',
+ 'version',
+ 'url',
+ 'digests',
+])
+
# Version 2 network status document fields, tuples of the form...
# (keyword, is_mandatory)
@@ -109,6 +127,7 @@ HEADER_STATUS_DOCUMENT_FIELDS = (
('voting-delay', True, True, True),
('client-versions', True, True, False),
('server-versions', True, True, False),
+ ('package', True, True, False),
('known-flags', True, True, True),
('flag-thresholds', True, False, False),
('params', True, True, False),
@@ -638,6 +657,30 @@ def _parse_footer_directory_signature_line(descriptor, entries):
descriptor.signatures = signatures
+def _parse_package_line(descriptor, entries):
+ package_versions = []
+
+ for value, _, _ in entries['package']:
+ value_comp = value.split()
+
+ if len(value_comp) < 3:
+ raise ValueError("'package' must at least have a 'PackageName Version URL': %s" % value)
+
+ name, version, url = value_comp[:3]
+ digests = {}
+
+ for digest_entry in value_comp[3:]:
+ if '=' not in digest_entry:
+ raise ValueError("'package' digest entries should be 'key=value' pairs: %s" % value)
+
+ key, value = digest_entry.split('=', 1)
+ digests[key] = value
+
+ package_versions.append(PackageVersion(name, version, url, digests))
+
+ descriptor.packages = package_versions
+
+
_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')
@@ -669,6 +712,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
signatures from all authorities
:var list client_versions: list of recommended client tor versions
:var list server_versions: list of recommended server tor versions
+ :var list packages: **\*** list of :data:`~stem.descriptor.networkstatus.PackageVersion` entries
:var list known_flags: **\*** list of :data:`~stem.Flag` for the router's flags
:var dict params: **\*** dict of parameter(**str**) => value(**int**) mappings
:var list directory_authorities: **\*** list of :class:`~stem.descriptor.networkstatus.DirectoryAuthority`
@@ -689,6 +733,9 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
**\*** attribute is either required when we're parsed with validation or has
a default value, others are left as None if undefined
+
+ .. versionchanged:: 1.4.0
+ Added the packages attribute.
"""
ATTRIBUTES = {
@@ -707,6 +754,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
'dist_delay': (None, _parse_header_voting_delay_line),
'client_versions': ([], _parse_header_client_versions_line),
'server_versions': ([], _parse_header_server_versions_line),
+ 'packages': ([], _parse_package_line),
'known_flags': ([], _parse_header_known_flags_line),
'flag_thresholds': ({}, _parse_header_flag_thresholds_line),
'params': ({}, _parse_header_parameters_line),
@@ -727,6 +775,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
'voting-delay': _parse_header_voting_delay_line,
'client-versions': _parse_header_client_versions_line,
'server-versions': _parse_header_server_versions_line,
+ 'package': _parse_package_line,
'known-flags': _parse_header_known_flags_line,
'flag-thresholds': _parse_header_flag_thresholds_line,
'params': _parse_header_parameters_line,
@@ -820,7 +869,7 @@ class NetworkStatusDocumentV3(NetworkStatusDocument):
# all known header fields can only appear once except
for keyword, values in list(entries.items()):
- if len(values) > 1 and keyword in HEADER_FIELDS:
+ if len(values) > 1 and keyword in HEADER_FIELDS and keyword != 'package':
raise ValueError("Network status documents can only have a single '%s' line, got %i" % (keyword, len(values)))
if self._default_params:
@@ -1072,6 +1121,10 @@ class DirectoryAuthority(Descriptor):
authority's key certificate
**\*** mandatory attribute
+
+ .. versionchanged:: 1.4.0
+ Renamed our 'fingerprint' attribute to 'v3ident' (prior attribute exists
+ for backward compatability, but is deprecated).
"""
ATTRIBUTES = {
diff --git a/test/mocking.py b/test/mocking.py
index 156ac4a..27b0921 100644
--- a/test/mocking.py
+++ b/test/mocking.py
@@ -173,6 +173,7 @@ NETWORK_STATUS_DOCUMENT_HEADER = (
('voting-delay', '300 300'),
('client-versions', None),
('server-versions', None),
+ ('package', None),
('known-flags', 'Authority BadExit Exit Fast Guard HSDir Named Running Stable Unnamed V2Dir Valid'),
('params', None),
)
diff --git a/test/unit/descriptor/networkstatus/document_v3.py b/test/unit/descriptor/networkstatus/document_v3.py
index 2f847d7..f440bbf 100644
--- a/test/unit/descriptor/networkstatus/document_v3.py
+++ b/test/unit/descriptor/networkstatus/document_v3.py
@@ -15,6 +15,7 @@ from stem.descriptor.networkstatus import (
HEADER_STATUS_DOCUMENT_FIELDS,
FOOTER_STATUS_DOCUMENT_FIELDS,
DEFAULT_PARAMS,
+ PackageVersion,
DirectoryAuthority,
NetworkStatusDocumentV3,
_parse_file,
@@ -125,6 +126,7 @@ I/TJmV928na7RLZe2mGHCAW3VQOvV+QkCfj05VZ8CsY=
self.assertEqual(expected_versions, document.client_versions)
self.assertEqual(expected_versions, document.server_versions)
self.assertEqual(expected_flags, set(document.known_flags))
+ self.assertEqual([], document.packages)
self.assertEqual({'CircuitPriorityHalflifeMsec': 30000, 'bwauthpid': 1}, document.params)
self.assertEqual(12, document.consensus_method)
@@ -248,6 +250,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
self.assertEqual([], document.client_versions)
self.assertEqual([], document.server_versions)
self.assertEqual(expected_flags, set(document.known_flags))
+ self.assertEqual([], document.packages)
self.assertEqual({'CircuitPriorityHalflifeMsec': 30000, 'bwauthpid': 1}, document.params)
self.assertEqual(None, document.consensus_method)
@@ -325,6 +328,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
self.assertEqual([], document.client_versions)
self.assertEqual([], document.server_versions)
self.assertEqual(expected_known_flags, document.known_flags)
+ self.assertEqual([], document.packages)
self.assertEqual({}, document.flag_thresholds)
self.assertEqual(DEFAULT_PARAMS, document.params)
self.assertEqual((), document.directory_authorities)
@@ -359,6 +363,7 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
self.assertEqual([], document.client_versions)
self.assertEqual([], document.server_versions)
self.assertEqual(expected_known_flags, document.known_flags)
+ self.assertEqual([], document.packages)
self.assertEqual({}, document.flag_thresholds)
self.assertEqual(DEFAULT_PARAMS, document.params)
self.assertEqual({}, document.bandwidth_weights)
@@ -726,6 +731,43 @@ DnN5aFtYKiTc19qIC7Nmo+afPdDEf0MlJvEOP5EWl3w=
document = NetworkStatusDocumentV3(content, False)
self.assertEqual([], getattr(document, attr))
+ def test_packages(self):
+ """
+ Parse the package line. These can appear multiple times, and have any
+ number of digests.
+ """
+
+ test_values = (
+ (['Stem 1.3.0 https://stem.torproject.org/'],
+ [PackageVersion('Stem', '1.3.0', 'https://stem.torproject.org/', {})]),
+ (['Stem 1.3.0 https://stem.torproject.org/ sha1=5d676c8124b4be1f52ddc8e15ca143cad211eeb4 md5=600ad5e2fc4caf585c1bdaaa532b7e82'],
+ [PackageVersion('Stem', '1.3.0', 'https://stem.torproject.org/', {'sha1': '5d676c8124b4be1f52ddc8e15ca143cad211eeb4', 'md5': '600ad5e2fc4caf585c1bdaaa532b7e82'})]),
+ (['Stem 1.3.0 https://stem.torproject.org/', 'Txtorcon 0.13.0 https://github.com/meejah/txtorcon'],
+ [PackageVersion('Stem', '1.3.0', 'https://stem.torproject.org/', {}),
+ PackageVersion('Txtorcon', '0.13.0', 'https://github.com/meejah/txtorcon', {})]),
+ )
+
+ for test_value, expected_value in test_values:
+ document = get_network_status_document_v3({'package': '\npackage '.join(test_value)})
+ self.assertEqual(expected_value, document.packages)
+
+ test_values = (
+ '',
+ ' ',
+ 'Stem',
+ 'Stem 1.3.0',
+ 'Stem 1.3.0 https://stem.torproject.org/ keyword_field',
+ 'Stem 1.3.0 https://stem.torproject.org/ keyword_field key=value',
+ 'Stem 1.3.0 https://stem.torproject.org/ key=value keyword_field',
+ )
+
+ for test_value in test_values:
+ content = get_network_status_document_v3({'package': test_value}, content = True)
+ self.assertRaises(ValueError, NetworkStatusDocumentV3, content, True)
+
+ document = NetworkStatusDocumentV3(content, False)
+ self.assertEqual([], document.packages)
+
def test_known_flags(self):
"""
Parses some known-flag entries. Just exercising the field, there's not much
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits