commit 528503f9e5b1157c9410eea5cbce82025c194459 Author: Damian Johnson atagar@torproject.org Date: Wed Feb 25 10:11:16 2015 -0800
get_hidden_service_descriptor() helper for testing them
Adding a helper for generating hidden service descriptors. This is done for all of our descriptor types, and helps us test individual fields. Presently just checking that the minimal descriptor it generates is valid. --- stem/descriptor/hidden_service_descriptor.py | 4 +- test/mocking.py | 44 +++++++++++++++++++++ test/unit/descriptor/hidden_service_descriptor.py | 20 ++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/stem/descriptor/hidden_service_descriptor.py b/stem/descriptor/hidden_service_descriptor.py index 68997ab..f247b07 100644 --- a/stem/descriptor/hidden_service_descriptor.py +++ b/stem/descriptor/hidden_service_descriptor.py @@ -254,7 +254,9 @@ class HiddenServiceDescriptor(Descriptor): # TODO: Support fields encrypted with a desriptor-cookie. Need sample data # to implement this.
- if not self.introduction_points_content.startswith('introduction-point '): + if not self.introduction_points_content: + return [] + elif not self.introduction_points_content.startswith('introduction-point '): raise DecryptionFailure('introduction-point content is encrypted')
introduction_points = [] diff --git a/test/mocking.py b/test/mocking.py index fdfc71d..604beec 100644 --- a/test/mocking.py +++ b/test/mocking.py @@ -33,14 +33,19 @@ Helper functions for creating mock objects. get_router_status_entry_v2 - RouterStatusEntryV2 get_router_status_entry_v3 - RouterStatusEntryV3 get_router_status_entry_micro_v3 - RouterStatusEntryMicroV3 + + stem.descriptor.hidden-service_descriptor + get_hidden_service_descriptor - HiddenServiceDescriptor """
import base64 import hashlib import itertools import re +import textwrap
import stem.descriptor.extrainfo_descriptor +import stem.descriptor.hidden_service_descriptor import stem.descriptor.microdescriptor import stem.descriptor.networkstatus import stem.descriptor.router_status_entry @@ -178,6 +183,20 @@ NETWORK_STATUS_DOCUMENT_FOOTER = ( ('directory-signature', '%s %s\n%s' % (DOC_SIG.identity, DOC_SIG.key_digest, DOC_SIG.signature)), )
+HIDDEN_SERVICE_HEADER = ( + ('rendezvous-service-descriptor', 'y3olqqblqw2gbh6phimfuiroechjjafa'), + ('version', '2'), + ('permanent-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB), + ('secret-id-part', 'e24kgecavwsznj7gpbktqsiwgvngsf4e'), + ('publication-time', '2015-02-23 20:00:00'), + ('protocol-versions', '2,3'), + ('introduction-points', '\n-----BEGIN MESSAGE-----\n-----END MESSAGE-----'), +) + +HIDDEN_SERVICE_FOOTER = ( + ('signature', '\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB), +) +
def get_all_combinations(attr, include_empty = False): """ @@ -499,6 +518,31 @@ def get_router_status_entry_micro_v3(attr = None, exclude = (), content = False) return stem.descriptor.router_status_entry.RouterStatusEntryMicroV3(desc_content, validate = True)
+def get_hidden_service_descriptor(attr = None, exclude = (), content = False, introduction_points_lines = None): + """ + Provides the descriptor content for... + stem.descriptor.hidden_service_descriptor.HidenServiceDescriptor + + :param dict attr: keyword/value mappings to be included in the descriptor + :param list exclude: mandatory keywords to exclude from the descriptor + :param bool content: provides the str content of the descriptor rather than the class if True + :param list introduction_points_lines: lines to be included in the introduction-points field + + :returns: HidenServiceDescriptor for the requested descriptor content + """ + + if introduction_points_lines is not None: + encoded = base64.b64encode(introduction_points_lines('\n')) + attr['introduction-points'] = '\n-----BEGIN MESSAGE-----\n%s\n-----END MESSAGE-----' % '\n'.join(textwrap.wrap(encoded, 64)) + + desc_content = _get_descriptor_content(attr, exclude, HIDDEN_SERVICE_HEADER, HIDDEN_SERVICE_FOOTER) + + if content: + return desc_content + else: + return stem.descriptor.hidden_service_descriptor.HiddenServiceDescriptor(desc_content, validate = True) + + def get_directory_authority(attr = None, exclude = (), is_vote = False, content = False): """ Provides the descriptor content for... diff --git a/test/unit/descriptor/hidden_service_descriptor.py b/test/unit/descriptor/hidden_service_descriptor.py index a430b06..1a1c14d 100644 --- a/test/unit/descriptor/hidden_service_descriptor.py +++ b/test/unit/descriptor/hidden_service_descriptor.py @@ -7,6 +7,7 @@ import unittest
import stem.descriptor
+from test.mocking import CRYPTO_BLOB, get_hidden_service_descriptor from test.unit.descriptor import get_resource
EXPECTED_DDG_PERMANENT_KEY = """\ @@ -238,3 +239,22 @@ class TestHiddenServiceDescriptor(unittest.TestCase): self.assertEqual(EXPECT_POINT_3_ONION_KEY, point.onion_key) self.assertEqual(EXPECT_POINT_3_SERVICE_KEY, point.service_key) self.assertEqual([], point.intro_authentication) + + def test_minimal_hidden_service_descriptor(self): + """ + Basic sanity check that we can parse a hidden service descriptor with minimal attributes. + """ + + desc = get_hidden_service_descriptor() + + self.assertEqual('y3olqqblqw2gbh6phimfuiroechjjafa', desc.descriptor_id) + self.assertEqual(2, desc.version) + self.assertTrue(CRYPTO_BLOB in desc.permanent_key) + self.assertEqual('e24kgecavwsznj7gpbktqsiwgvngsf4e', desc.secret_id_part) + self.assertEqual(datetime.datetime(2015, 2, 23, 20, 0, 0), desc.published) + self.assertEqual([2, 3], desc.protocol_versions) + self.assertEqual('-----BEGIN MESSAGE-----\n-----END MESSAGE-----', desc.introduction_points_encoded) + self.assertEqual([], desc.introduction_points_auth) + self.assertEqual('', desc.introduction_points_content) + self.assertTrue(CRYPTO_BLOB in desc.signature) + self.assertEqual([], desc.introduction_points())