commit 399552ae06b56c7f703303e9d0c638253657d1bb Author: Isis Lovecruft isis@torproject.org Date: Wed Feb 11 21:58:51 2015 +0000
Deprecate the bridgedb.parse.networkstatus module.
* MOVE bridgedb.parse.networkstatus to bridgedb.test.deprecated_networkstatus and wrap all callables within with @twisted.python.deprecate.deprecated. * REMOVE the import of bridgedb.parse.networkstatus in bridgedb.Bridges module. * CHANGE legacy_Tests.py to import deprecated_networkstatus to continue to check for regressions in other parts of the codebase. * REMOVE bridgedb.test.test_parse_networkstatus.py. --- lib/bridgedb/Bridges.py | 1 - lib/bridgedb/parse/networkstatus.py | 263 ---------------- lib/bridgedb/test/deprecated_networkstatus.py | 275 ++++++++++++++++ lib/bridgedb/test/legacy_Tests.py | 2 +- lib/bridgedb/test/test_parse_networkstatus.py | 414 ------------------------- 5 files changed, 276 insertions(+), 679 deletions(-)
diff --git a/lib/bridgedb/Bridges.py b/lib/bridgedb/Bridges.py index 31b7cf6..bdb911a 100644 --- a/lib/bridgedb/Bridges.py +++ b/lib/bridgedb/Bridges.py @@ -25,7 +25,6 @@ import bridgedb.Bucket from bridgedb.bridges import Bridge from bridgedb.crypto import getHMACFunc from bridgedb.parse import addr -from bridgedb.parse import networkstatus from bridgedb.parse.fingerprint import toHex from bridgedb.parse.fingerprint import fromHex from bridgedb.parse.fingerprint import isValidFingerprint diff --git a/lib/bridgedb/parse/networkstatus.py b/lib/bridgedb/parse/networkstatus.py deleted file mode 100644 index 8140fe0..0000000 --- a/lib/bridgedb/parse/networkstatus.py +++ /dev/null @@ -1,263 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of BridgeDB, a Tor bridge distribution system. -# -# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 isis@torproject.org -# please also see AUTHORS file -# :copyright: (c) 2013 Isis Lovecruft -# (c) 2007-2014, The Tor Project, Inc. -# (c) 2007-2014, all entities within the AUTHORS file -# :license: 3-clause BSD, see included LICENSE for information - -"""Parsers for bridge networkstatus descriptors. - -.. py:module:: bridgedb.parse.networkstatus - :synopsis: Parsers for ``@type bridge-network-status`` descriptors_. -.. _descriptors: https://metrics.torproject.org/formats.html#descriptortypes - - -bridgedb.parse.networkstatus -============================ -:: - - networkstatus - |_ isValidRouterNickname - Determine if a nickname is according to spec - |_ parseRLine - Parse an 'r'-line from a networkstatus document - |_ parseALine - Parse an 'a'-line from a networkstatus document - _ parseSLine - Parse an 's'-line from a networkstatus document -.. -""" - -import binascii -import logging -import string -import time -import warnings - -from twisted.python.log import showwarning - -from bridgedb.parse import addr -from bridgedb.parse import parseUnpaddedBase64 -from bridgedb.parse import InvalidBase64 -from bridgedb.parse.nickname import InvalidRouterNickname -from bridgedb.parse.nickname import isValidRouterNickname - - -class NetworkstatusParsingError(Exception): - """Unable to parse networkstatus document line.""" - -class InvalidNetworkstatusRouterIdentity(ValueError): - """The ID field of a networkstatus document 'r'-line is invalid.""" - - -def parseRLine(line): - """Parse an 'r'-line from a networkstatus document. - - From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512: - | "r" SP nickname SP identity SP digest SP publication SP IP SP ORPort - | SP DirPort NL - | - | [At start, exactly once.] - | - | "Nickname" is the OR's nickname. "Identity" is a hash of its - | identity key, encoded in base64, with trailing equals sign(s) - | removed. "Digest" is a hash of its most recent descriptor as - | signed (that is, not including the signature), encoded in base64. - | "Publication" is the - | publication time of its most recent descriptor, in the form - | YYYY-MM-DD HH:MM:SS, in UTC. "IP" is its current IP address; - | ORPort is its current OR port, "DirPort" is its current directory - | port, or "0" for "none". - - :param string line: An 'r'-line from an bridge-network-status descriptor. - :returns: - A 7-tuple of:: - (nickname, identityDigest, descriptorDigest, timestamp, - orAddress, orPort, dirport) - where each value is set according to the data parsed from the - **line**, or ``None`` if nothing suitable could be parsed. - """ - (nickname, ID, descDigest, timestamp, - ORaddr, ORport, dirport) = (None for x in xrange(7)) - - try: - if not line.startswith('r '): - raise NetworkstatusParsingError( - "Networkstatus parser received non 'r'-line: %r" % line) - - line = line[2:] # Chop off the 'r ' - fields = line.split() - - if len(fields) != 8: - raise NetworkstatusParsingError( - "Wrong number of fields in networkstatus 'r'-line: %r" % line) - - nickname, ID = fields[:2] - - try: - ID = parseUnpaddedBase64(ID) - except InvalidBase64 as error: - raise InvalidNetworkstatusRouterIdentity(error) - - # Check the nickname validity after parsing the ID, otherwise, if the - # nickname is invalid, we end up with the nickname being ``None`` and - # the ID being unparsed, unpadded (meaning it is technically invalid) - # base64. - isValidRouterNickname(nickname) - - except NetworkstatusParsingError as error: - logging.error(error) - nickname, ID = None, None - except InvalidRouterNickname as error: - logging.error(error) - # Assume that we mostly care about obtaining the OR's ID, then it - # should be okay to set the nickname to ``None``, if it was invalid. - nickname = None - except InvalidNetworkstatusRouterIdentity as error: - logging.error(error) - ID = None - else: - try: - descDigest = parseUnpaddedBase64(fields[2]) - timestamp = time.mktime(time.strptime(" ".join(fields[3:5]), - "%Y-%m-%d %H:%M:%S")) - ORaddr = fields[5] - ORport = int(fields[6]) - dirport = fields[7] - except InvalidBase64 as error: - logging.error(error) - descDigest = None - except (AttributeError, ValueError, IndexError) as error: - logging.error(error) - timestamp = None - finally: - return (nickname, ID, descDigest, timestamp, ORaddr, ORport, dirport) - -def parseALine(line, fingerprint=None): - """Parse an 'a'-line of a bridge networkstatus document. - - From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512: - | - | "a" SP address ":" port NL - | - | [Any number.] - | - | Present only if the OR has at least one IPv6 address. - | - | Address and portlist are as for "or-address" as specified in - | 2.1. - | - | (Only included when the vote or consensus is generated with - | consensus-method 14 or later.) - - :param string line: An 'a'-line from an bridge-network-status descriptor. - :type fingerprint: string or None - :param fingerprint: A string which identifies which OR the descriptor - we're parsing came from (since the 'a'-line doesn't tell us, this can - help make the log messages clearer). - :raises: :exc:`NetworkstatusParsingError` - :rtype: tuple - :returns: A 2-tuple of a string respresenting the IP address and a - :class:`bridgedb.parse.addr.PortList`. - """ - ip = None - portlist = None - - if line.startswith('a '): - line = line[2:] # Chop off the 'a ' - else: - logging.warn("Networkstatus parser received non 'a'-line for %r:"\ - " %r" % (fingerprint or 'Unknown', line)) - - try: - ip, portlist = line.rsplit(':', 1) - except ValueError as error: - logging.error("Bad separator in networkstatus 'a'-line: %r" % line) - return (None, None) - - if ip.startswith('[') and ip.endswith(']'): - ip = ip.strip('[]') - - try: - if not addr.isIPAddress(ip): - raise NetworkstatusParsingError( - "Got invalid IP Address in networkstatus 'a'-line for %r: %r" - % (fingerprint or 'Unknown', line)) - - if addr.isIPv4(ip): - warnings.warn(FutureWarning( - "Got IPv4 address in networkstatus 'a'-line! "\ - "Networkstatus document format may have changed!")) - except NetworkstatusParsingError as error: - logging.error(error) - ip, portlist = None, None - - try: - portlist = addr.PortList(portlist) - if not portlist: - raise NetworkstatusParsingError( - "Got invalid portlist in 'a'-line for %r!\n Line: %r" - % (fingerprint or 'Unknown', line)) - except (addr.InvalidPort, NetworkstatusParsingError) as error: - logging.error(error) - portlist = None - else: - logging.debug("Parsed networkstatus ORAddress line for %r:"\ - "\n Address: %s \tPorts: %s" - % (fingerprint or 'Unknown', ip, portlist)) - finally: - return (ip, portlist) - -def parseSLine(line): - """Parse an 's'-line from a bridge networkstatus document. - - The 's'-line contains all flags assigned to a bridge. The flags which may - be assigned to a bridge are as follows: - - From torspec.git/dir-spec.txt, commit 36761c7d553d L1526-1554: - | - | "s" SP Flags NL - | - | [Exactly once.] - | - | A series of space-separated status flags, in lexical order (as ASCII - | byte strings). Currently documented flags are: - | - | "BadDirectory" if the router is believed to be useless as a - | directory cache (because its directory port isn't working, - | its bandwidth is always throttled, or for some similar - | reason). - | "Fast" if the router is suitable for high-bandwidth circuits. - | "Guard" if the router is suitable for use as an entry guard. - | "HSDir" if the router is considered a v2 hidden service directory. - | "Named" if the router's identity-nickname mapping is canonical, - | and this authority binds names. - | "Stable" if the router is suitable for long-lived circuits. - | "Running" if the router is currently usable. - | "Valid" if the router has been 'validated'. - | "V2Dir" if the router implements the v2 directory protocol. - - :param string line: An 's'-line from an bridge-network-status descriptor. - :rtype: tuple - :returns: A 2-tuple of booleans, the first is True if the bridge has the - "Running" flag, and the second is True if it has the "Stable" flag. - """ - line = line[2:] - - flags = [x.capitalize() for x in line.split()] - fast = 'Fast' in flags - running = 'Running' in flags - stable = 'Stable' in flags - guard = 'Guard' in flags - valid = 'Valid' in flags - - if (fast or running or stable or guard or valid): - logging.debug("Parsed Flags: %s%s%s%s%s" - % ('Fast ' if fast else '', - 'Running ' if running else '', - 'Stable ' if stable else '', - 'Guard ' if guard else '', - 'Valid ' if valid else '')) - - # Right now, we only care about 'Running' and 'Stable' - return running, stable diff --git a/lib/bridgedb/test/deprecated_networkstatus.py b/lib/bridgedb/test/deprecated_networkstatus.py new file mode 100644 index 0000000..7e3b0a4 --- /dev/null +++ b/lib/bridgedb/test/deprecated_networkstatus.py @@ -0,0 +1,275 @@ +# -*- coding: utf-8 -*- +# +# This file is part of BridgeDB, a Tor bridge distribution system. +# +# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 isis@torproject.org +# please also see AUTHORS file +# :copyright: (c) 2013 Isis Lovecruft +# (c) 2007-2014, The Tor Project, Inc. +# (c) 2007-2014, all entities within the AUTHORS file +# :license: 3-clause BSD, see included LICENSE for information + +"""Parsers for bridge networkstatus descriptors. + +THIS ENTIRE MODULE WAS DEPRECATED (AS PART OF #9380_) AND WAS REPLACED WITH +THE CORRESPONDING FUNCTIONS IN :mod:`bridgedb.parse.descriptors`. + +.. #9380: https://bugs.torproject.org/9380 + +.. py:module:: bridgedb.parse.networkstatus + :synopsis: Parsers for ``@type bridge-network-status`` descriptors_. +.. _descriptors: https://metrics.torproject.org/formats.html#descriptortypes + + +bridgedb.parse.networkstatus +============================ +:: + + networkstatus + |_ isValidRouterNickname - Determine if a nickname is according to spec + |_ parseRLine - Parse an 'r'-line from a networkstatus document + |_ parseALine - Parse an 'a'-line from a networkstatus document + _ parseSLine - Parse an 's'-line from a networkstatus document +.. +""" + +import binascii +import logging +import string +import time +import warnings + +from twisted.python import deprecate +from twisted.python.log import showwarning +from twisted.python.versions import Version + +from bridgedb.parse import addr +from bridgedb.parse import parseUnpaddedBase64 +from bridgedb.parse import InvalidBase64 +from bridgedb.parse.nickname import InvalidRouterNickname +from bridgedb.parse.nickname import isValidRouterNickname + + +@deprecate.deprecated(Version('bridgedb', 0, 2, 5)) +class NetworkstatusParsingError(Exception): + """Unable to parse networkstatus document line.""" + +@deprecate.deprecated(Version('bridgedb', 0, 2, 5)) +class InvalidNetworkstatusRouterIdentity(ValueError): + """The ID field of a networkstatus document 'r'-line is invalid.""" + + +@deprecate.deprecated(Version('bridgedb', 0, 2, 5)) +def parseRLine(line): + """Parse an 'r'-line from a networkstatus document. + + From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512: + | "r" SP nickname SP identity SP digest SP publication SP IP SP ORPort + | SP DirPort NL + | + | [At start, exactly once.] + | + | "Nickname" is the OR's nickname. "Identity" is a hash of its + | identity key, encoded in base64, with trailing equals sign(s) + | removed. "Digest" is a hash of its most recent descriptor as + | signed (that is, not including the signature), encoded in base64. + | "Publication" is the + | publication time of its most recent descriptor, in the form + | YYYY-MM-DD HH:MM:SS, in UTC. "IP" is its current IP address; + | ORPort is its current OR port, "DirPort" is its current directory + | port, or "0" for "none". + + :param string line: An 'r'-line from an bridge-network-status descriptor. + :returns: + A 7-tuple of:: + (nickname, identityDigest, descriptorDigest, timestamp, + orAddress, orPort, dirport) + where each value is set according to the data parsed from the + **line**, or ``None`` if nothing suitable could be parsed. + """ + (nickname, ID, descDigest, timestamp, + ORaddr, ORport, dirport) = (None for x in xrange(7)) + + try: + if not line.startswith('r '): + raise NetworkstatusParsingError( + "Networkstatus parser received non 'r'-line: %r" % line) + + line = line[2:] # Chop off the 'r ' + fields = line.split() + + if len(fields) != 8: + raise NetworkstatusParsingError( + "Wrong number of fields in networkstatus 'r'-line: %r" % line) + + nickname, ID = fields[:2] + + try: + ID = parseUnpaddedBase64(ID) + except InvalidBase64 as error: + raise InvalidNetworkstatusRouterIdentity(error) + + # Check the nickname validity after parsing the ID, otherwise, if the + # nickname is invalid, we end up with the nickname being ``None`` and + # the ID being unparsed, unpadded (meaning it is technically invalid) + # base64. + isValidRouterNickname(nickname) + + except NetworkstatusParsingError as error: + logging.error(error) + nickname, ID = None, None + except InvalidRouterNickname as error: + logging.error(error) + # Assume that we mostly care about obtaining the OR's ID, then it + # should be okay to set the nickname to ``None``, if it was invalid. + nickname = None + except InvalidNetworkstatusRouterIdentity as error: + logging.error(error) + ID = None + else: + try: + descDigest = parseUnpaddedBase64(fields[2]) + timestamp = time.mktime(time.strptime(" ".join(fields[3:5]), + "%Y-%m-%d %H:%M:%S")) + ORaddr = fields[5] + ORport = int(fields[6]) + dirport = fields[7] + except InvalidBase64 as error: + logging.error(error) + descDigest = None + except (AttributeError, ValueError, IndexError) as error: + logging.error(error) + timestamp = None + finally: + return (nickname, ID, descDigest, timestamp, ORaddr, ORport, dirport) + +@deprecate.deprecated(Version('bridgedb', 0, 2, 5)) +def parseALine(line, fingerprint=None): + """Parse an 'a'-line of a bridge networkstatus document. + + From torspec.git/dir-spec.txt, commit 36761c7d553d L1499-1512: + | + | "a" SP address ":" port NL + | + | [Any number.] + | + | Present only if the OR has at least one IPv6 address. + | + | Address and portlist are as for "or-address" as specified in + | 2.1. + | + | (Only included when the vote or consensus is generated with + | consensus-method 14 or later.) + + :param string line: An 'a'-line from an bridge-network-status descriptor. + :type fingerprint: string or None + :param fingerprint: A string which identifies which OR the descriptor + we're parsing came from (since the 'a'-line doesn't tell us, this can + help make the log messages clearer). + :raises: :exc:`NetworkstatusParsingError` + :rtype: tuple + :returns: A 2-tuple of a string respresenting the IP address and a + :class:`bridgedb.parse.addr.PortList`. + """ + ip = None + portlist = None + + if line.startswith('a '): + line = line[2:] # Chop off the 'a ' + else: + logging.warn("Networkstatus parser received non 'a'-line for %r:"\ + " %r" % (fingerprint or 'Unknown', line)) + + try: + ip, portlist = line.rsplit(':', 1) + except ValueError as error: + logging.error("Bad separator in networkstatus 'a'-line: %r" % line) + return (None, None) + + if ip.startswith('[') and ip.endswith(']'): + ip = ip.strip('[]') + + try: + if not addr.isIPAddress(ip): + raise NetworkstatusParsingError( + "Got invalid IP Address in networkstatus 'a'-line for %r: %r" + % (fingerprint or 'Unknown', line)) + + if addr.isIPv4(ip): + warnings.warn(FutureWarning( + "Got IPv4 address in networkstatus 'a'-line! "\ + "Networkstatus document format may have changed!")) + except NetworkstatusParsingError as error: + logging.error(error) + ip, portlist = None, None + + try: + portlist = addr.PortList(portlist) + if not portlist: + raise NetworkstatusParsingError( + "Got invalid portlist in 'a'-line for %r!\n Line: %r" + % (fingerprint or 'Unknown', line)) + except (addr.InvalidPort, NetworkstatusParsingError) as error: + logging.error(error) + portlist = None + else: + logging.debug("Parsed networkstatus ORAddress line for %r:"\ + "\n Address: %s \tPorts: %s" + % (fingerprint or 'Unknown', ip, portlist)) + finally: + return (ip, portlist) + +@deprecate.deprecated(Version('bridgedb', 0, 2, 5)) +def parseSLine(line): + """Parse an 's'-line from a bridge networkstatus document. + + The 's'-line contains all flags assigned to a bridge. The flags which may + be assigned to a bridge are as follows: + + From torspec.git/dir-spec.txt, commit 36761c7d553d L1526-1554: + | + | "s" SP Flags NL + | + | [Exactly once.] + | + | A series of space-separated status flags, in lexical order (as ASCII + | byte strings). Currently documented flags are: + | + | "BadDirectory" if the router is believed to be useless as a + | directory cache (because its directory port isn't working, + | its bandwidth is always throttled, or for some similar + | reason). + | "Fast" if the router is suitable for high-bandwidth circuits. + | "Guard" if the router is suitable for use as an entry guard. + | "HSDir" if the router is considered a v2 hidden service directory. + | "Named" if the router's identity-nickname mapping is canonical, + | and this authority binds names. + | "Stable" if the router is suitable for long-lived circuits. + | "Running" if the router is currently usable. + | "Valid" if the router has been 'validated'. + | "V2Dir" if the router implements the v2 directory protocol. + + :param string line: An 's'-line from an bridge-network-status descriptor. + :rtype: tuple + :returns: A 2-tuple of booleans, the first is True if the bridge has the + "Running" flag, and the second is True if it has the "Stable" flag. + """ + line = line[2:] + + flags = [x.capitalize() for x in line.split()] + fast = 'Fast' in flags + running = 'Running' in flags + stable = 'Stable' in flags + guard = 'Guard' in flags + valid = 'Valid' in flags + + if (fast or running or stable or guard or valid): + logging.debug("Parsed Flags: %s%s%s%s%s" + % ('Fast ' if fast else '', + 'Running ' if running else '', + 'Stable ' if stable else '', + 'Guard ' if guard else '', + 'Valid ' if valid else '')) + + # Right now, we only care about 'Running' and 'Stable' + return running, stable diff --git a/lib/bridgedb/test/legacy_Tests.py b/lib/bridgedb/test/legacy_Tests.py index 7be5270..d416d22 100644 --- a/lib/bridgedb/test/legacy_Tests.py +++ b/lib/bridgedb/test/legacy_Tests.py @@ -35,7 +35,7 @@ from bridgedb.Filters import filterBridgesByNotBlockedIn from bridgedb.Stability import BridgeHistory
from bridgedb.parse import addr -from bridgedb.parse import networkstatus +from bridgedb.test import deprecated_networkstatus as networkstatus
from math import log
diff --git a/lib/bridgedb/test/test_parse_networkstatus.py b/lib/bridgedb/test/test_parse_networkstatus.py deleted file mode 100644 index 6a89c25..0000000 --- a/lib/bridgedb/test/test_parse_networkstatus.py +++ /dev/null @@ -1,414 +0,0 @@ -# -*- coding: utf-8 -*- -# -# This file is part of BridgeDB, a Tor bridge distribution system. -# -# :authors: Isis Lovecruft 0xA3ADB67A2CDB8B35 isis@torproject.org -# :copyright: (c) 2013-2014, Isis Lovecruft -# (c) 2007-2014, The Tor Project, Inc. -# :license: 3-Clause BSD, see LICENSE for licensing information - -"""Unittests for the :mod:`bridgedb.parse.networkstatus` module. - -These tests are meant to ensure that the :mod:`bridgedb.parse.networkstatus` -module is functioning correctly. -""" - -from __future__ import print_function -from __future__ import unicode_literals - -import binascii - -from twisted.python import log -from twisted.trial import unittest -from bridgedb.parse import networkstatus - -import sure -from sure import this, these, those, the, it - - -logFormat = "%(created)d [%(levelname)s] %(module)s.%(funcName)s(): " -logFormat += "%(message)s" -networkstatus.logging.basicConfig( - filename='test_parse_networkstatus.log', - level=networkstatus.logging.DEBUG, - flags='w', format=logFormat) - - -class ParseNetworkStatusRLineTests(unittest.TestCase): - """Tests for :func:`bridgedb.parse.networkstatus.parseRLine`. - - The documentation for all class variables, e.g. 'pre' or 'ident', refers - to what said value should be in a *valid* descriptor. - """ - rawIdent = 'identdigestidentdig' - rawDesc = 'descdigestdescdiges' - - #: The prefix for the 'r'-line. Should be an 'r', unless testing that - #: lines with unknown prefixes are dropped. - pre = 'r ' - #: An OR nickname string. To be valid, it should be 1-19 alphanumeric - #: upper or lower cased characters. - nick = 'Testing' - #: A base64-encoded, SHA-1 digest of the DER-formatted, ASN.1-encoded, - #: public portion of an OR identity key, with any trailing base64 padding - #: (any '=' characters) removed. - ident = binascii.b2a_base64(rawIdent).strip().rstrip('==') - #: A base64-encoded, SHA-1 digest of the OR - #: `@type-[bridge-]server-descriptor` document (the whole thing, up until - #: the 'router signature' line, but not including the signature thereafter), - #: with any trailing base64 padding (any '=' characters) removed. - desc = binascii.b2a_base64(rawDesc).strip().rstrip('==') - #: An ISO-8661 formatted timestamp, with a space separator (rather than a - #: 'T' character). - ts = '2013-10-31 15:15:15' - #: An IPv4 address. - ip = '221.251.0.42' - #: An ORPort number. - port = '9001' - #: A DirPort number. - dirp = '0' - - def makeRLine(self, *args, **kwargs): - """Concatenate parameters into an 'r'-line and store the result as - ``self.line``. - - :keywords: The keyword arguments may be any of the class variables, - i.e. 'nick' or 'ident', and the variables should be similar - to the defaults in the class variables. If not given as - parameters, the class variables will be used. - """ - line = [] - for kw in ('pre', 'nick', 'ident', 'desc', 'ts', 'ip', 'port', 'dirp'): - if kw in kwargs.keys(): - if kwargs[kw]: - line.append(kwargs[kw]) - elif kwargs[kw] is False: - pass - else: - line.append(getattr(self, kw, '')) - - self.line = ' '.join([l for l in line]).strip() - log.msg("\n Testing networkstatusline:\n %r..." % self.line) - self.assertTrue(self.line != '') - - def tearDown(self): - self.line = '' - - def assertAllFieldsAreNone(self, fields): - """Assert that every field in the iterable ``fields`` is None.""" - for field in fields: - self.assertTrue(field is None) - - def test_missingPrefix(self): - """Test a networkstatus 'r'-line that is missing the 'r ' prefix.""" - self.makeRLine(pre=False) - fields = networkstatus.parseRLine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_wrongNumberOfFields(self): - """Test a line missing digest, ORPort, and DirPort fields.""" - self.makeRLine(desc=False, port=False, dirp=False) - fields = networkstatus.parseRLine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_wrongFieldOrder(self): - """Test a line with the identity and descriptor digests switched.""" - self.makeRLine(desc=self.ident, ident=self.desc) - fields = networkstatus.parseRLine(self.line) - nick, others = fields[0], fields[1:] - - this(nick).should.be.ok - this(nick).should.be.a(basestring) - this(nick).should.equal(self.nick) - - the(others).should.be.a(tuple) - the(others).should.have.length_of(6) - for other in others: - the(other).should.be(None) - - def test_invalidNicknameNonAlphanumeric(self): - """Test a line with a non-alphanumeric router nickname.""" - self.makeRLine(nick='abcdef/*comment*/') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc = fields[:3] - this(nick).should.be(None) - the(ident).should.be.a(basestring) - the(desc).should.be(None) - - def test_invalidNicknameTooLong(self): - """Test a line with a router nickname which is way too long.""" - self.makeRLine(nick='ThisIsAReallyReallyLongRouterNickname') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc = fields[:3] - this(nick).should.be(None) - the(ident).should.be.a(basestring) - the(desc).should.be(None) - - def test_invalidIdentBase64(self): - """Test line with '%$>@,<' for an identity digest.""" - self.makeRLine(ident='%$>#@,<') - (nick, ident, desc, ts, - ip, port, dirp) = networkstatus.parseRLine(self.line) - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.equal(self.nick) - the(ident).should.be(None) - the(desc).should.be(None) - - def test_invalidIdentSingleQuoteChar(self): - """Test a line with a single quote character for the identity digest.""" - self.makeRLine(ident=chr(0x27)) - fields = networkstatus.parseRLine(self.line) - nick, ident, desc = fields[:3] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(None) - the(desc).should.be.equal(None) - - def test_invalidIdent_withBase64padding(self): - """Test a line with invalid base64 (no padding) identity digest.""" - self.makeRLine(ident=self.ident + '==') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc = fields[:3] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(None) - the(desc).should.be.equal(None) - - def test_invalidDescriptorDigest(self): - """Test an 'r'-line with invalid base64 descriptor digest.""" - self.makeRLine(desc='敃噸襶') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip = fields[:5] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.be.equal(self.nick) - - the(ident).should.be.a(basestring) - the(ident).should.be.equal(self.rawIdent) - - the(desc).should.be.equal(None) - the(ts).should.be.equal(None) - the(ip).should.be.equal(None) - - def test_invalidDescriptorDigest_invalidBase64(self): - """Test line with '%$>@,<' for an identity digest.""" - self.makeRLine(desc='%$>#@,<') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip = fields[:5] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.equal(self.nick) - the(ident).should.be(None) - the(desc).should.be(None) - - def test_invalidDescriptorDigest_withBase64padding(self): - """Test a line with invalid base64 (no padding) descriptor digest.""" - self.makeRLine(desc=self.desc + '==') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip = fields[:5] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.be.equal(self.nick) - - the(ident).should.be.a(basestring) - the(ident).should.be.equal(self.rawIdent) - - the(desc).should.be.equal(None) - the(ts).should.be.equal(None) - the(ip).should.be.equal(None) - - def test_invalidDescriptorDigest_singleQuoteChar(self): - """Test with a single quote character for the descriptor digest.""" - self.makeRLine(desc=chr(0x27)) - fields = networkstatus.parseRLine(self.line) - nick, ident, desc = fields[:3] - - the(nick).should.be.ok - the(nick).should.be.a(basestring) - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(self.rawIdent) - the(desc).should.be.equal(None) - - def test_missingAfterDesc(self): - """Test a line that has a valid descriptor digest, and is missing - everything after the descriptor digest, i.e. the timestamp, IP address, - and DirPort. - """ - self.makeRLine(nick='missingAfterDesc', ts=False, ip=False, dirp=False) - fields = networkstatus.parseRLine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_missingAfterIdent(self): - """Test a line that and is missing the descriptor digest and - everything after it, i.e. the timestamp, IP address, and DirPort. - """ - self.makeRLine(nick='noDesc', desc=False, ts=False, - ip=False, dirp=False) - fields = networkstatus.parseRLine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_invalidTimestamp(self): - """Test line with two large integers for the timestamp.""" - self.makeRLine(ts='123456789 987654321') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip, port = fields[:6] - - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(self.rawIdent) - - # descDigest is set to `None` if there is an error while parsing: - the(desc).should.be(None) - the(ts).should.be(None) - the(ip).should.be(None) - - def test_invalidTimestampMissingDate(self): - """Test a line where the timestamp is missing the date portion.""" - self.makeRLine(ts='15:15:15') - fields = networkstatus.parseRLine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_invalidIPAddress(self): - """Test a line with an invalid IP address.""" - self.makeRLine(ip='0.0.0.0') - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip, port = fields[:6] - - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(self.rawIdent) - - # descDigest is set to `None` if there is an error while parsing: - the(desc).should.be(None) - the(ts).should.be(None) - the(ip).should.be(None) - - def test_valid(self): - """Test a valid 'r'-line.""" - self.makeRLine() - fields = networkstatus.parseRLine(self.line) - nick, ident, desc, ts, ip, port = fields[:6] - the(nick).should.be.equal(self.nick) - the(ident).should.be.equal(self.rawIdent) - the(desc).should.be.equal(self.rawDesc) - the(ts).should.be.ok - the(ip).should.be.ok - - -class ParseNetworkStatusALineTests(unittest.TestCase): - """Tests for :func:`bridgedb.parse.networkstatus.parseALine`. - - The documentation for all class variables, e.g. 'pre' or 'oraddr', refers - to what said value should be in a *valid* descriptor. - """ - #: The prefix for the 'a'-line. Should be an 'a', unless testing that - #: lines with unknown prefixes are dropped. - pre = 'a ' - #: An ORAddress. As of tor-0.2.5.1-alpha, there is only one and it is an - #: IPv6 address. - oraddr = '[b8d:48ae:5185:dad:5c2a:4e75:8394:f5f8]' - - def tearDown(self): - self.line = '' - - def assertAllFieldsAreNone(self, fields): - """Assert that every field in the iterable ``fields`` is None.""" - for field in fields: - self.assertTrue(field is None) - - def test_missingPrefix(self): - """Changed to allow a missing 'a' prefix in branch - ``hotfix/9462B-netstatus-returns-None``. - """ - self.line = '%s:1234' % self.oraddr - ip, port = networkstatus.parseALine(self.line) - this(ip).should.be.a(basestring) - this(port).should.be(None) - - def test_IPv4(self): - self.line = 'a 48.32.199.45:9001' - ip, port = networkstatus.parseALine(self.line) - ip, port = self.assertWarns( - FutureWarning, - "Got IPv4 address in networkstatus 'a'-line! "\ - "Networkstatus document format may have changed!", - networkstatus.__file__, - networkstatus.parseALine, - self.line) - this(ip).should.be.a(basestring) - this(port).should.be.ok - this(port).should.be.a(networkstatus.addr.PortList) - - def test_IPv4BadPortSeparator(self): - self.line = 'a 1.1.1.1 9001' - fields = networkstatus.parseALine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_IPv6BadPortlist(self): - self.line = 'a 23.23.23.23:1111,2222,badportlist' - ip, port = networkstatus.parseALine(self.line) - this(ip).should.be.a(basestring) - this(port).should.be(None) - - def test_IPv4MissingPort(self): - self.line = 'a 1.1.1.1' - fields = networkstatus.parseALine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_IPv4InvalidAddress(self): - self.line = 'a 127.0.0.1:5555' - fields = networkstatus.parseALine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_IPv6BadPortSeparator(self): - self.line = 'a %s missingcolon' % self.oraddr - fields = networkstatus.parseALine(self.line) - self.assertAllFieldsAreNone(fields) - - def test_IPv6BadPortlist(self): - self.line = 'a %s:1111,2222,badportlist' % self.oraddr - ip, port = networkstatus.parseALine(self.line) - this(ip).should.be.a(basestring) - this(port).should.be(None) - - def test_IPv6(self): - self.line = 'a %s:6004' % self.oraddr - ip, port = networkstatus.parseALine(self.line) - this(ip).should.be.a(basestring) - this(port).should.be.ok - this(port).should.be.a(networkstatus.addr.PortList) - - -class ParseNetworkStatusSLineTests(unittest.TestCase): - """Tests for :func:`bridgedb.parse.networkstatus.parseSLine`.""" - - def tearDown(self): - """Automatically called after each test_* method to run cleanups.""" - self.line = '' - - def test_missingPrefix(self): - self.line = 'Stable' - running, stable = networkstatus.parseSLine(self.line) - self.assertFalse(running) - self.assertFalse(stable) - - def test_makeBelieveFlag(self): - """Test that 's'-parser should ignore a 'MakeBelieve' flag.""" - self.line = 's Stable Running MakeBelieve BadExit' - running, stable = networkstatus.parseSLine(self.line) - self.assertTrue(running) - self.assertTrue(stable) - - def test_noFlags(self): - """Test that an 's'-line with no flags returns False for everything.""" - self.line = '' - running, stable = networkstatus.parseSLine(self.line) - self.assertFalse(running) - self.assertFalse(stable)
tor-commits@lists.torproject.org