commit e47abb9f6ed81f39bcb09cd4e8bfb202488f695f Author: Damian Johnson atagar@torproject.org Date: Thu Aug 22 16:48:04 2019 -0700
Parse version field
Trivial parsing for the first field. Mostly still just wiring things up. --- stem/descriptor/hidden_service.py | 49 ++++++++++++++++++++++++++++++- test/unit/descriptor/hidden_service_v3.py | 34 ++++++++++++++++++--- 2 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py index 1ed100ef..4baad548 100644 --- a/stem/descriptor/hidden_service.py +++ b/stem/descriptor/hidden_service.py @@ -145,7 +145,14 @@ def _parse_file(descriptor_file, desc_type = None, validate = False, **kwargs):
def _parse_version_line(descriptor, entries): - value = _value('version', entries) + if isinstance(descriptor, HiddenServiceDescriptorV2): + keyword = 'version' + elif isinstance(descriptor, HiddenServiceDescriptorV3): + keyword = 'hs-descriptor' + else: + raise ValueError('BUG: unexpected descriptor type (%s)' % type(descriptor).__name__) + + value = _value(keyword, entries)
if value.isdigit(): descriptor.version = int(value) @@ -463,12 +470,52 @@ class HiddenServiceDescriptorV2(BaseHiddenServiceDescriptor): class HiddenServiceDescriptorV3(BaseHiddenServiceDescriptor): """ Version 3 hidden service descriptor. + + :var int version: **\*** hidden service descriptor version + + **\*** attribute is either required when we're parsed with validation or has + a default value, others are left as **None** if undefined """
# TODO: requested this @type on https://trac.torproject.org/projects/tor/ticket/31481
TYPE_ANNOTATION_NAME = 'hidden-service-descriptor-3'
+ ATTRIBUTES = { + 'version': (None, _parse_version_line), + } + + PARSER_FOR_LINE = { + 'hs-descriptor': _parse_version_line, + } + + @classmethod + def content(cls, attr = None, exclude = (), sign = False): + if sign: + raise NotImplementedError('Signing of %s not implemented' % cls.__name__) + + return _descriptor_content(attr, exclude, ( + ('hs-descriptor', '3'), + ('descriptor-lifetime', '180'), + ('descriptor-signing-key-cert', _random_crypto_blob('ED25519 CERT')), + ('revision-counter', '15'), + ('superencrypted', _random_crypto_blob('MESSAGE')), + ('signature', 'wdc7ffr+dPZJ/mIQ1l4WYqNABcmsm6SHW/NL3M3wG7bjjqOJWoPR5TimUXxH52n5Zk0Gc7hl/hz3YYmAx5MvAg'), + ), ()) + + @classmethod + def create(cls, attr = None, exclude = (), validate = True, sign = False): + return cls(cls.content(attr, exclude, sign), validate = validate, skip_crypto_validation = not sign) + + def __init__(self, raw_contents, validate = False, skip_crypto_validation = False): + super(HiddenServiceDescriptorV3, self).__init__(raw_contents, lazy_load = not validate) + entries = _descriptor_components(raw_contents, validate) + + if validate: + self._parse(entries, validate) + else: + self._entries = entries +
# TODO: drop this alias in stem 2.x
diff --git a/test/unit/descriptor/hidden_service_v3.py b/test/unit/descriptor/hidden_service_v3.py index 757c1944..04a95a6d 100644 --- a/test/unit/descriptor/hidden_service_v3.py +++ b/test/unit/descriptor/hidden_service_v3.py @@ -2,18 +2,44 @@ Unit tests for stem.descriptor.hidden_service for version 3. """
+import functools import unittest
import stem.descriptor
-from test.unit.descriptor import get_resource +from stem.descriptor.hidden_service import HiddenServiceDescriptorV3 + +from test.unit.descriptor import ( + get_resource, + base_expect_invalid_attr, +) + +expect_invalid_attr = functools.partial(base_expect_invalid_attr, HiddenServiceDescriptorV3, 'version', 3)
class TestHiddenServiceDescriptorV3(unittest.TestCase): - def test_stub(self): - # TODO: replace with actual field assertions as the class gets implemented + def test_for_riseup(self): + """ + Parse riseup's descriptor... + + vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion + """
with open(get_resource('hidden_service_v3'), 'rb') as descriptor_file: desc = next(stem.descriptor.parse_file(descriptor_file, 'hidden-service-descriptor-3 1.0', validate = True))
- self.assertTrue('hs-descriptor 3' in str(desc)) + self.assertEqual(3, desc.version) + + def test_invalid_version(self): + """ + Checks that our version field expects a numeric value. + """ + + test_values = ( + '', + '-10', + 'hello', + ) + + for test_value in test_values: + expect_invalid_attr(self, {'hs-descriptor': test_value}, 'version')