commit 2a3c688715d4ac4dd5ad1dae46be14ed65623d5b Author: Isis Lovecruft isis@torproject.org Date: Wed Dec 11 13:23:15 2013 +0000
Move base64 re-padding logic into separate function.
This logic is not specific to parsing networkstatus descriptors, so for now I've placed it in parse.parseUnpaddedBase64() ― though it could live somewhere else later. --- lib/bridgedb/parse/__init__.py | 38 +++++++++++++++++++++++++++++++++++ lib/bridgedb/parse/networkstatus.py | 28 ++++++++++---------------- 2 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/lib/bridgedb/parse/__init__.py b/lib/bridgedb/parse/__init__.py index f4b75d1..0618dae 100644 --- a/lib/bridgedb/parse/__init__.py +++ b/lib/bridgedb/parse/__init__.py @@ -26,6 +26,16 @@ __ :mod:`bridgedb.parse.versions` """
+from __future__ import absolute_import +from __future__ import print_function +from __future__ import unicode_literals + +import binascii + + +class InvalidBase64(ValueError): + """Cannot decode base64 value.""" +
def padBase64(b64string): """Re-add any stripped equals sign character padding to a b64 string. @@ -50,3 +60,31 @@ def padBase64(b64string): b64string += '=' * addchars
return b64string + +def parseUnpaddedBase64(field): + """Parse an unpadded, base64-encoded field. + + The **field** will be re-padded, if need be, and then base64 decoded. + + :param str field: Should be some base64-encoded thing, with any trailing + '=' characters removed. + :raises: :exc:`InvalidBase64`, if there is an error in either unpadding or + decoding **field**. + :rtype: str + :returns: The base64-decoded **field**. + """ + if field.endswith('='): + raise InvalidBase64("Unpadded, base64-encoded networkstatus field "\ + "must not end with '=': %r" % field) + + try: + paddedField = padBase64(field) # Add the trailing equals sign back in + except ValueError as error: + raise InvalidBase64(error) + + debasedField = binascii.a2b_base64(paddedField) + if not debasedField: + raise InvalidBase64("Base64-encoded networkstatus field %r is invalid!" + % field) + + return debasedField diff --git a/lib/bridgedb/parse/networkstatus.py b/lib/bridgedb/parse/networkstatus.py index 7fd9e18..09c9a65 100644 --- a/lib/bridgedb/parse/networkstatus.py +++ b/lib/bridgedb/parse/networkstatus.py @@ -32,7 +32,8 @@ import warnings from twisted.python.log import showwarning
from bridgedb.parse import addr -from bridgedb.parse import padBase64 +from bridgedb.parse import parseUnpaddedBase64 +from bridgedb.parse import InvalidBase64
class NetworkstatusParsingError(Exception): @@ -103,19 +104,10 @@ def parseRLine(line): nickname, ID = fields[:2] isValidRouterNickname(nickname)
- if ID.endswith('='): - raise InvalidNetworkstatusRouterIdentity( - "Skipping networkstatus parsing for router with nickname "\ - "'%s':\n Unpadded, base64-encoded networkstatus router identity "\ - "string ends with '=': %r" % (nickname, ID)) - paddedID = padBase64(ID) # Add the trailing equals sign back in - debasedID = binascii.a2b_base64(paddedID) - if not debasedID: - raise InvalidNetworkstatusRouterIdentity( - "Skipping networkstatus parsing for router with nickname "\ - "'%s':\n Base64-encoding for networkstatus router identity "\ - "string is invalid!\n Line: %r" % (nickname, line)) - ID = debasedID + try: + ID = parseUnpaddedBase64(ID) + except InvalidBase64 as error: + raise InvalidNetworkstatusRouterIdentity(error)
except NetworkstatusParsingError as error: logging.error(error) @@ -128,16 +120,18 @@ def parseRLine(line): ID = None else: try: - paddedDigest = padBase64(fields[2]) - descDigest = binascii.b2a_base64(paddedDigest) + descDigest = parseUnpaddedBase64(fields[2]) timestamp = time.mktime(time.strptime(" ".join(fields[3:5]), "%Y-%m-%d %H:%M:%S")) ORaddr = fields[5] ORport = fields[6] dirport = fields[7] - except (AttributeError, ValueError, IndexError) as error: + 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)