commit 906c998ab7eee705a33e738fc401dfde04cf882c Author: Damian Johnson atagar@torproject.org Date: Tue Apr 10 09:36:58 2018 -0700
Add is_hidden_service_dir to server descriptors
The hidden service directory version is obsolete, but the presence or lack of 'hidden-service-dir' lines are still meaningful...
https://gitweb.torproject.org/torspec.git/commit/?id=43c2f78
Adding a boolean attribute indicate if we have the flag.
Noticed this thanks to our static checks, which informed me I buggered up my earlier change by ignoring the descriptor's data...
STATIC CHECKS * /home/atagar/Desktop/stem/stem/descriptor/server_descriptor.py line 342 - local variable 'value' is assigned to but never used | value = _value('hidden-service-dir', entries) --- docs/change_log.rst | 1 + stem/descriptor/server_descriptor.py | 24 +++++++++++++----------- test/unit/descriptor/server_descriptor.py | 12 +++++++----- 3 files changed, 21 insertions(+), 16 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index a67aae2d..b0773382 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -56,6 +56,7 @@ The following are only available within Stem's `git repository
* `Fallback directory v2 support https://lists.torproject.org/pipermail/tor-dev/2017-December/012721.html`_, which adds *nickname* and *extrainfo* * Added zstd and lzma compression support (:spec:`1cb56af`) + * Added server descriptor's new is_hidden_service_dir attribute * Reduced maximum descriptors fetched by the remote module to match tor's new limit (:trac:`24743`) * Consensus **shared_randomness_*_reveal_count** attributes undocumented, and unavailable if retrieved before their corresponding shared_randomness_*_value attribute (:trac:`25046`) * Allow 'proto' line to have blank values (:spec:`a8455f4`) diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py index 4f2bcbec..63a3d069 100644 --- a/stem/descriptor/server_descriptor.py +++ b/stem/descriptor/server_descriptor.py @@ -338,16 +338,6 @@ def _parse_hibernating_line(descriptor, entries): descriptor.hibernating = value == '1'
-def _parse_hidden_service_dir_line(descriptor, entries): - value = _value('hidden-service-dir', entries) - - # TODO: Remove the following field in Stem 2.0. It has never been populated... - # - # https://gitweb.torproject.org/torspec.git/commit/?id=43c2f78 - - descriptor.hidden_service_dir = ['2'] - - def _parse_uptime_line(descriptor, entries): # We need to be tolerant of negative uptimes to accommodate a past tor # bug... @@ -450,6 +440,7 @@ _parse_ipv6_policy_line = _parse_simple_line('ipv6-policy', 'exit_policy_v6', fu _parse_allow_single_hop_exits_line = _parse_if_present('allow-single-hop-exits', 'allow_single_hop_exits') _parse_tunneled_dir_server_line = _parse_if_present('tunnelled-dir-server', 'allow_tunneled_dir_requests') _parse_proto_line = _parse_protocol_line('proto', 'protocols') +_parse_hidden_service_dir_line = _parse_if_present('hidden-service-dir', 'is_hidden_service_dir') _parse_caches_extra_info_line = _parse_if_present('caches-extra-info', 'extra_info_cache') _parse_bridge_distribution_request_line = _parse_simple_line('bridge-distribution-request', 'bridge_distribution') _parse_family_line = _parse_simple_line('family', 'family', func = lambda v: set(v.split(' '))) @@ -495,6 +486,8 @@ class ServerDescriptor(Descriptor):
:var list link_protocols: link protocols supported by the relay :var list circuit_protocols: circuit protocols supported by the relay + :var bool is_hidden_service_dir: ***** indicates if the relay serves hidden + service descriptors :var bool hibernating: ***** hibernating when published :var bool allow_single_hop_exits: ***** flag if single hop exiting is allowed :var bool allow_tunneled_dir_requests: ***** flag if tunneled directory @@ -530,6 +523,9 @@ class ServerDescriptor(Descriptor): attributes.
.. versionchanged:: 1.7.0 + Added the is_hidden_service_dir attribute. + + .. versionchanged:: 1.7.0 Deprecated the hidden_service_dir field, it's never been populated (:spec:`43c2f78`). This field will be removed in Stem 2.0. """ @@ -560,6 +556,7 @@ class ServerDescriptor(Descriptor):
'link_protocols': (None, _parse_protocols_line), 'circuit_protocols': (None, _parse_protocols_line), + 'is_hidden_service_dir': (False, _parse_hidden_service_dir_line), 'hibernating': (False, _parse_hibernating_line), 'allow_single_hop_exits': (False, _parse_allow_single_hop_exits_line), 'allow_tunneled_dir_requests': (False, _parse_tunneled_dir_server_line), @@ -567,7 +564,6 @@ class ServerDescriptor(Descriptor): 'extra_info_cache': (False, _parse_caches_extra_info_line), 'extra_info_digest': (None, _parse_extrainfo_digest_line), 'extra_info_sha256_digest': (None, _parse_extrainfo_digest_line), - 'hidden_service_dir': (None, _parse_hidden_service_dir_line), 'eventdns': (None, _parse_eventdns_line), 'ntor_onion_key': (None, _parse_ntor_onion_key_line), 'or_addresses': ([], _parse_or_address_line), @@ -638,6 +634,12 @@ class ServerDescriptor(Descriptor):
entries, self._unparsed_exit_policy = _descriptor_components(stem.util.str_tools._to_unicode(raw_contents), validate, extra_keywords = ('accept', 'reject'), non_ascii_fields = ('contact', 'platform'))
+ # TODO: Remove the following field in Stem 2.0. It has never been populated... + # + # https://gitweb.torproject.org/torspec.git/commit/?id=43c2f78 + + self.hidden_service_dir = ['2'] + if validate: self._parse(entries, validate)
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py index f392b44f..99d3c38e 100644 --- a/test/unit/descriptor/server_descriptor.py +++ b/test/unit/descriptor/server_descriptor.py @@ -134,13 +134,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual(b'www.atagar.com/contact', desc.contact) self.assertEqual(['1', '2'], desc.link_protocols) self.assertEqual(['1'], desc.circuit_protocols) + self.assertEqual(True, desc.is_hidden_service_dir) self.assertEqual(False, desc.hibernating) self.assertEqual(False, desc.allow_single_hop_exits) self.assertEqual(False, desc.allow_tunneled_dir_requests) self.assertEqual(False, desc.extra_info_cache) self.assertEqual('D225B728768D7EA4B5587C13A7A9D22EBBEE6E66', desc.extra_info_digest) self.assertEqual(None, desc.extra_info_sha256_digest) - self.assertEqual(['2'], desc.hidden_service_dir) self.assertEqual(BridgeDistribution.ANY, desc.bridge_distribution) self.assertEqual(expected_family, desc.family) self.assertEqual(153600, desc.average_bandwidth) @@ -156,6 +156,8 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual([], desc.get_unrecognized_lines()) self.assertEqual('2C7B27BEAB04B4E2459D89CA6D5CD1CC5F95A689', desc.digest())
+ self.assertEqual(['2'], desc.hidden_service_dir) # obsolete field + def test_metrics_descriptor_multiple(self): """ Parses and checks our results against a server descriptor from metrics. @@ -194,13 +196,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual(None, desc.contact) self.assertEqual(None, desc.link_protocols) self.assertEqual(None, desc.circuit_protocols) + self.assertEqual(False, desc.is_hidden_service_dir) self.assertEqual(True, desc.hibernating) self.assertEqual(False, desc.allow_single_hop_exits) self.assertEqual(False, desc.allow_tunneled_dir_requests) self.assertEqual(False, desc.extra_info_cache) self.assertEqual(None, desc.extra_info_digest) self.assertEqual(None, desc.extra_info_sha256_digest) - self.assertEqual(None, desc.hidden_service_dir) self.assertEqual(BridgeDistribution.ANY, desc.bridge_distribution) self.assertEqual(set(), desc.family) self.assertEqual(102400, desc.average_bandwidth) @@ -243,13 +245,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual(b'1024D/04D2E818 L\xc3\xa9na\xc3\xafc Huard <lenaic dot huard AT laposte dot net>', desc.contact) self.assertEqual(['1', '2'], desc.link_protocols) self.assertEqual(['1'], desc.circuit_protocols) + self.assertEqual(True, desc.is_hidden_service_dir) self.assertEqual(False, desc.hibernating) self.assertEqual(False, desc.allow_single_hop_exits) self.assertEqual(False, desc.allow_tunneled_dir_requests) self.assertEqual(False, desc.extra_info_cache) self.assertEqual('56403D838DE152421CD401B8E57DAD4483A3D56B', desc.extra_info_digest) self.assertEqual(None, desc.extra_info_sha256_digest) - self.assertEqual(['2'], desc.hidden_service_dir) self.assertEqual(BridgeDistribution.ANY, desc.bridge_distribution) self.assertEqual(set(), desc.family) self.assertEqual(102400, desc.average_bandwidth) @@ -389,13 +391,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual(b'0x02225522 Frenn vun der Enn (FVDE) <info AT enn DOT lu>', desc.contact) self.assertEqual(['1', '2'], desc.link_protocols) self.assertEqual(['1'], desc.circuit_protocols) + self.assertEqual(True, desc.is_hidden_service_dir) self.assertEqual(False, desc.hibernating) self.assertEqual(False, desc.allow_single_hop_exits) self.assertEqual(False, desc.allow_tunneled_dir_requests) self.assertEqual(False, desc.extra_info_cache) self.assertEqual('44E9B679AF0B4EB09296985BAF4066AE9CA5BB93', desc.extra_info_digest) self.assertEqual('r+roMxhsjd1GPpn5knQoBvtE9Rhsv8zQHCqiYL6u2CA', desc.extra_info_sha256_digest) - self.assertEqual(['2'], desc.hidden_service_dir) self.assertEqual(family, desc.family) self.assertEqual(149715200, desc.average_bandwidth) self.assertEqual(1048576000, desc.burst_bandwidth) @@ -500,13 +502,13 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= self.assertEqual(None, desc.contact) self.assertEqual(['1', '2'], desc.link_protocols) self.assertEqual(['1'], desc.circuit_protocols) + self.assertEqual(False, desc.is_hidden_service_dir) self.assertEqual(False, desc.hibernating) self.assertEqual(False, desc.allow_single_hop_exits) self.assertEqual(False, desc.allow_tunneled_dir_requests) self.assertEqual(True, desc.extra_info_cache) self.assertEqual('BB1F13AA431421BEA29B840A2E33BB1C31C2990B', desc.extra_info_digest) self.assertEqual(None, desc.extra_info_sha256_digest) - self.assertEqual(None, desc.hidden_service_dir) self.assertEqual(BridgeDistribution.ANY, desc.bridge_distribution) self.assertEqual(set(), desc.family) self.assertEqual(3220480, desc.average_bandwidth)