[tor-commits] [stem/master] Randomize created server descirptor fields
atagar at torproject.org
atagar at torproject.org
Tue Jun 27 15:35:07 UTC 2017
commit 25bf050edf71a7653970aa9ab41d70e4b4219b63
Author: Damian Johnson <atagar at torproject.org>
Date: Tue Jun 27 08:31:40 2017 -0700
Randomize created server descirptor fields
Now that we're providing a method to create descriptors to callers (rather than
just our own tests) we should randomize the default attributes. Gonna do this
with all descriptor types, but starting with server descriptors since we just
added signing for 'em.
---
run_tests.py | 40 +++++++++++++------------------
stem/descriptor/__init__.py | 22 +++++++++++++++++
stem/descriptor/server_descriptor.py | 36 +++++++++++++++-------------
test/unit/descriptor/__init__.py | 6 ++---
test/unit/descriptor/export.py | 5 +++-
test/unit/descriptor/server_descriptor.py | 9 ++++---
test/unit/tutorial.py | 2 +-
7 files changed, 71 insertions(+), 49 deletions(-)
diff --git a/run_tests.py b/run_tests.py
index 802a6b4..c0d9cbc 100755
--- a/run_tests.py
+++ b/run_tests.py
@@ -310,10 +310,8 @@ def main():
_print_static_issues(static_check_issues)
- runtime_label = '(%i seconds)' % (time.time() - start_time)
-
if error_tracker.has_errors_occured():
- println('TESTING FAILED %s' % runtime_label, ERROR, STDERR)
+ println('TESTING FAILED (%i seconds)' % (time.time() - start_time), ERROR, STDERR)
for line in error_tracker:
println(' %s' % line, ERROR, STDERR)
@@ -329,7 +327,7 @@ def main():
if skipped_tests > 0:
println('%i TESTS WERE SKIPPED' % skipped_tests, STATUS)
- println('TESTING PASSED %s\n' % runtime_label, SUCCESS)
+ println('TESTING PASSED (%i seconds)\n' % (time.time() - start_time), SUCCESS)
new_capabilities = test.get_new_capabilities()
@@ -369,26 +367,23 @@ def _print_static_issues(static_check_issues):
def _run_test(args, test_class, output_filters, logging_buffer):
start_time = time.time()
+ # Test classes look like...
+ #
+ # test.unit.util.conf.TestConf.test_parse_enum_csv
+ #
+ # We want to strip the 'test.unit.' or 'test.integ.' prefix since it's
+ # redundant. We also want to drop the test class name. The individual test
+ # name at the end it optional (only present if we used the '--test'
+ # argument).
+
+ label_comp = test_class.split('.')[2:]
+ del label_comp[-1 if label_comp[-1][0].isupper() else -2]
+ test_label = ' %-52s' % ('.'.join(label_comp) + '...')
+
if args.verbose:
test.output.print_divider(test_class)
else:
- # Test classes look like...
- #
- # test.unit.util.conf.TestConf.test_parse_enum_csv
- #
- # We want to strip the 'test.unit.' or 'test.integ.' prefix since it's
- # redundant. We also want to drop the test class name. The individual test
- # name at the end it optional (only present if we used the '--test'
- # argument).
-
- label_comp = test_class.split('.')[2:]
- del label_comp[-1 if label_comp[-1][0].isupper() else -2]
- label = '.'.join(label_comp)
-
- label = ' %s...' % label
- label = '%-54s' % label
-
- println(label, STATUS, NO_NL)
+ println(test_label, STATUS, NO_NL)
try:
suite = unittest.TestLoader().loadTestsFromName(test_class)
@@ -413,7 +408,7 @@ def _run_test(args, test_class, output_filters, logging_buffer):
println(' success (%0.2fs)' % (time.time() - start_time), SUCCESS)
else:
if args.quiet:
- println(label, STATUS, NO_NL, STDERR)
+ println(test_label, STATUS, NO_NL, STDERR)
println(' failed (%0.2fs)' % (time.time() - start_time), ERROR, STDERR)
println(test.output.apply_filters(test_results.getvalue(), *output_filters), STDERR)
else:
@@ -421,7 +416,6 @@ def _run_test(args, test_class, output_filters, logging_buffer):
println(test.output.apply_filters(test_results.getvalue(), *output_filters), NO_NL)
test.output.print_logging(logging_buffer)
-
return run_result
diff --git a/stem/descriptor/__init__.py b/stem/descriptor/__init__.py
index bf336fb..80901af 100644
--- a/stem/descriptor/__init__.py
+++ b/stem/descriptor/__init__.py
@@ -42,6 +42,7 @@ import codecs
import copy
import hashlib
import os
+import random
import re
import string
import tarfile
@@ -952,6 +953,27 @@ def _get_pseudo_pgp_block(remaining_contents):
return None
+def _random_ipv4_address():
+ return '%i.%i.%i.%i' % (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
+
+
+def _random_date():
+ return '%i-%02i-%02i %02i:%02i:%02i' % (random.randint(2000, 2015), random.randint(1, 12), random.randint(1, 20), random.randint(0, 23), random.randint(0, 59), random.randint(0, 59))
+
+
+def _random_crypto_blob(block_type = None):
+ """
+ Provides a random string that can be used for crypto blocks.
+ """
+
+ crypto_blob = stem.util.str_tools._split_by_length(base64.b64encode('%0140x' % random.randrange(16 ** 140)), 64)
+
+ if block_type:
+ return '\n-----BEGIN %s-----\n%s\n-----END %s-----' % (block_type, crypto_blob, block_type)
+ else:
+ return crypto_blob
+
+
def _descriptor_components(raw_contents, validate, extra_keywords = (), non_ascii_fields = ()):
"""
Initial breakup of the server descriptor contents to make parsing easier.
diff --git a/stem/descriptor/server_descriptor.py b/stem/descriptor/server_descriptor.py
index 8dbd0f0..607908d 100644
--- a/stem/descriptor/server_descriptor.py
+++ b/stem/descriptor/server_descriptor.py
@@ -35,7 +35,9 @@ import base64
import binascii
import functools
import hashlib
+import random
import re
+import sys
import stem.descriptor.certificate
import stem.descriptor.extrainfo_descriptor
@@ -49,7 +51,6 @@ import stem.version
from stem.util import str_type
from stem.descriptor import (
- CRYPTO_BLOB,
PGP_BLOCK_END,
Descriptor,
_descriptor_content,
@@ -65,6 +66,9 @@ from stem.descriptor import (
_parse_forty_character_hex,
_parse_protocol_line,
_parse_key_block,
+ _random_ipv4_address,
+ _random_date,
+ _random_crypto_blob,
)
try:
@@ -112,19 +116,6 @@ SINGLE_FIELDS = (
DEFAULT_IPV6_EXIT_POLICY = stem.exit_policy.MicroExitPolicy('reject 1-65535')
REJECT_ALL_POLICY = stem.exit_policy.ExitPolicy('reject *:*')
-RELAY_SERVER_HEADER = (
- ('router', 'caerSidi 71.35.133.197 9001 0 0'),
- ('published', '2012-03-01 17:15:27'),
- ('bandwidth', '153600 256000 104590'),
- ('reject', '*:*'),
- ('onion-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
- ('signing-key', '\n-----BEGIN RSA PUBLIC KEY-----%s-----END RSA PUBLIC KEY-----' % CRYPTO_BLOB),
-)
-
-RELAY_SERVER_FOOTER = (
- ('router-signature', '\n-----BEGIN SIGNATURE-----%s-----END SIGNATURE-----' % CRYPTO_BLOB),
-)
-
BRIDGE_SERVER_HEADER = (
('router', 'Unnamed 10.45.227.253 9001 0 0'),
('router-digest', '006FD96BA35E7785A6A3B8B75FE2E2435A13BDB4'),
@@ -818,6 +809,19 @@ class RelayDescriptor(ServerDescriptor):
@classmethod
def content(cls, attr = None, exclude = (), sign = False, private_signing_key = None):
+ base_header = (
+ ('router', 'Unnamed%i %s 9001 0 0' % (random.randint(0, sys.maxint), _random_ipv4_address())),
+ ('published', _random_date()),
+ ('bandwidth', '153600 256000 104590'),
+ ('reject', '*:*'),
+ ('onion-key', _random_crypto_blob('RSA PUBLIC KEY')),
+ ('signing-key', _random_crypto_blob('RSA PUBLIC KEY')),
+ )
+
+ base_footer = (
+ ('router-signature', _random_crypto_blob('SIGNATURE')),
+ )
+
if sign:
if not stem.prereq.is_crypto_available():
raise ImportError('Signing requires the cryptography module')
@@ -861,12 +865,12 @@ class RelayDescriptor(ServerDescriptor):
format = serialization.PublicFormat.PKCS1,
).strip()
- content = _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER) + b'\nrouter-signature\n'
+ content = _descriptor_content(attr, exclude, sign, base_header) + b'\nrouter-signature\n'
signature = base64.b64encode(private_signing_key.sign(content, padding.PKCS1v15(), hashes.SHA1()))
return content + b'\n'.join([b'-----BEGIN SIGNATURE-----'] + stem.util.str_tools._split_by_length(signature, 64) + [b'-----END SIGNATURE-----\n'])
else:
- return _descriptor_content(attr, exclude, sign, RELAY_SERVER_HEADER, RELAY_SERVER_FOOTER)
+ return _descriptor_content(attr, exclude, sign, base_header, base_footer)
@classmethod
def create(cls, attr = None, exclude = (), validate = True, sign = False, private_signing_key = None):
diff --git a/test/unit/descriptor/__init__.py b/test/unit/descriptor/__init__.py
index cd35ae1..bf0e861 100644
--- a/test/unit/descriptor/__init__.py
+++ b/test/unit/descriptor/__init__.py
@@ -29,7 +29,7 @@ def base_expect_invalid_attr(cls, default_attr, default_value, test, desc_attrs,
return base_expect_invalid_attr_for_text(cls, default_attr, default_value, test, cls.content(desc_attrs), attr, expected_value)
-def base_expect_invalid_attr_for_text(cls, default_attr, default_value, test, desc_text, attr = None, expected_value = None):
+def base_expect_invalid_attr_for_text(cls, default_attr, default_prefix, test, desc_text, attr = None, expected_value = None):
"""
Asserts that construction will fail due to desc_text having a malformed
attribute. If an attr is provided then we check that it matches an expected
@@ -44,7 +44,7 @@ def base_expect_invalid_attr_for_text(cls, default_attr, default_value, test, de
# constructed without validation
test.assertEqual(expected_value, getattr(desc, attr))
- elif default_attr and default_value:
- test.assertEqual(default_value, getattr(desc, default_attr)) # check a default attribute
+ elif default_attr and default_prefix:
+ test.assertTrue(getattr(desc, default_attr).startswith(default_prefix)) # check a default attribute
return desc
diff --git a/test/unit/descriptor/export.py b/test/unit/descriptor/export.py
index cd005d1..a33c1d4 100644
--- a/test/unit/descriptor/export.py
+++ b/test/unit/descriptor/export.py
@@ -25,7 +25,10 @@ class TestExport(unittest.TestCase):
self.skipTest('(header added in python 2.7)')
return
- desc = RelayDescriptor.create()
+ desc = RelayDescriptor.create({
+ 'router': 'caerSidi 71.35.133.197 9001 0 0',
+ 'published': '2012-03-01 17:15:27',
+ })
desc_csv = export_csv(desc, included_fields = ('nickname', 'address', 'published'), header = False)
expected = 'caerSidi,71.35.133.197,2012-03-01 17:15:27\n'
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py
index 227df12..2c47bdf 100644
--- a/test/unit/descriptor/server_descriptor.py
+++ b/test/unit/descriptor/server_descriptor.py
@@ -40,8 +40,8 @@ TARFILE_FINGERPRINTS = set([
str_type('1F43EE37A0670301AD9CB555D94AFEC2C89FDE86'),
])
-expect_invalid_attr = functools.partial(base_expect_invalid_attr, RelayDescriptor, 'nickname', 'caerSidi')
-expect_invalid_attr_for_text = functools.partial(base_expect_invalid_attr_for_text, RelayDescriptor, 'nickname', 'caerSidi')
+expect_invalid_attr = functools.partial(base_expect_invalid_attr, RelayDescriptor, 'nickname', 'Unnamed')
+expect_invalid_attr_for_text = functools.partial(base_expect_invalid_attr_for_text, RelayDescriptor, 'nickname', 'Unnamed')
class TestServerDescriptor(unittest.TestCase):
@@ -440,11 +440,10 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
attributes.
"""
- desc = RelayDescriptor.create()
+ desc = RelayDescriptor.create({'router': 'caerSidi 71.35.133.197 9001 0 0'})
self.assertEqual('caerSidi', desc.nickname)
self.assertEqual('71.35.133.197', desc.address)
self.assertEqual(None, desc.fingerprint)
- self.assertTrue(stem.descriptor.CRYPTO_BLOB in desc.onion_key)
def test_with_opt(self):
"""
@@ -625,7 +624,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4=
self.assertRaises(ValueError, list, desc_iter)
desc_text = b'@pepperjack very tasty\n at mushrooms not so much\n'
- desc_text += RelayDescriptor.content()
+ desc_text += RelayDescriptor.content({'router': 'caerSidi 71.35.133.197 9001 0 0'})
desc_iter = stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_text))
desc_entries = list(desc_iter)
diff --git a/test/unit/tutorial.py b/test/unit/tutorial.py
index cdfb014..b0f5b71 100644
--- a/test/unit/tutorial.py
+++ b/test/unit/tutorial.py
@@ -162,7 +162,7 @@ class TestTutorial(unittest.TestCase):
@patch('stem.descriptor.reader.DescriptorReader', spec = DescriptorReader)
def test_mirror_mirror_on_the_wall_4(self, reader_mock, stdout_mock):
reader = reader_mock().__enter__()
- reader.__iter__.return_value = iter([RelayDescriptor.create()])
+ reader.__iter__.return_value = iter([RelayDescriptor.create({'router': 'caerSidi 71.35.133.197 9001 0 0'})])
exec_documentation_example('past_descriptors.py')
self.assertEqual('found relay caerSidi (None)\n', stdout_mock.getvalue())
More information about the tor-commits
mailing list