Beispiel #1
0
  def test_get_info_address_caching(self, msg_mock):
    msg_mock.return_value = ControlMessage.from_str('551 Address unknown\r\n')

    self.assertEqual(None, self.controller._last_address_exc)
    self.assertRaisesWith(stem.OperationFailed, 'Address unknown', self.controller.get_info, 'address')
    self.assertEqual('Address unknown', str(self.controller._last_address_exc))
    self.assertEqual(1, msg_mock.call_count)

    # now that we have a cached failure we should provide that back

    self.assertRaisesWith(stem.OperationFailed, 'Address unknown', self.controller.get_info, 'address')
    self.assertEqual(1, msg_mock.call_count)

    # invalidates the cache, transitioning from no address to having one

    msg_mock.return_value = ControlMessage.from_str('250-address=17.2.89.80\r\n250 OK\r\n', 'GETINFO')
    self.assertRaisesWith(stem.OperationFailed, 'Address unknown', self.controller.get_info, 'address')
    self.controller._handle_event(ControlMessage.from_str('650 STATUS_SERVER NOTICE EXTERNAL_ADDRESS ADDRESS=17.2.89.80 METHOD=DIRSERV\r\n'))
    self.assertEqual('17.2.89.80', self.controller.get_info('address'))

    # invalidates the cache, transitioning from one address to another

    msg_mock.return_value = ControlMessage.from_str('250-address=80.89.2.17\r\n250 OK\r\n', 'GETINFO')
    self.assertEqual('17.2.89.80', self.controller.get_info('address'))
    self.controller._handle_event(ControlMessage.from_str('650 STATUS_SERVER NOTICE EXTERNAL_ADDRESS ADDRESS=80.89.2.17 METHOD=DIRSERV\r\n'))
    self.assertEqual('80.89.2.17', self.controller.get_info('address'))
Beispiel #2
0
  def test_invalid_requests(self):
    """
    Parses a MAPADDRESS replies that contain an error code due to hostname syntax errors.
    """

    control_message = ControlMessage.from_str(UNRECOGNIZED_KEYS_RESPONSE, normalize = True)
    self.assertRaises(stem.InvalidRequest, stem.response.convert, 'MAPADDRESS', control_message)

    control_message = ControlMessage.from_str(PARTIAL_FAILURE_RESPONSE, 'MAPADDRESS', normalize = True)
    self.assertEqual({'23': '324'}, control_message.entries)
Beispiel #3
0
  def test_single_line_response(self):
    message = ControlMessage.from_str('552 NOTOK\r\n', 'SINGLELINE')
    self.assertEqual(False, message.is_ok())

    message = ControlMessage.from_str('250 KK\r\n', 'SINGLELINE')
    self.assertEqual(True, message.is_ok())

    message = ControlMessage.from_str('250 OK\r\n', 'SINGLELINE')
    self.assertEqual(True, message.is_ok(True))

    message = ControlMessage.from_str('250 HMM\r\n', 'SINGLELINE')
    self.assertEqual(False, message.is_ok(True))
Beispiel #4
0
  def test_invalid_response(self):
    """
    Parses a malformed MAPADDRESS reply that contains an invalid response code.
    This is a proper controller message, but malformed according to the
    MAPADDRESS's spec.
    """

    control_message = ControlMessage.from_str(INVALID_EMPTY_RESPONSE, normalize = True)
    self.assertRaises(stem.ProtocolError, stem.response.convert, 'MAPADDRESS', control_message)

    control_message = ControlMessage.from_str(INVALID_RESPONSE, normalize = True)
    self.assertRaises(stem.ProtocolError, stem.response.convert, 'MAPADDRESS', control_message)
Beispiel #5
0
    def test_single_line_response(self):
        message = ControlMessage.from_str('552 NOTOK\r\n', 'SINGLELINE')
        self.assertEqual(False, message.is_ok())

        message = ControlMessage.from_str('250 KK\r\n', 'SINGLELINE')
        self.assertEqual(True, message.is_ok())

        message = ControlMessage.from_str('250 OK\r\n', 'SINGLELINE')
        self.assertEqual(True, message.is_ok(True))

        message = ControlMessage.from_str('250 HMM\r\n', 'SINGLELINE')
        self.assertEqual(False, message.is_ok(True))
Beispiel #6
0
    def test_invalid_requests(self):
        """
    Parses a MAPADDRESS replies that contain an error code due to hostname syntax errors.
    """

        control_message = ControlMessage.from_str(UNRECOGNIZED_KEYS_RESPONSE,
                                                  normalize=True)
        self.assertRaises(stem.InvalidRequest, stem.response.convert,
                          'MAPADDRESS', control_message)

        control_message = ControlMessage.from_str(PARTIAL_FAILURE_RESPONSE,
                                                  'MAPADDRESS',
                                                  normalize=True)
        self.assertEqual({'23': '324'}, control_message.mapped)
Beispiel #7
0
  def test_single_response(self):
    """
    Parses a GETCONF reply response for a single parameter.
    """

    control_message = ControlMessage.from_str(SINGLE_RESPONSE, 'GETCONF', normalize = True)
    self.assertEqual({'DataDirectory': ['/home/neena/.tor']}, control_message.entries)
Beispiel #8
0
  def test_get_protocolinfo(self, get_protocolinfo_mock):
    """
    Exercises the get_protocolinfo() method.
    """

    # use the handy mocked protocolinfo response

    protocolinfo_msg = ControlMessage.from_str('250-PROTOCOLINFO 1\r\n250 OK\r\n', 'PROTOCOLINFO')
    get_protocolinfo_mock.return_value = protocolinfo_msg

    # compare the str representation of these object, because the class
    # does not have, nor need, a direct comparison operator

    self.assertEqual(
      str(protocolinfo_msg),
      str(self.controller.get_protocolinfo())
    )

    # raise an exception in the stem.connection.get_protocolinfo() call

    get_protocolinfo_mock.side_effect = ProtocolError

    # get a default value when the call fails

    self.assertEqual(
      'default returned',
      self.controller.get_protocolinfo(default = 'default returned')
    )

    # no default value, accept the error

    self.assertRaises(ProtocolError, self.controller.get_protocolinfo)
Beispiel #9
0
  def test_no_key_type(self):
    """
    Checks a response that's missing the private key type.
    """

    response = ControlMessage.from_str(MISSING_KEY_TYPE, normalize = True)
    self.assertRaisesRegexp(stem.ProtocolError, 'ADD_ONION PrivateKey lines should be of the form', stem.response.convert, 'ADD_ONION', response)
Beispiel #10
0
  def test_without_service_id(self):
    """
    Checks a response that lack an initial service id.
    """

    response = ControlMessage.from_str(WRONG_FIRST_KEY, normalize = True)
    self.assertRaisesRegexp(stem.ProtocolError, 'ADD_ONION response should start with', stem.response.convert, 'ADD_ONION', response)
Beispiel #11
0
    def __parse_line(self, line):
        if not self.boot_succeeded:
            if re.search("Starting\storctl\sprogram\son\shost", line) is not None:
                parts = line.strip().split()
                if len(parts) < 11:
                    return True
                self.name = parts[10]
            if re.search("Bootstrapped\s100", line) is not None:
                self.boot_succeeded = True
            elif re.search("BOOTSTRAP", line) is not None and re.search("PROGRESS=100", line) is not None:
                self.boot_succeeded = True

        if self.do_simple is False or (self.do_simple is True and re.search("650\sBW", line) is not None):
            # parse with stem
            timestamps, sep, raw_event_str = line.partition(" 650 ")
            if sep == '':
                return True

            # event.arrived_at is also available but at worse granularity
            unix_ts = float(timestamps.strip().split()[2])

            # check if we should ignore the line
            line_date = datetime.datetime.utcfromtimestamp(unix_ts).date()
            if not self.__is_date_valid(line_date):
                return True

            event = ControlMessage.from_str("{0} {1}".format(sep.strip(), raw_event_str))
            convert('EVENT', event)
            self.__handle_event(event, unix_ts)
        return True
Beispiel #12
0
    def __parse_line(self, line):
        if not self.boot_succeeded:
            if re.search("Starting\storctl\sprogram\son\shost",
                         line) is not None:
                parts = line.strip().split()
                if len(parts) < 11:
                    return True
                self.name = parts[10]
            if re.search("Bootstrapped\s100", line) is not None:
                self.boot_succeeded = True
            elif re.search("BOOTSTRAP", line) is not None and re.search(
                    "PROGRESS=100", line) is not None:
                self.boot_succeeded = True

        # parse with stem
        timestamps, sep, raw_event_str = line.partition(" 650 ")
        if sep == '':
            return True

        # event.arrived_at is also available but at worse granularity
        unix_ts = float(timestamps.strip().split()[2])

        # check if we should ignore the line
        line_date = datetime.datetime.utcfromtimestamp(unix_ts).date()
        if not self.__is_date_valid(line_date):
            return True

        event = ControlMessage.from_str("{0} {1}".format(
            sep.strip(), raw_event_str))
        convert('EVENT', event)
        self.__handle_event(event, unix_ts)

        return True
Beispiel #13
0
  def test_single_response(self):
    """
    Parses a GETCONF reply response for a single parameter.
    """

    control_message = ControlMessage.from_str(SINGLE_RESPONSE, 'GETCONF', normalize = True)
    self.assertEqual({'DataDirectory': ['/home/neena/.tor']}, control_message.entries)
Beispiel #14
0
  def test_password_auth(self):
    """
    Checks a response with password authentication.
    """

    control_message = ControlMessage.from_str(PASSWORD_AUTH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual((AuthMethod.PASSWORD, ), control_message.auth_methods)
Beispiel #15
0
def built_circ(circ_id,
               purpose,
               guard="$5416F3E8F80101A133B1970495B04FDBD1C7446B~Unnamed"):
    s = "650 CIRC " + str(
        circ_id
    ) + " BUILT " + guard + ",$1F9544C0A80F1C5D8A5117FBFFB50694469CC7F4~as44194l10501,$DBD67767640197FF96EC6A87684464FC48F611B6~nocabal,$387B065A38E4DAA16D9D41C2964ECBC4B31D30FF~redjohn1 BUILD_FLAGS=IS_INTERNAL,NEED_CAPACITY,NEED_UPTIME PURPOSE=" + purpose + " TIME_CREATED=2018-05-04T06:09:32.751920\r\n"
    return ControlMessage.from_str(s, "EVENT")
Beispiel #16
0
  def test_setevents(self):
    controller = Mock()
    controller.msg.return_value = ControlMessage.from_str('250 OK\r\n')

    interpreter = ControlInterpreter(controller)

    self.assertEqual('\x1b[34m250 OK\x1b[0m\n', interpreter.run_command('SETEVENTS BW'))
Beispiel #17
0
  def test_single_response(self):
    """
    Parses a GETINFO reply response for a single parameter.
    """

    control_message = ControlMessage.from_str(SINGLE_RESPONSE, 'GETINFO', normalize = True)
    self.assertEqual({'version': b'0.2.3.11-alpha-dev'}, control_message.entries)
Beispiel #18
0
  def test_single_response(self):
    """
    Parses a MAPADDRESS reply response with a single address mapping.
    """

    control_message = ControlMessage.from_str('250 foo=bar\r\n', 'MAPADDRESS')
    self.assertEqual({'foo': 'bar'}, control_message.entries)
Beispiel #19
0
    def test_get_info_without_fingerprint(self, get_conf_mock, msg_mock):
        msg_mock.return_value = ControlMessage.from_str(
            '551 Not running in server mode\r\n')
        get_conf_mock.return_value = None

        self.assertEqual(None, self.controller._last_fingerprint_exc)
        self.assertRaisesWith(stem.OperationFailed,
                              'Not running in server mode',
                              self.controller.get_info, 'fingerprint')
        self.assertEqual('Not running in server mode',
                         str(self.controller._last_fingerprint_exc))
        self.assertEqual(1, msg_mock.call_count)

        # now that we have a cached failure we should provide that back

        self.assertRaisesWith(stem.OperationFailed,
                              'Not running in server mode',
                              self.controller.get_info, 'fingerprint')
        self.assertEqual(1, msg_mock.call_count)

        # ... but if we become a relay we'll call it again

        get_conf_mock.return_value = '443'
        self.assertRaisesWith(stem.OperationFailed,
                              'Not running in server mode',
                              self.controller.get_info, 'fingerprint')
        self.assertEqual(2, msg_mock.call_count)
Beispiel #20
0
    async def test_with_get_protocolinfo(self, authenticate_none_mock,
                                         get_protocolinfo_mock):
        """
    Tests the authenticate() function when it needs to make a get_protocolinfo.
    """

        # tests where get_protocolinfo succeeds

        authenticate_none_mock.side_effect = coro_func_returning_value(None)

        protocolinfo_message = ControlMessage.from_str(
            '250-PROTOCOLINFO 1\r\n250 OK\r\n', 'PROTOCOLINFO')
        protocolinfo_message.auth_methods = (stem.connection.AuthMethod.NONE, )
        get_protocolinfo_mock.side_effect = coro_func_returning_value(
            protocolinfo_message)

        await stem.connection.authenticate(None)

        # tests where get_protocolinfo raises an exception

        get_protocolinfo_mock.side_effect = stem.ProtocolError
        with self.assertRaises(stem.connection.IncorrectSocketType):
            await stem.connection.authenticate(None)

        get_protocolinfo_mock.side_effect = stem.SocketError
        with self.assertRaises(stem.connection.AuthenticationFailure):
            await stem.connection.authenticate(None)
Beispiel #21
0
    def _emit_event(self, event):
        # Spins up our Controller's thread pool, emits an event, then shuts it
        # down. This last part is important for a couple reasons...
        #
        #   1. So we don't leave any lingering threads.
        #
        #   2. To ensure our event handlers are done being executed. Events are
        #      processed asynchronously, so the only way to endsure it's done
        #      with its work is to join on the thread.

        with patch('time.time', Mock(return_value=TEST_TIMESTAMP)):
            with patch('stem.control.Controller.is_alive') as is_alive_mock:
                is_alive_mock.return_value = True
                self.controller._launch_threads()

                try:
                    # Converting an event back into an uncast ControlMessage, then feeding it
                    # into our controller's event queue.

                    uncast_event = ControlMessage.from_str(event.raw_content())
                    self.controller._event_queue.put(uncast_event)
                    self.controller._event_notice.set()
                    self.controller._event_queue.join(
                    )  # block until the event is consumed
                finally:
                    is_alive_mock.return_value = False
                    self.controller._close()
Beispiel #22
0
    def test_invalid_response(self):
        """
    Parses a malformed MAPADDRESS reply that contains an invalid response code.
    This is a proper controller message, but malformed according to the
    MAPADDRESS's spec.
    """

        control_message = ControlMessage.from_str(INVALID_EMPTY_RESPONSE,
                                                  normalize=True)
        self.assertRaises(stem.ProtocolError, stem.response.convert,
                          'MAPADDRESS', control_message)

        control_message = ControlMessage.from_str(INVALID_RESPONSE,
                                                  normalize=True)
        self.assertRaises(stem.ProtocolError, stem.response.convert,
                          'MAPADDRESS', control_message)
Beispiel #23
0
    def test_convert(self):
        """
    Exercises functionality of the convert method both when it works and
    there's an error.
    """

        # working case
        control_message = ControlMessage.from_str(NO_AUTH,
                                                  'PROTOCOLINFO',
                                                  normalize=True)

        # now this should be a ProtocolInfoResponse (ControlMessage subclass)
        self.assertTrue(
            isinstance(control_message, stem.response.ControlMessage))
        self.assertTrue(
            isinstance(control_message,
                       stem.response.protocolinfo.ProtocolInfoResponse))

        # exercise some of the ControlMessage functionality
        raw_content = (NO_AUTH + '\n').replace('\n', '\r\n')
        self.assertEqual(raw_content, control_message.raw_content())
        self.assertTrue(str(control_message).startswith('PROTOCOLINFO 1'))

        # attempt to convert the wrong type
        self.assertRaises(TypeError, stem.response.convert, 'PROTOCOLINFO',
                          'hello world')

        # attempt to convert a different message type
        self.assertRaises(stem.ProtocolError, ControlMessage.from_str,
                          '650 BW 32326 2856\r\n', 'PROTOCOLINFO')
Beispiel #24
0
    def test_get_info_without_fingerprint(self, get_conf_mock, msg_mock):
        msg_mock.return_value = ControlMessage.from_str(
            '551 Not running in server mode\r\n')
        get_conf_mock.return_value = None

        self.assertEqual(None, self.controller._last_fingerprint_exc)
        self.assertRaisesRegexp(stem.ProtocolError,
                                'Not running in server mode',
                                self.controller.get_info, 'fingerprint')
        self.assertEqual(
            "GETINFO response didn't have an OK status:\nNot running in server mode",
            str(self.controller._last_fingerprint_exc))
        self.assertEqual(1, msg_mock.call_count)

        # now that we have a cached failure we should provide that back

        self.assertRaisesRegexp(stem.ProtocolError,
                                'Not running in server mode',
                                self.controller.get_info, 'fingerprint')
        self.assertEqual(1, msg_mock.call_count)

        # ... but if we become a relay we'll call it again

        get_conf_mock.return_value = '443'
        self.assertRaisesRegexp(stem.ProtocolError,
                                'Not running in server mode',
                                self.controller.get_info, 'fingerprint')
        self.assertEqual(2, msg_mock.call_count)
Beispiel #25
0
def extended_circ(circ_id,
                  purpose,
                  guard="$5416F3E8F80101A133B1970495B04FDBD1C7446B~Unnamed"):
    s = "650 CIRC " + str(
        circ_id
    ) + " EXTENDED " + guard + ",$1F9544C0A80F1C5D8A5117FBFFB50694469CC7F4~as44194l10501,$DBD67767640197FF96EC6A87684464FC48F611B6~nocabal BUILD_FLAGS=IS_INTERNAL,NEED_CAPACITY,NEED_UPTIME PURPOSE=" + purpose + " TIME_CREATED=2018-05-04T06:09:32.751920\r\n"
    return ControlMessage.from_str(s, "EVENT")
Beispiel #26
0
    def test_exit_used(self, stdout_mock, from_port_mock):
        path_1 = ('9EA317EECA56BDF30CAEB208A253FB456EDAB1A0', 'bolobolo1')
        path_2 = ('00C2C2A16AEDB51D5E5FB7D6168FC66B343D822F', 'ph3x')
        path_3 = ('A59E1E7C7EAEE083D756EE1FF6EC31CA3D8651D7',
                  'chaoscomputerclub19')

        event = ControlMessage.from_str(
            '650 STREAM 15 SUCCEEDED 3 64.15.112.44:80',
            'EVENT',
            normalize=True)
        r_line = '%s pZ4efH6u4IPXVu4f9uwxyj2GUdc= oQZFLYe9e4A7bOkWKR7TaNxb0JE 2012-08-06 11:19:31 31.172.30.2 443 0'

        controller = from_port_mock().__enter__()
        controller.get_circuit.return_value = _make_circ_event(
            1, path_1, path_2, path_3)
        controller.get_network_status.return_value = RouterStatusEntryV3.create(
            {'r': r_line % path_3[1]})
        controller.get_info.return_value = 'unknown'

        import exit_used

        with patch(
                'builtins.input',
                Mock(side_effect=functools.partial(exit_used.stream_event,
                                                   controller, event))):
            exit_used.main()

        self.assertEqual(EXPECTED_EXIT_USED, stdout_mock.getvalue())
Beispiel #27
0
  def test_unicode_cookie(self):
    """
    Checks an authentication cookie with a unicode path.
    """

    control_message = ControlMessage.from_str(UNICODE_COOKIE_PATH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual(EXPECTED_UNICODE_PATH, control_message.cookie_path)
Beispiel #28
0
  def test_get_protocolinfo(self, get_protocolinfo_mock):
    """
    Exercises the get_protocolinfo() method.
    """

    # use the handy mocked protocolinfo response

    protocolinfo_msg = ControlMessage.from_str('250-PROTOCOLINFO 1\r\n250 OK\r\n', 'PROTOCOLINFO')
    get_protocolinfo_mock.return_value = protocolinfo_msg

    # compare the str representation of these object, because the class
    # does not have, nor need, a direct comparison operator

    self.assertEqual(
      str(protocolinfo_msg),
      str(self.controller.get_protocolinfo())
    )

    # raise an exception in the stem.connection.get_protocolinfo() call

    get_protocolinfo_mock.side_effect = ProtocolError

    # get a default value when the call fails

    self.assertEqual(
      'default returned',
      self.controller.get_protocolinfo(default = 'default returned')
    )

    # no default value, accept the error

    self.assertRaises(ProtocolError, self.controller.get_protocolinfo)
Beispiel #29
0
    def test_setevents(self):
        controller = Mock()
        controller.msg.return_value = ControlMessage.from_str('250 OK\r\n')

        interpreter = ControlInterpreter(controller)

        self.assertEqual('\x1b[34m250 OK\x1b[0m\n',
                         interpreter.run_command('SETEVENTS BW'))
Beispiel #30
0
def built_hs_circ(circ_id,
                  purpose,
                  hs_state,
                  guard="$5416F3E8F80101A133B1970495B04FDBD1C7446B~Unnamed"):
    s = "650 CIRC " + str(
        circ_id
    ) + " BUILT " + guard + ",$855BC2DABE24C861CD887DB9B2E950424B49FC34~Logforme,$E8B3796C809853D9C8AF6B8EDE9080B6F2AE8005~BensTorRelay,$EAB114DAF0488F1223FF30778468E272E00EDC32~trnyc3 BUILD_FLAGS=IS_INTERNAL,NEED_CAPACITY,NEED_UPTIME PURPOSE=" + purpose + " HS_STATE=" + hs_state + " REND_QUERY=4u56zw2g4uvyyq7i TIME_CREATED=2018-05-04T05:50:41.751938\r\n"
    return ControlMessage.from_str(s, "EVENT")
Beispiel #31
0
  def test_unknown_auth(self):
    """
    Checks a response with an unrecognized authtentication method.
    """

    control_message = ControlMessage.from_str(UNKNOWN_AUTH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual((AuthMethod.UNKNOWN, AuthMethod.PASSWORD), control_message.auth_methods)
    self.assertEqual(('MAGIC', 'PIXIE_DUST'), control_message.unknown_auth_methods)
Beispiel #32
0
  def test_multiple_auth(self):
    """
    Checks a response with multiple authentication methods.
    """

    control_message = ControlMessage.from_str(MULTIPLE_AUTH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual((AuthMethod.COOKIE, AuthMethod.PASSWORD), control_message.auth_methods)
    self.assertEqual('/home/atagar/.tor/control_auth_cookie', control_message.cookie_path)
Beispiel #33
0
  def test_getconf(self):
    controller = Mock()
    controller.msg.return_value = ControlMessage.from_str('250-Log=notice stdout\r\n250 Address\r\n')

    interpreter = ControlInterpreter(controller)

    self.assertEqual('\x1b[34m250-Log=notice stdout\r\x1b[0m\n\x1b[34m250 Address\x1b[0m\n', interpreter.run_command('GETCONF log address'))
    controller.msg.assert_called_with('GETCONF log address')
Beispiel #34
0
    def test_single_response(self):
        """
    Parses a MAPADDRESS reply response with a single address mapping.
    """

        control_message = ControlMessage.from_str('250 foo=bar\r\n',
                                                  'MAPADDRESS')
        self.assertEqual({'foo': 'bar'}, control_message.mapped)
Beispiel #35
0
  def test_invalid_non_mapping_content(self):
    """
    Parses a malformed GETINFO reply containing a line that isn't a key=value
    entry.
    """

    control_message = ControlMessage.from_str(NON_KEY_VALUE_ENTRY, normalize = True)
    self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO', control_message)
Beispiel #36
0
    def test_unicode_cookie(self):
        """
    Checks an authentication cookie with a unicode path.
    """

        control_message = ControlMessage.from_str(UNICODE_COOKIE_PATH,
                                                  'PROTOCOLINFO',
                                                  normalize=True)
        self.assertEqual(EXPECTED_UNICODE_PATH, control_message.cookie_path)
Beispiel #37
0
  def test_cookie_auth(self):
    """
    Checks a response with cookie authentication and a path including escape
    characters.
    """

    control_message = ControlMessage.from_str(COOKIE_AUTH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual((AuthMethod.COOKIE, ), control_message.auth_methods)
    self.assertEqual('/tmp/my data\\"dir//control_auth_cookie', control_message.cookie_path)
Beispiel #38
0
    def test_without_service_id(self):
        """
    Checks a response that lack an initial service id.
    """

        response = ControlMessage.from_str(WRONG_FIRST_KEY, normalize=True)
        self.assertRaisesRegexp(stem.ProtocolError,
                                'ADD_ONION response should start with',
                                stem.response.convert, 'ADD_ONION', response)
Beispiel #39
0
  def test_without_private_key(self):
    """
    Checks a response without a private key.
    """

    response = ControlMessage.from_str(WITHOUT_PRIVATE_KEY, 'ADD_ONION', normalize = True)
    self.assertEqual('gfzprpioee3hoppz', response.service_id)
    self.assertEqual(None, response.private_key)
    self.assertEqual(None, response.private_key_type)
Beispiel #40
0
  def test_invalid_multiline_content(self):
    """
    Parses a malformed GETINFO reply with a multi-line entry missing a newline
    between its key and value. This is a proper controller message, but
    malformed according to the GETINFO's spec.
    """

    control_message = ControlMessage.from_str(MISSING_MULTILINE_NEWLINE, normalize = True)
    self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO', control_message)
Beispiel #41
0
    def test_password_auth(self):
        """
    Checks a response with password authentication.
    """

        control_message = ControlMessage.from_str(PASSWORD_AUTH,
                                                  'PROTOCOLINFO',
                                                  normalize=True)
        self.assertEqual((AuthMethod.PASSWORD, ), control_message.auth_methods)
Beispiel #42
0
  def test_with_private_key(self):
    """
    Checks a response when there's a private key.
    """

    response = ControlMessage.from_str(WITH_PRIVATE_KEY, 'ADD_ONION', normalize = True)
    self.assertEqual('gfzprpioee3hoppz', response.service_id)
    self.assertTrue(response.private_key.startswith('MIICXgIBAAKB'))
    self.assertEqual('RSA1024', response.private_key_type)
    self.assertEqual({}, response.client_auth)
Beispiel #43
0
    def test_single_response(self):
        """
    Parses a GETINFO reply response for a single parameter.
    """

        control_message = ControlMessage.from_str(SINGLE_RESPONSE,
                                                  'GETINFO',
                                                  normalize=True)
        self.assertEqual({'version': b'0.2.3.11-alpha-dev'},
                         control_message.entries)
Beispiel #44
0
    def test_latin_cookie_path(self):
        """
    Parse a latin-1 path when our filesystem is configured for unicode.
    (:ticket:`57`)
    """

        control_message = ControlMessage.from_str(LATIN_COOKIE_PATH,
                                                  'PROTOCOLINFO',
                                                  normalize=True)
        self.assertEqual(EXPECTED_LATIN_PATH, control_message.cookie_path)
Beispiel #45
0
  def test_with_client_auth(self):
    """
    Checks a response when there's client credentials.
    """

    response = ControlMessage.from_str(WITH_CLIENT_AUTH, 'ADD_ONION', normalize = True)
    self.assertEqual('oekn5sqrvcu4wote', response.service_id)
    self.assertEqual(None, response.private_key)
    self.assertEqual(None, response.private_key_type)
    self.assertEqual({'bob': 'lhwLVFt0Kd5/0Gy9DkKoyA', 'alice': 'T9UADxtrvqx2HnLKWp/fWQ'}, response.client_auth)
Beispiel #46
0
    def test_invalid_non_mapping_content(self):
        """
    Parses a malformed GETINFO reply containing a line that isn't a key=value
    entry.
    """

        control_message = ControlMessage.from_str(NON_KEY_VALUE_ENTRY,
                                                  normalize=True)
        self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO',
                          control_message)
Beispiel #47
0
    def test_no_key_type(self):
        """
    Checks a response that's missing the private key type.
    """

        response = ControlMessage.from_str(MISSING_KEY_TYPE, normalize=True)
        self.assertRaisesRegexp(
            stem.ProtocolError,
            'ADD_ONION PrivateKey lines should be of the form',
            stem.response.convert, 'ADD_ONION', response)
Beispiel #48
0
def circ_bw(circ_id, read, sent, delivered_read, delivered_sent, overhead_read,
            overhead_sent):
    s = "650 CIRC_BW ID=" + str(circ_id) + " READ=" + str(
        int(read)) + " WRITTEN=" + str(int(
            sent)) + " TIME=2018-05-04T06:08:55.751726 DELIVERED_READ=" + str(
                int(delivered_read)) + " OVERHEAD_READ=" + str(
                    int(overhead_read)) + " DELIVERED_WRITTEN=" + str(
                        int(delivered_sent)) + " OVERHEAD_WRITTEN=" + str(
                            int(overhead_sent)) + "\r\n"
    return ControlMessage.from_str(s, "EVENT")
Beispiel #49
0
    def test_without_private_key(self):
        """
    Checks a response without a private key.
    """

        response = ControlMessage.from_str(WITHOUT_PRIVATE_KEY,
                                           'ADD_ONION',
                                           normalize=True)
        self.assertEqual('gfzprpioee3hoppz', response.service_id)
        self.assertEqual(None, response.private_key)
        self.assertEqual(None, response.private_key_type)
Beispiel #50
0
  def test_unrecognized_key_response(self):
    """
    Parses a GETCONF reply that contains an error code with an unrecognized key.
    """

    try:
      control_message = ControlMessage.from_str(UNRECOGNIZED_KEY_RESPONSE, normalize = True)
      stem.response.convert('GETCONF', control_message)
      self.fail('expected a stem.InvalidArguments to be raised')
    except stem.InvalidArguments as exc:
      self.assertEqual(exc.arguments, ['brickroad', 'submarine'])
Beispiel #51
0
  def test_unrecognized_key_response(self):
    """
    Parses a GETCONF reply that contains an error code with an unrecognized key.
    """

    try:
      control_message = ControlMessage.from_str(UNRECOGNIZED_KEY_RESPONSE, normalize = True)
      stem.response.convert('GETCONF', control_message)
      self.fail('expected a stem.InvalidArguments to be raised')
    except stem.InvalidArguments as exc:
      self.assertEqual(exc.arguments, ['brickroad', 'submarine'])
Beispiel #52
0
  def test_no_auth(self):
    """
    Checks a response when there's no authentication.
    """

    control_message = ControlMessage.from_str(NO_AUTH, 'PROTOCOLINFO', normalize = True)
    self.assertEqual(1, control_message.protocol_version)
    self.assertEqual(stem.version.Version('0.2.1.30'), control_message.tor_version)
    self.assertEqual((AuthMethod.NONE, ), control_message.auth_methods)
    self.assertEqual((), control_message.unknown_auth_methods)
    self.assertEqual(None, control_message.cookie_path)
Beispiel #53
0
    def test_invalid_multiline_content(self):
        """
    Parses a malformed GETINFO reply with a multi-line entry missing a newline
    between its key and value. This is a proper controller message, but
    malformed according to the GETINFO's spec.
    """

        control_message = ControlMessage.from_str(MISSING_MULTILINE_NEWLINE,
                                                  normalize=True)
        self.assertRaises(stem.ProtocolError, stem.response.convert, 'GETINFO',
                          control_message)
Beispiel #54
0
    def test_getconf(self):
        controller = Mock()
        controller.msg.return_value = ControlMessage.from_str(
            '250-Log=notice stdout\r\n250 Address\r\n')

        interpreter = ControlInterpreter(controller)

        self.assertEqual(
            '\x1b[34m250-Log=notice stdout\r\x1b[0m\n\x1b[34m250 Address\x1b[0m\n',
            interpreter.run_command('GETCONF log address'))
        controller.msg.assert_called_with('GETCONF log address')
Beispiel #55
0
  def test_multivalue_response(self):
    """
    Parses a GETCONF reply containing a single key with multiple parameters.
    """

    expected = {
      'ControlPort': ['9100'],
      'ExitPolicy': ['accept 34.3.4.5', 'accept 3.4.53.3', 'accept 3.4.53.3', 'reject 23.245.54.3']
    }

    control_message = ControlMessage.from_str(MULTIVALUE_RESPONSE, 'GETCONF', normalize = True)
    self.assertEqual(expected, control_message.entries)
Beispiel #56
0
  def test_empty_response(self):
    """
    Parses a GETCONF reply without options (just calling "GETCONF").
    """

    control_message = ControlMessage.from_str('250 OK\r\n', 'GETCONF')

    # now this should be a GetConfResponse (ControlMessage subclass)
    self.assertTrue(isinstance(control_message, stem.response.ControlMessage))
    self.assertTrue(isinstance(control_message, stem.response.getconf.GetConfResponse))

    self.assertEqual({}, control_message.entries)
Beispiel #57
0
  def test_minimum_response(self):
    """
    Checks a PROTOCOLINFO response that only contains the minimum amount of
    information to be a valid response.
    """

    control_message = ControlMessage.from_str(MINIMUM_RESPONSE, 'PROTOCOLINFO', normalize = True)
    self.assertEqual(5, control_message.protocol_version)
    self.assertEqual(None, control_message.tor_version)
    self.assertEqual((), control_message.auth_methods)
    self.assertEqual((), control_message.unknown_auth_methods)
    self.assertEqual(None, control_message.cookie_path)
Beispiel #58
0
  def test_getinfo(self):
    controller = Mock()
    controller.msg.return_value = ControlMessage.from_str('250-version=0.2.5.1-alpha-dev (git-245ecfff36c0cecc)\r\n250 OK\r\n')

    interpreter = ControlInterpreter(controller)

    self.assertEqual('\x1b[34m250-version=0.2.5.1-alpha-dev (git-245ecfff36c0cecc)\r\x1b[0m\n\x1b[34m250 OK\x1b[0m\n', interpreter.run_command('GETINFO version'))
    self.assertEqual('\x1b[34m250-version=0.2.5.1-alpha-dev (git-245ecfff36c0cecc)\r\x1b[0m\n\x1b[34m250 OK\x1b[0m\n', interpreter.run_command('GETINFO version'))
    controller.msg.assert_called_with('GETINFO version')

    controller.msg.side_effect = stem.ControllerError('kaboom!')
    self.assertEqual('\x1b[1;31mkaboom!\x1b[0m\n', interpreter.run_command('getinfo process/user'))
Beispiel #59
0
  def test_multiline_response(self):
    """
    Parses a GETINFO reply for multiple parameters including a multi-line
    value.
    """

    expected = {
      'version': b'0.2.3.11-alpha-dev (git-ef0bc7f8f26a917c)',
      'config-text': b'\n'.join(stem.util.str_tools._to_bytes(MULTILINE_RESPONSE).splitlines()[2:8]),
    }

    control_message = ControlMessage.from_str(MULTILINE_RESPONSE, 'GETINFO', normalize = True)
    self.assertEqual(expected, control_message.entries)
Beispiel #60
0
  def test_valid_response(self):
    """
    Parses valid AUTHCHALLENGE responses.
    """

    control_message = ControlMessage.from_str(VALID_RESPONSE, 'AUTHCHALLENGE', normalize = True)

    # now this should be a AuthChallengeResponse (ControlMessage subclass)
    self.assertTrue(isinstance(control_message, stem.response.ControlMessage))
    self.assertTrue(isinstance(control_message, stem.response.authchallenge.AuthChallengeResponse))

    self.assertEqual(VALID_HASH, control_message.server_hash)
    self.assertEqual(VALID_NONCE, control_message.server_nonce)