Beispiel #1
0
    def test_valid_string_unescaping(self):
        unescapeable = {
            '\\\\': '\\',         # \\     -> \
            r'\"': r'"',          # \"     -> "
            r'\\\"': r'\"',       # \\\"   -> \"
            r'\\\\\"': r'\\"',    # \\\\\" -> \\"
            '\\"\\\\': '"\\',     # \"\\   -> "\
            "\\'": "'",           # \'     -> '
            "\\\\\\'": "\\'",     # \\\'   -> \
            r'some\"text': 'some"text',
            'some\\word': 'someword',
            '\\delete\\ al\\l un\\used \\backslashes': 'delete all unused backslashes',
            '\\n\\r\\t': '\n\r\t',
            '\\x00 \\x0123': 'x00 x0123',
            '\\\\x00 \\\\x00': '\\x00 \\x00',
            '\\\\\\x00  \\\\\\x00': '\\x00  \\x00'
        }

        for escaped, correct_unescaped in unescapeable.items():
            escaped = '"{}"'.format(escaped)
            unescaped = unescape_quoted_string(escaped)
            msg = "Wrong unescape: {escaped} -> {unescaped} instead of {correct}"
            msg = msg.format(unescaped=unescaped, escaped=escaped,
                             correct=correct_unescaped)
            self.assertEqual(unescaped, correct_unescaped, msg=msg)
Beispiel #2
0
    def test_valid_string_unescaping(self):
        unescapeable = {
            '\\\\': '\\',  # \\     -> \
            r'\"': r'"',  # \"     -> "
            r'\\\"': r'\"',  # \\\"   -> \"
            r'\\\\\"': r'\\"',  # \\\\\" -> \\"
            '\\"\\\\': '"\\',  # \"\\   -> "\
            "\\'": "'",  # \'     -> '
            "\\\\\\'": "\\'",  # \\\'   -> \
            r'some\"text': 'some"text',
            'some\\word': 'someword',
            '\\delete\\ al\\l un\\used \\backslashes':
            'delete all unused backslashes',
            '\\n\\r\\t': '\n\r\t',
            '\\x00 \\x0123': 'x00 x0123',
            '\\\\x00 \\\\x00': '\\x00 \\x00',
            '\\\\\\x00  \\\\\\x00': '\\x00  \\x00'
        }

        for escaped, correct_unescaped in unescapeable.items():
            escaped = '"{}"'.format(escaped)
            unescaped = unescape_quoted_string(escaped)
            msg = "Wrong unescape: {escaped} -> {unescaped} instead of {correct}"
            msg = msg.format(unescaped=unescaped,
                             escaped=escaped,
                             correct=correct_unescaped)
            self.assertEqual(unescaped, correct_unescaped, msg=msg)
Beispiel #3
0
    def test_string_unescape_octals(self):
        '''
        Octal numbers can be escaped by a backslash:
        \0 is interpreted as a byte with the value 0
        '''
        for number in range(0x7f):
            escaped = '\\%o' % number
            result = unescape_quoted_string('"{}"'.format(escaped))
            expected = chr(number)

            msg = "Number not decoded correctly: {escaped} -> {result} instead of {expected}"
            msg = msg.format(escaped=escaped, result=repr(result), expected=repr(expected))
            self.assertEqual(result, expected, msg=msg)
Beispiel #4
0
    def test_string_unescape_octals(self):
        '''
        Octal numbers can be escaped by a backslash:
        \0 is interpreted as a byte with the value 0
        '''
        for number in range(0x7f):
            escaped = '\\%o' % number
            result = unescape_quoted_string('"{}"'.format(escaped))
            expected = chr(number)

            msg = "Number not decoded correctly: {escaped} -> {result} instead of {expected}"
            msg = msg.format(escaped=escaped, result=repr(result), expected=repr(expected))
            self.assertEqual(result, expected, msg=msg)
Beispiel #5
0
    def test_string_unescape_octals(self):
        '''
        Octal numbers can be escaped by a backslash:
        \0 is interpreted as a byte with the value 0
        '''
        for number in range(1000):
            escaped = '\\{}'.format(number)
            result = unescape_quoted_string('"{}"'.format(escaped))

            expected = escaped.decode('string-escape')
            if expected[0] == '\\' and len(expected) > 1:
                expected = expected[1:]

            msg = "Number not decoded correctly: {escaped} -> {result} instead of {expected}"
            msg = msg.format(escaped=escaped, result=repr(result), expected=repr(expected))
            self.assertEquals(result, expected, msg=msg)
Beispiel #6
0
    def test_string_unescape_octals(self):
        '''
        Octal numbers can be escaped by a backslash:
        \0 is interpreted as a byte with the value 0
        '''
        for number in range(1000):
            escaped = '\\{}'.format(number)
            result = unescape_quoted_string('"{}"'.format(escaped))

            expected = escaped.decode('string-escape')
            if expected[0] == '\\' and len(expected) > 1:
                expected = expected[1:]

            msg = "Number not decoded correctly: {escaped} -> {result} instead of {expected}"
            msg = msg.format(escaped=escaped,
                             result=repr(result),
                             expected=repr(expected))
            self.assertEquals(result, expected, msg=msg)
    def _do_authenticate(self, protoinfo):
        """
        Callback on PROTOCOLINFO to actually authenticate once we know
        what's supported.
        """
        methods = None
        cookie_auth = False
        for line in protoinfo.split('\n'):
            if line[:5] == 'AUTH ':
                kw = parse_keywords(line[5:].replace(' ', '\n'))
                methods = kw['METHODS'].split(',')
        if not methods:
            raise RuntimeError(
                "Didn't find AUTH line in PROTOCOLINFO response."
            )

        if 'SAFECOOKIE' in methods or 'COOKIE' in methods:
            cookiefile_match = re.search(r'COOKIEFILE=("(?:[^"\\]|\\.)*")',
                                         protoinfo)
            if cookiefile_match:
                cookiefile = cookiefile_match.group(1)
                cookiefile = unescape_quoted_string(cookiefile)
                try:
                    self._read_cookie(cookiefile)
                except IOError as why:
                    txtorlog.msg("Reading COOKIEFILE failed: " + str(why))
                    cookie_auth = False
                else:
                    cookie_auth = True
            else:
                txtorlog.msg("Didn't get COOKIEFILE")

        if cookie_auth:
            if 'SAFECOOKIE' in methods:
                txtorlog.msg("Using SAFECOOKIE authentication", cookiefile,
                             len(self._cookie_data), "bytes")
                self.client_nonce = os.urandom(32)

                cmd = 'AUTHCHALLENGE SAFECOOKIE ' + \
                      base64.b16encode(self.client_nonce)
                d = self.queue_command(cmd)
                d.addCallback(self._safecookie_authchallenge)
                d.addCallback(self._bootstrap)
                d.addErrback(self._auth_failed)
                return

            elif 'COOKIE' in methods:
                txtorlog.msg("Using COOKIE authentication",
                             cookiefile, len(self._cookie_data), "bytes")
                d = self.authenticate(self._cookie_data)
                d.addCallback(self._bootstrap)
                d.addErrback(self._auth_failed)
                return

        if self.password_function and 'HASHEDPASSWORD' in methods:
            d = defer.maybeDeferred(self.password_function)
            d.addCallback(self._do_password_authentication)
            d.addErrback(self._auth_failed)
            return

        if 'NULL' in methods:
            d = self.queue_command('AUTHENTICATE')
            d.addCallback(self._bootstrap)
            d.addErrback(self._auth_failed)
            return

        raise RuntimeError(
            "The Tor I connected to doesn't support SAFECOOKIE nor COOKIE"
            " authentication and I have no password_function specified."
        )
Beispiel #8
0
    def _do_authenticate(self, protoinfo):
        """
        Callback on PROTOCOLINFO to actually authenticate once we know
        what's supported.
        """
        methods = None
        cookie_auth = False
        for line in protoinfo.split('\n'):
            if line[:5] == 'AUTH ':
                kw = parse_keywords(line[5:].replace(' ', '\n'))
                methods = kw['METHODS'].split(',')
        if not methods:
            raise RuntimeError(
                "Didn't find AUTH line in PROTOCOLINFO response.")

        if 'SAFECOOKIE' in methods or 'COOKIE' in methods:
            cookiefile_match = re.search(r'COOKIEFILE=("(?:[^"\\]|\\.)*")',
                                         protoinfo)
            if cookiefile_match:
                cookiefile = cookiefile_match.group(1)
                cookiefile = unescape_quoted_string(cookiefile)
                try:
                    self._read_cookie(cookiefile)
                except IOError as why:
                    txtorlog.msg("Reading COOKIEFILE failed: " + str(why))
                    cookie_auth = False
                else:
                    cookie_auth = True
            else:
                txtorlog.msg("Didn't get COOKIEFILE")

        if cookie_auth:
            if 'SAFECOOKIE' in methods:
                txtorlog.msg("Using SAFECOOKIE authentication", cookiefile,
                             len(self._cookie_data), "bytes")
                self.client_nonce = os.urandom(32)

                cmd = 'AUTHCHALLENGE SAFECOOKIE ' + \
                      base64.b16encode(self.client_nonce)
                d = self.queue_command(cmd)
                d.addCallback(self._safecookie_authchallenge)
                d.addCallback(self._bootstrap)
                d.addErrback(self._auth_failed)
                return

            elif 'COOKIE' in methods:
                txtorlog.msg("Using COOKIE authentication", cookiefile,
                             len(self._cookie_data), "bytes")
                d = self.authenticate(self._cookie_data)
                d.addCallback(self._bootstrap)
                d.addErrback(self._auth_failed)
                return

        if self.password_function and 'HASHEDPASSWORD' in methods:
            d = defer.maybeDeferred(self.password_function)
            d.addCallback(self._do_password_authentication)
            d.addErrback(self._auth_failed)
            return

        raise RuntimeError(
            "The Tor I connected to doesn't support SAFECOOKIE nor COOKIE"
            " authentication and I have no password_function specified.")
Beispiel #9
0
    def _do_authenticate(self, protoinfo):
        """
        Callback on PROTOCOLINFO to actually authenticate once we know
        what's supported.
        """
        methods = None
        cookie_auth = False
        for line in protoinfo.split('\n'):
            if line[:5] == 'AUTH ':
                kw = parse_keywords(line[5:].replace(' ', '\n'))
                methods = kw['METHODS'].split(',')
        if not methods:
            raise RuntimeError(
                "Didn't find AUTH line in PROTOCOLINFO response.")

        if 'SAFECOOKIE' in methods or 'COOKIE' in methods:
            cookiefile_match = re.search(r'COOKIEFILE=("(?:[^"\\]|\\.)*")',
                                         protoinfo)
            if cookiefile_match:
                cookiefile = cookiefile_match.group(1)
                cookiefile = unescape_quoted_string(cookiefile)
                try:
                    self._read_cookie(cookiefile)
                    cookie_auth = True
                except IOError as why:
                    txtorlog.msg("Reading COOKIEFILE failed: " + str(why))
                    if self.password_function and 'HASHEDPASSWORD' in methods:
                        txtorlog.msg("Falling back to password")
                    else:
                        raise RuntimeError(
                            "Failed to read COOKIEFILE '{fname}': {msg}\n".
                            format(
                                fname=cookiefile,
                                msg=str(why),
                            )
                            # "On Debian, join the debian-tor group"
                        )
            else:
                txtorlog.msg("Didn't get COOKIEFILE")
                raise RuntimeError(
                    "Got 'COOKIE' or 'SAFECOOKIE' method, but no 'COOKIEFILE'")

        if cookie_auth:
            if 'SAFECOOKIE' in methods:
                txtorlog.msg("Using SAFECOOKIE authentication", cookiefile,
                             len(self._cookie_data), "bytes")
                self.client_nonce = os.urandom(32)

                cmd = b'AUTHCHALLENGE SAFECOOKIE ' + \
                      hexlify(self.client_nonce)
                d = self.queue_command(cmd)
                d.addCallback(self._safecookie_authchallenge)
                d.addCallback(self._bootstrap)
                return d

            elif 'COOKIE' in methods:
                txtorlog.msg("Using COOKIE authentication", cookiefile,
                             len(self._cookie_data), "bytes")
                d = self.authenticate(self._cookie_data)
                d.addCallback(self._bootstrap)
                return d

        if self.password_function and 'HASHEDPASSWORD' in methods:
            d = defer.maybeDeferred(self.password_function)
            d.addCallback(maybe_coroutine)
            d.addCallback(self._do_password_authentication)
            return d

        if 'NULL' in methods:
            d = self.queue_command('AUTHENTICATE')
            d.addCallback(self._bootstrap)
            return d

        return defer.fail(
            RuntimeError(
                "The Tor I connected to doesn't support SAFECOOKIE nor COOKIE"
                " authentication (or we can't read the cookie files) and I have"
                " no password_function specified."))