commit 15ed89f92087d50c0646b373e8c43153948550e9 Author: Damian Johnson atagar@torproject.org Date: Tue Mar 21 21:40:51 2017 +0100
Adding _to_int() helper to str_tools
Replacing our cert module's _bytes_to_long() helper with a tested counterpart in str_tools. Not sure if it matters but should be more efficient. Rather than doing a 'unicode => bytes => hex => int' conversion we directly convert to the integer representation. --- stem/descriptor/certificate.py | 18 ++++++------------ stem/util/str_tools.py | 16 ++++++++++++++++ test/unit/util/str_tools.py | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py index 528d594..191e87e 100644 --- a/stem/descriptor/certificate.py +++ b/stem/descriptor/certificate.py @@ -2,8 +2,8 @@ # See LICENSE for licensing information
""" -Parsing for the Tor server descriptor Ed25519 Certificates, which is used to -validate the Ed25519 key used to sign the relay descriptor. +Parsing for Tor Ed25519 certificates, which is used to validate the key used to +sign server descriptors.
Certificates can optionally contain CertificateExtension objects depending on their type and purpose. Currently Ed25519KeyCertificate certificates will @@ -41,16 +41,9 @@ CERTIFICATE_FLAGS_LENGTH = 4 ED25519_ROUTER_SIGNATURE_PREFIX = b'Tor router descriptor signature v1'
-def _bytes_to_long(b): - if stem.prereq.is_python_3(): - return int(binascii.hexlify(stem.util.str_tools._to_bytes(b)), 16) - else: - return long(binascii.hexlify(b), 16) - - def _parse_long_offset(offset, length): def _parse(raw_contents): - return _bytes_to_long(raw_contents[offset:(offset + length)]) + return stem.util.str_tools._to_int(raw_contents[offset:(offset + length)])
return _parse
@@ -82,7 +75,8 @@ def _parse_certificate(raw_contents, master_key_bytes, validate = False):
def _parse_extensions(raw_contents): - n_extensions = _bytes_to_long(raw_contents[39:40]) + n_extensions = stem.util.str_tools._to_int(raw_contents[39:40]) + if n_extensions == 0: return []
@@ -90,7 +84,7 @@ def _parse_extensions(raw_contents): extension_bytes = raw_contents[STANDARD_ATTRIBUTES_LENGTH:-SIGNATURE_LENGTH]
while len(extension_bytes) > 0: - ext_length = _bytes_to_long(extension_bytes[0:2]) + ext_length = stem.util.str_tools._to_int(extension_bytes[0:2]) ext_type = extension_bytes[2:3] ext_flags = extension_bytes[3:CERTIFICATE_FLAGS_LENGTH] ext_data = extension_bytes[CERTIFICATE_FLAGS_LENGTH:(CERTIFICATE_FLAGS_LENGTH + ext_length)] diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py index 0fbdf38..8c6463a 100644 --- a/stem/util/str_tools.py +++ b/stem/util/str_tools.py @@ -117,6 +117,22 @@ def _to_unicode(msg): return _to_unicode_impl(msg)
+def _to_int(msg): + """ + Serializes a string to a number. + + :param str msg: string to be serialized + + :returns: **int** representation of the string + """ + + if stem.prereq.is_python_3() and isinstance(msg, bytes): + # iterating over bytes in python3 provides ints rather than characters + return sum([pow(256, (len(msg) - i - 1)) * c for (i, c) in enumerate(msg)]) + else: + return sum([pow(256, (len(msg) - i - 1)) * ord(c) for (i, c) in enumerate(msg)]) + + def _to_camel_case(label, divider = '_', joiner = ' '): """ Converts the given string to camel case, ie: diff --git a/test/unit/util/str_tools.py b/test/unit/util/str_tools.py index 3d0936f..00e5c55 100644 --- a/test/unit/util/str_tools.py +++ b/test/unit/util/str_tools.py @@ -9,6 +9,23 @@ from stem.util import str_tools
class TestStrTools(unittest.TestCase): + def test_to_int(self): + """ + Checks the _to_int() function. + """ + + test_inputs = { + '': 0, + 'h': 104, + 'hi': 26729, + 'hello': 448378203247, + str_tools._to_bytes('hello'): 448378203247, + str_tools._to_unicode('hello'): 448378203247, + } + + for arg, expected in test_inputs.items(): + self.assertEqual(expected, str_tools._to_int(arg)) + def test_to_camel_case(self): """ Checks the _to_camel_case() function.