def test_bootstrap_callback(self): ''' FIXME: something is still screwy with this; try throwing an exception from TorState.bootstrap and we'll just hang... ''' from test_torconfig import FakeControlProtocol protocol = FakeControlProtocol([ "ns/all=", # ns/all "", # circuit-status "", # stream-status "", # address-mappings/all "entry-guards=\r\n$0000000000000000000000000000000000000000=name up\r\n$1111111111111111111111111111111111111111=foo up\r\n$9999999999999999999999999999999999999999=eman unusable 2012-01-01 22:00:00\r\n", # entry-guards "99999", # process/pid "??", # ip-to-country/0.0.0.0 ]) state = yield TorState.from_protocol(protocol) self.assertEqual(len(state.entry_guards), 2) self.assertTrue( '$0000000000000000000000000000000000000000' in state.entry_guards) self.assertTrue( '$1111111111111111111111111111111111111111' in state.entry_guards) self.assertEqual(len(state.unusable_entry_guards), 1) self.assertTrue('$9999999999999999999999999999999999999999' in state.unusable_entry_guards[0])
def setUp(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([]) self.protocol.event_happened('INFO', 'something craaaaaaazy') self.protocol.event_happened( 'INFO', 'connection_dir_client_reached_eof(): Uploaded rendezvous ' 'descriptor (status 200 ("Service descriptor (v2) stored"))') self.config = TorConfig(self.protocol) self.protocol.answers.append( 'config/names=\nHiddenServiceOptions Virtual') self.protocol.answers.append('HiddenServiceOptions') self.patcher = patch('txtorcon.torconfig.find_tor_binary', return_value='/not/tor') self.patcher.start()
def setUp(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([]) self.config = TorConfig(self.protocol) self.protocol.answers.append( 'config/names=\nHiddenServiceOptions Virtual') self.protocol.answers.append('HiddenServiceOptions') self.patcher = patch('txtorcon.torconfig.find_tor_binary', return_value='/not/tor') self.patcher.start()
def setUp(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([]) self.protocol.event_happened("INFO", "something craaaaaaazy") self.protocol.event_happened( "INFO", "connection_dir_client_reached_eof(): Uploaded rendezvous " 'descriptor (status 200 ("Service descriptor (v2) stored"))', ) self.config = TorConfig(self.protocol) self.protocol.answers.append("config/names=\nHiddenServiceOptions Virtual") self.protocol.answers.append("HiddenServiceOptions") self.patcher = patch("txtorcon.torconfig.find_tor_binary", return_value="/not/tor") self.patcher.start()
class EndpointTests(unittest.TestCase): def setUp(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([]) self.protocol.event_happened('INFO', 'something craaaaaaazy') self.protocol.event_happened( 'INFO', 'connection_dir_client_reached_eof(): Uploaded rendezvous ' 'descriptor (status 200 ("Service descriptor (v2) stored"))' ) self.config = TorConfig(self.protocol) self.protocol.answers.append( 'config/names=\nHiddenServiceOptions Virtual' ) self.protocol.answers.append('HiddenServiceOptions') self.patcher = patch( 'txtorcon.torconfig.find_tor_binary', return_value='/not/tor' ) self.patcher.start() def tearDown(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.patcher.stop() @defer.inlineCallbacks def test_global_tor(self): config = yield get_global_tor( Mock(), _tor_launcher=lambda x, y, z: True ) self.assertEqual(0, config.SOCKSPort) @defer.inlineCallbacks def test_global_tor_error(self): config0 = yield get_global_tor( Mock(), _tor_launcher=lambda x, y, z: True ) # now if we specify a control_port it should be an error since # the above should have launched one. try: config1 = yield get_global_tor(Mock(), control_port=111, _tor_launcher=lambda x, y, z: True) self.fail() except RuntimeError as e: # should be an error pass @defer.inlineCallbacks def test_endpoint_properties(self): ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80) self.assertEqual(None, ep.onion_private_key) self.assertEqual(None, ep.onion_uri) ep.hiddenservice = Mock() ep.hiddenservice.private_key = 'mumble' self.assertEqual('mumble', ep.onion_private_key) @defer.inlineCallbacks def test_private_tor(self): m = Mock() from txtorcon import endpoints endpoints.launch_tor = m ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80, control_port=1234) self.assertTrue(m.called) @defer.inlineCallbacks def test_private_tor_no_control_port(self): m = Mock() from txtorcon import endpoints endpoints.launch_tor = m ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80) self.assertTrue(m.called) @defer.inlineCallbacks def test_system_tor(self): from test_torconfig import FakeControlProtocol def boom(*args): # why does the new_callable thing need a callable that # returns a callable? Feels like I must be doing something # wrong somewhere... def bam(*args, **kw): return self.protocol return bam with patch('txtorcon.endpoints.launch_tor') as launch_mock: with patch('txtorcon.endpoints.build_tor_connection', new_callable=boom) as btc: client = clientFromString( self.reactor, "tcp:host=localhost:port=9050" ) ep = yield TCPHiddenServiceEndpoint.system_tor(self.reactor, client, 80) port = yield ep.listen(NoOpProtocolFactory()) toa = port.getHost() self.assertTrue(hasattr(toa, 'onion_uri')) self.assertTrue(hasattr(toa, 'onion_port')) port.startListening() str(port) port.tor_config # system_tor should be connecting to a running one, # *not* launching a new one. self.assertFalse(launch_mock.called) @defer.inlineCallbacks def test_basic(self): listen = RuntimeError("listen") connect = RuntimeError("connect") reactor = proto_helpers.RaisingMemoryReactor(listen, connect) reactor.addSystemEventTrigger = Mock() ep = TCPHiddenServiceEndpoint(reactor, self.config, 123) self.config.bootstrap() yield self.config.post_bootstrap self.assertTrue(IProgressProvider.providedBy(ep)) try: port = yield ep.listen(NoOpProtocolFactory()) self.fail("Should have been an exception") except RuntimeError as e: # make sure we called listenTCP not connectTCP self.assertEqual(e, listen) repr(self.config.HiddenServices) def test_progress_updates(self): config = TorConfig() ep = TCPHiddenServiceEndpoint(self.reactor, config, 123) self.assertTrue(IProgressProvider.providedBy(ep)) prog = IProgressProvider(ep) ding = Mock() prog.add_progress_listener(ding) args = (50, "blarg", "Doing that thing we talked about.") # kind-of cheating, test-wise? ep._tor_progress_update(*args) self.assertTrue(ding.called_with(*args)) @patch('txtorcon.endpoints.launch_tor') def test_progress_updates_private_tor(self, tor): ep = TCPHiddenServiceEndpoint.private_tor(self.reactor, 1234) tor.call_args[1]['progress_updates'](40, 'FOO', 'foo to the bar') return ep def __test_progress_updates_system_tor(self): ep = TCPHiddenServiceEndpoint.system_tor(self.reactor, 1234) ep._tor_progress_update(40, "FOO", "foo to bar") return ep @patch('txtorcon.endpoints.get_global_tor') def test_progress_updates_global_tor(self, tor): ep = TCPHiddenServiceEndpoint.global_tor(self.reactor, 1234) tor.call_args[1]['progress_updates'](40, 'FOO', 'foo to the bar') return ep def test_hiddenservice_key_unfound(self): ep = TCPHiddenServiceEndpoint.private_tor( self.reactor, 1234, hidden_service_dir='/dev/null' ) # FIXME Mock() should work somehow for this, but I couldn't # make it "go" class Blam(object): @property def private_key(self): raise IOError("blam") ep.hiddenservice = Blam() self.assertEqual(ep.onion_private_key, None) return ep def test_multiple_listen(self): ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d0 = ep.listen(NoOpProtocolFactory()) @defer.inlineCallbacks def more_listen(arg): yield arg.stopListening() d1 = ep.listen(NoOpProtocolFactory()) def foo(arg): return arg d1.addBoth(foo) defer.returnValue(arg) return d0.addBoth(more_listen) self.config.bootstrap() def check(arg): self.assertEqual('127.0.0.1', ep.tcp_endpoint._interface) self.assertEqual(len(self.config.HiddenServices), 1) d0.addCallback(check).addErrback(self.fail) return d0 def test_already_bootstrapped(self): self.config.bootstrap() ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d = ep.listen(NoOpProtocolFactory()) return d @defer.inlineCallbacks def test_explicit_data_dir(self): d = tempfile.mkdtemp() try: with open(os.path.join(d, 'hostname'), 'w') as f: f.write('public') config = TorConfig(self.protocol) ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, d) # make sure listen() correctly configures our hidden-serivce # with the explicit directory we passed in above port = yield ep.listen(NoOpProtocolFactory()) self.assertEqual(1, len(config.HiddenServices)) self.assertEqual(config.HiddenServices[0].dir, d) self.assertEqual(config.HiddenServices[0].hostname, 'public') finally: shutil.rmtree(d, ignore_errors=True) def test_failure(self): self.reactor.failures = 1 ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d = ep.listen(NoOpProtocolFactory()) self.config.bootstrap() d.addErrback(self.check_error) return d def check_error(self, failure): self.assertEqual(failure.type, error.CannotListenError) return None def test_parse_via_plugin(self): # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config) ) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=/foo/bar' ) self.assertEqual(ep.public_port, 88) self.assertEqual(ep.local_port, 1234) self.assertEqual(ep.hidden_service_dir, '/foo/bar') def test_parse_user_path(self): # this makes sure we expand users and symlinks in # hiddenServiceDir args. see Issue #77 # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config) ) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=~/blam/blarg' ) # would be nice to have a fixed path here, but then would have # to run as a known user :/ # maybe using the docker stuff to run integration tests better here? self.assertEqual( os.path.expanduser('~/blam/blarg'), ep.hidden_service_dir ) def test_parse_relative_path(self): # this makes sure we convert a relative path to absolute # hiddenServiceDir args. see Issue #77 # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config) ) orig = os.path.realpath('.') try: with util.TempDir() as t: t = str(t) os.chdir(t) os.mkdir(os.path.join(t, 'foo')) hsdir = os.path.join(t, 'foo', 'blam') os.mkdir(hsdir) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=foo/blam' ) self.assertEqual( os.path.realpath(hsdir), ep.hidden_service_dir ) finally: os.chdir(orig) @defer.inlineCallbacks def test_stealth_auth(self): ''' make sure we produce a HiddenService instance with stealth-auth lines if we had authentication specified in the first place. ''' config = TorConfig(self.protocol) ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, '/dev/null', stealth_auth=['alice', 'bob']) # make sure listen() correctly configures our hidden-serivce # with the explicit directory we passed in above d = ep.listen(NoOpProtocolFactory()) def foo(fail): print "ERROR", fail d.addErrback(foo) port = yield d self.assertEqual(1, len(config.HiddenServices)) self.assertEqual(config.HiddenServices[0].dir, '/dev/null') self.assertEqual(config.HiddenServices[0].authorize_client[0], 'stealth alice,bob') self.assertEqual(None, ep.onion_uri) config.HiddenServices[0].hostname = 'oh my' self.assertEqual('oh my', ep.onion_uri)
class EndpointTests(unittest.TestCase): def setUp(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([]) self.protocol.event_happened('INFO', 'something craaaaaaazy') self.protocol.event_happened( 'INFO', 'connection_dir_client_reached_eof(): Uploaded rendezvous ' 'descriptor (status 200 ("Service descriptor (v2) stored"))') self.config = TorConfig(self.protocol) self.protocol.answers.append( 'config/names=\nHiddenServiceOptions Virtual') self.protocol.answers.append('HiddenServiceOptions') self.patcher = patch('txtorcon.torconfig.find_tor_binary', return_value='/not/tor') self.patcher.start() def tearDown(self): from txtorcon import endpoints endpoints._global_tor_config = None del endpoints._global_tor_lock endpoints._global_tor_lock = defer.DeferredLock() self.patcher.stop() @defer.inlineCallbacks def test_global_tor(self): config = yield get_global_tor(Mock(), _tor_launcher=lambda x, y, z: True) self.assertEqual(0, config.SOCKSPort) @defer.inlineCallbacks def test_global_tor_error(self): config0 = yield get_global_tor(Mock(), _tor_launcher=lambda x, y, z: True) # now if we specify a control_port it should be an error since # the above should have launched one. try: config1 = yield get_global_tor(Mock(), control_port=111, _tor_launcher=lambda x, y, z: True) self.fail() except RuntimeError as e: # should be an error pass @defer.inlineCallbacks def test_endpoint_properties(self): ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80) self.assertEqual(None, ep.onion_private_key) self.assertEqual(None, ep.onion_uri) ep.hiddenservice = Mock() ep.hiddenservice.private_key = 'mumble' self.assertEqual('mumble', ep.onion_private_key) @defer.inlineCallbacks def test_private_tor(self): m = Mock() from txtorcon import endpoints endpoints.launch_tor = m ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80, control_port=1234) self.assertTrue(m.called) @defer.inlineCallbacks def test_private_tor_no_control_port(self): m = Mock() from txtorcon import endpoints endpoints.launch_tor = m ep = yield TCPHiddenServiceEndpoint.private_tor(Mock(), 80) self.assertTrue(m.called) @defer.inlineCallbacks def test_system_tor(self): from test_torconfig import FakeControlProtocol def boom(*args): # why does the new_callable thing need a callable that # returns a callable? Feels like I must be doing something # wrong somewhere... def bam(*args, **kw): return self.protocol return bam with patch('txtorcon.endpoints.launch_tor') as launch_mock: with patch('txtorcon.endpoints.build_tor_connection', new_callable=boom) as btc: client = clientFromString(self.reactor, "tcp:host=localhost:port=9050") ep = yield TCPHiddenServiceEndpoint.system_tor( self.reactor, client, 80) port = yield ep.listen(NoOpProtocolFactory()) toa = port.getHost() self.assertTrue(hasattr(toa, 'onion_uri')) self.assertTrue(hasattr(toa, 'onion_port')) port.startListening() str(port) port.tor_config # system_tor should be connecting to a running one, # *not* launching a new one. self.assertFalse(launch_mock.called) @defer.inlineCallbacks def test_basic(self): listen = RuntimeError("listen") connect = RuntimeError("connect") reactor = proto_helpers.RaisingMemoryReactor(listen, connect) reactor.addSystemEventTrigger = Mock() ep = TCPHiddenServiceEndpoint(reactor, self.config, 123) self.config.bootstrap() yield self.config.post_bootstrap self.assertTrue(IProgressProvider.providedBy(ep)) try: port = yield ep.listen(NoOpProtocolFactory()) self.fail("Should have been an exception") except RuntimeError as e: # make sure we called listenTCP not connectTCP self.assertEqual(e, listen) repr(self.config.HiddenServices) def test_progress_updates(self): config = TorConfig() ep = TCPHiddenServiceEndpoint(self.reactor, config, 123) self.assertTrue(IProgressProvider.providedBy(ep)) prog = IProgressProvider(ep) ding = Mock() prog.add_progress_listener(ding) args = (50, "blarg", "Doing that thing we talked about.") # kind-of cheating, test-wise? ep._tor_progress_update(*args) self.assertTrue(ding.called_with(*args)) @patch('txtorcon.endpoints.launch_tor') def test_progress_updates_private_tor(self, tor): ep = TCPHiddenServiceEndpoint.private_tor(self.reactor, 1234) tor.call_args[1]['progress_updates'](40, 'FOO', 'foo to the bar') return ep def __test_progress_updates_system_tor(self): ep = TCPHiddenServiceEndpoint.system_tor(self.reactor, 1234) ep._tor_progress_update(40, "FOO", "foo to bar") return ep @patch('txtorcon.endpoints.get_global_tor') def test_progress_updates_global_tor(self, tor): ep = TCPHiddenServiceEndpoint.global_tor(self.reactor, 1234) tor.call_args[1]['progress_updates'](40, 'FOO', 'foo to the bar') return ep def test_hiddenservice_key_unfound(self): ep = TCPHiddenServiceEndpoint.private_tor( self.reactor, 1234, hidden_service_dir='/dev/null') # FIXME Mock() should work somehow for this, but I couldn't # make it "go" class Blam(object): @property def private_key(self): raise IOError("blam") ep.hiddenservice = Blam() self.assertEqual(ep.onion_private_key, None) return ep def test_multiple_listen(self): ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d0 = ep.listen(NoOpProtocolFactory()) @defer.inlineCallbacks def more_listen(arg): yield arg.stopListening() d1 = ep.listen(NoOpProtocolFactory()) def foo(arg): return arg d1.addBoth(foo) defer.returnValue(arg) return d0.addBoth(more_listen) self.config.bootstrap() def check(arg): self.assertEqual('127.0.0.1', ep.tcp_endpoint._interface) self.assertEqual(len(self.config.HiddenServices), 1) d0.addCallback(check).addErrback(self.fail) return d0 def test_already_bootstrapped(self): self.config.bootstrap() ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d = ep.listen(NoOpProtocolFactory()) return d @defer.inlineCallbacks def test_explicit_data_dir(self): d = tempfile.mkdtemp() try: with open(os.path.join(d, 'hostname'), 'w') as f: f.write('public') config = TorConfig(self.protocol) ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, d) # make sure listen() correctly configures our hidden-serivce # with the explicit directory we passed in above port = yield ep.listen(NoOpProtocolFactory()) self.assertEqual(1, len(config.HiddenServices)) self.assertEqual(config.HiddenServices[0].dir, d) self.assertEqual(config.HiddenServices[0].hostname, 'public') finally: shutil.rmtree(d, ignore_errors=True) def test_failure(self): self.reactor.failures = 1 ep = TCPHiddenServiceEndpoint(self.reactor, self.config, 123) d = ep.listen(NoOpProtocolFactory()) self.config.bootstrap() d.addErrback(self.check_error) return d def check_error(self, failure): self.assertEqual(failure.type, error.CannotListenError) return None def test_parse_via_plugin(self): # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config)) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=/foo/bar') self.assertEqual(ep.public_port, 88) self.assertEqual(ep.local_port, 1234) self.assertEqual(ep.hidden_service_dir, '/foo/bar') def test_parse_user_path(self): # this makes sure we expand users and symlinks in # hiddenServiceDir args. see Issue #77 # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config)) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=~/blam/blarg') # would be nice to have a fixed path here, but then would have # to run as a known user :/ # maybe using the docker stuff to run integration tests better here? self.assertEqual(os.path.expanduser('~/blam/blarg'), ep.hidden_service_dir) def test_parse_relative_path(self): # this makes sure we convert a relative path to absolute # hiddenServiceDir args. see Issue #77 # make sure we have a valid thing from get_global_tor without # actually launching tor config = TorConfig() config.post_bootstrap = defer.succeed(config) from txtorcon import torconfig torconfig._global_tor_config = None get_global_tor( self.reactor, _tor_launcher=lambda react, config, prog: defer.succeed(config)) orig = os.path.realpath('.') try: with util.TempDir() as t: t = str(t) os.chdir(t) os.mkdir(os.path.join(t, 'foo')) hsdir = os.path.join(t, 'foo', 'blam') os.mkdir(hsdir) ep = serverFromString( self.reactor, 'onion:88:localPort=1234:hiddenServiceDir=foo/blam') self.assertEqual(os.path.realpath(hsdir), ep.hidden_service_dir) finally: os.chdir(orig) @defer.inlineCallbacks def test_stealth_auth(self): ''' make sure we produce a HiddenService instance with stealth-auth lines if we had authentication specified in the first place. ''' config = TorConfig(self.protocol) ep = TCPHiddenServiceEndpoint(self.reactor, config, 123, '/dev/null', stealth_auth=['alice', 'bob']) # make sure listen() correctly configures our hidden-serivce # with the explicit directory we passed in above d = ep.listen(NoOpProtocolFactory()) def foo(fail): print "ERROR", fail d.addErrback(foo) port = yield d self.assertEqual(1, len(config.HiddenServices)) self.assertEqual(config.HiddenServices[0].dir, '/dev/null') self.assertEqual(config.HiddenServices[0].authorize_client[0], 'stealth alice,bob') self.assertEqual(None, ep.onion_uri) config.HiddenServices[0].hostname = 'oh my' self.assertEqual('oh my', ep.onion_uri)
def setUp(self): self.reactor = FakeReactorTcp(self) self.protocol = FakeControlProtocol([])