def test_happened_already(self): proto = FakeControlProtocol([]) events = [] def event_cb(*args, **kw): events.append((args, kw)) proto.event_happened("something", "arg") proto.add_event_listener("something", event_cb) self.assertEqual( [(("arg",), {})], events )
def test_set_dir(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hsdir0 = self.mktemp() os.mkdir(hsdir0) hsdir1 = self.mktemp() os.mkdir(hsdir1) with open(join(hsdir0, "hostname"), "w") as f: f.write('{}.onion'.format(_test_onion_id)) hs_d = FilesystemOnionService.create( Mock(), config, hsdir=hsdir0, ports=["80 127.0.0.1:4321"], version=3, ) # arrange HS_DESC callbacks so we get the hs instance back cb = protocol.events['HS_DESC'] cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id)) cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id)) hs = yield hs_d hs.dir = hsdir1 self.assertEqual(hs.dir, hsdir1)
def test_tor_version_v3_progress(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hsdir = self.mktemp() os.mkdir(hsdir) with open(join(hsdir, "hostname"), "w") as f: f.write('{}.onion'.format(_test_onion_id)) def my_progress(a, b, c): pass eph_d = FilesystemOnionService.create( Mock(), config, hsdir, ports=["80 127.0.0.1:80"], progress=my_progress, version=3, ) # arrange HS_DESC callbacks so we get the hs instance back cb = protocol.events['HS_DESC'] cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id)) cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id)) yield eph_d
def test_tor_version_v3_progress_await_all(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hsdir = self.mktemp() os.mkdir(hsdir) with open(join(hsdir, "hostname"), "w") as f: f.write('{}.onion'.format(_test_onion_id)) class Bad(Exception): pass def my_progress(a, b, c): raise Bad("it's bad") eph_d = FilesystemOnionService.create( Mock(), config, hsdir, ports=["80 127.0.0.1:80"], progress=my_progress, version=3, await_all_uploads=True, ) # arrange HS_DESC callbacks so we get the hs instance back cb = protocol.events['HS_DESC'] cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id)) cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id)) yield eph_d errs = self.flushLoggedErrors(Bad) self.assertEqual(3, len(errs)) # because there's a "100%" one too
def test_ephemeral_bad_return_value(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) progress_messages = [] def progress(*args): progress_messages.append(args) eph_d = EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], progress=progress, private_key=DISCARD, ) cmd, d = protocol.commands[0] self.assertEqual(u"ADD_ONION NEW:BEST Port=80,127.0.0.1:80 Flags=DiscardPK", cmd) d.callback("BadKey=nothing") def check(f): self.assertIn("Expected ADD_ONION to return ServiceID", str(f.value)) return None eph_d.addCallbacks(self.fail, check) return eph_d
def test_ephemeral_remove_not_ok(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) eph_d = EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], ) cmd, d = protocol.commands[0] self.assertEqual(u"ADD_ONION NEW:BEST Port=80,127.0.0.1:80", cmd) d.callback("PrivateKey={}\nServiceID={}".format(_test_private_key_blob, _test_onion_id)) cb = protocol.events['HS_DESC'] for x in range(6): cb('UPLOAD {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) for x in range(6): cb('UPLOADED {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) hs = yield eph_d remove_d = hs.remove() cmd, d = protocol.commands[-1] self.assertEqual(u"DEL_ONION {}".format(_test_onion_id), cmd) d.callback('bad stuff') with self.assertRaises(RuntimeError): yield remove_d
def test_set_ports(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hsdir = self.mktemp() os.mkdir(hsdir) with open(join(hsdir, 'hs_ed25519_secret_key'), 'wb') as f: f.write(b'\x01\x02\x03\x04') with open(join(hsdir, 'hostname'), 'w') as f: f.write('{}.onion'.format(_test_onion_id)) hs_d = FilesystemOnionService.create( Mock(), config, hsdir=hsdir, ports=["80 127.0.0.1:4321"], version=3, ) # arrange HS_DESC callbacks so we get the hs instance back cb = protocol.events['HS_DESC'] cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id)) cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id)) hs = yield hs_d hs.ports = ["443 127.0.0.1:443"] self.assertEqual(1, len(hs.ports))
def test_old_tor_version(self): protocol = FakeControlProtocol([]) protocol.version = "0.1.2.3" config = TorConfig(protocol) hsdir = self.mktemp() def my_progress(a, b, c): pass eph_d = FilesystemOnionService.create( Mock(), config, hsdir, ports=["80 127.0.0.1:80"], progress=my_progress, ) yield eph_d
def test_unknown_version(self): protocol = FakeControlProtocol([]) protocol.version = "0.1.1.1" config = TorConfig(protocol) hsdir = self.mktemp() os.mkdir(hsdir) hs = yield FilesystemOnionService.create( Mock(), config, hsdir=hsdir, ports=["80 127.0.0.1:4321"], version=99, ) with self.assertRaises(RuntimeError) as ctx: hs.private_key self.assertIn("Don't know how to load", str(ctx.exception))
def setUp(self): self.thedir = self.mktemp() os.mkdir(self.thedir) protocol = FakeControlProtocol([]) self.config = TorConfig(protocol) self.hs = FilesystemAuthenticatedOnionService( config=self.config, thedir=self.thedir, ports=["80 127.0.0.1:1234"], auth=AuthBasic(['foo', 'bar']))
def test_ephemeral_ver_option(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hs = EphemeralOnionService( config, ports=["80 127.0.0.1:80"], ver=2, ) self.assertEqual(2, hs.version)
def test_ephemeral_key_whitespace1(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) d = EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], private_key=_test_private_key_blob + '\n', detach=True, ) return self.assertFailure(d, ValueError)
def test_filesystem_wrong_ports(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) with self.assertRaises(ValueError) as ctx: yield FilesystemOnionService.create( Mock(), config, "/dev/null", ports="80 127.0.0.1:80", ) self.assertIn("'ports' must be a list of strings", str(ctx.exception))
def test_ephemeral_v3_ip_addr_tuple_non_local(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) # returns a Deferred we're ignoring with self.assertRaises(ValueError): yield EphemeralOnionService.create( Mock(), config, ports=[(80, "hostname:80")], detach=True, version=3, )
def test_ephemeral_ports_no_spaces(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) privkey = 'a' * 32 with self.assertRaises(ValueError) as ctx: yield EphemeralOnionService.create( Mock(), config, ports=["80:127.0.0.1:80"], private_key=privkey, ) self.assertIn("exactly one space", str(ctx.exception))
def test_ephemeral_ports_non_local(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) privkey = 'a' * 32 with self.assertRaises(ValueError) as ctx: yield EphemeralOnionService.create( Mock(), config, ports=["80 8.8.8.8:80"], private_key=privkey, ) self.assertIn("should be a local address", str(ctx.exception))
def test_ephemeral_ports_not_an_int(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) privkey = 'a' * 32 with self.assertRaises(ValueError) as ctx: yield EphemeralOnionService.create( Mock(), config, ports=["web 127.0.0.1:80"], private_key=privkey, ) self.assertIn("external port isn't an int", str(ctx.exception))
def test_ephemeral_ports_not_a_list(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) privkey = 'a' * 32 with self.assertRaises(ValueError) as ctx: yield EphemeralOnionService.create( Mock(), config, ports="80 127.0.0.1:80", private_key=privkey, ) self.assertIn("'ports' must be a list of strings", str(ctx.exception))
def test_ephemeral_auth_stealth(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) with self.assertRaises(ValueError) as ctx: yield EphemeralAuthenticatedOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], auth=AuthStealth(["steve", "carol"]), ) self.assertIn( "Tor does not yet support", str(ctx.exception), )
def test_ephemeral_extra_kwargs(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) with self.assertRaises(ValueError) as ctx: EphemeralOnionService( config, ports=["80 127.0.0.1:80"], ver=2, something_funny="foo", ) self.assertIn( "Unknown kwarg", str(ctx.exception), )
def test_ephemeral_ports_bad0(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) with self.assertRaises(ValueError) as ctx: yield EphemeralAuthenticatedOnionService.create( Mock(), config, ports="80 127.0.0.1:80", auth=AuthBasic(["xavier"]), ) self.assertIn( "'ports' must be a list of strings", str(ctx.exception), )
def test_ephemeral_auth_unknown(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) with self.assertRaises(ValueError) as ctx: yield EphemeralAuthenticatedOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], auth=["carol", "steve"], ) self.assertIn( "'auth' should be an AuthBasic or AuthStealth instance", str(ctx.exception), )
def test_ephemeral_v3_no_key(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) # returns a Deferred we're ignoring EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], detach=True, version=3, ) cmd, d = protocol.commands[0] self.assertEqual(u"ADD_ONION NEW:ED25519-V3 Port=80,127.0.0.1:80 Flags=Detach", cmd) d.callback("PrivateKey={}\nServiceID={}".format(_test_private_key_blob, _test_onion_id))
def test_happened_already(self): proto = FakeControlProtocol([]) events = [] def event_cb(*args, **kw): events.append((args, kw)) proto.event_happened("something", "arg") proto.add_event_listener("something", event_cb) self.assertEqual([(("arg", ), {})], events)
def test_ephemeral_v3_wrong_key_type(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) privkey = 'RSA1024:{}'.format('a' * 32) with self.assertRaises(ValueError) as ctx: yield EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], detach=True, version=3, private_key=privkey, ) self.assertIn( "but private key isn't", str(ctx.exception), )
def test_ephemeral_v3_non_anonymous(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) # returns a Deferred we're ignoring EphemeralOnionService.create( Mock(), config, ports=[(80, "192.168.1.2:80")], version=3, detach=True, single_hop=True, ) cmd, d = protocol.commands[0] self.assertEqual( u"ADD_ONION NEW:ED25519-V3 Port=80,192.168.1.2:80 Flags=Detach,NonAnonymous", cmd) d.callback("PrivateKey={}\nServiceID={}".format( _test_private_key_blob, _test_onion_id))
def test_descriptor_all_uploads_fail(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) progress_messages = [] def progress(*args): progress_messages.append(args) eph_d = EphemeralOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], progress=progress, private_key=DISCARD, ) cmd, d = protocol.commands[0] self.assertEqual( u"ADD_ONION NEW:BEST Port=80,127.0.0.1:80 Flags=DiscardPK", cmd) d.callback("PrivateKey={}\nServiceID={}".format( _test_private_key_blob, _test_onion_id)) # get the event-listener callback that torconfig code added cb = protocol.events['HS_DESC'] for x in range(6): cb('UPLOAD {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) for x in range(6): cb('FAILED {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) # now when we wait for our onion, it should already be failed # because all 6 uploads failed. with self.assertRaises(RuntimeError) as ctx: yield eph_d self.assertIn("Failed to upload", str(ctx.exception)) for x in range(6): self.assertIn("hsdir_{}".format(x), str(ctx.exception))
def test_dir_ioerror(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) hsdir = self.mktemp() os.mkdir(hsdir) with open(join(hsdir, "hostname"), "w") as f: f.write("{}.onion".format(_test_onion_id)) hs_d = FilesystemOnionService.create( Mock(), config, hsdir=hsdir, ports=["80 127.0.0.1:4321"], ) # arrange HS_DESC callbacks so we get the hs instance back cb = protocol.events['HS_DESC'] cb('UPLOAD {} UNKNOWN hsdir0'.format(_test_onion_id)) cb('UPLOADED {} UNKNOWN hsdir0'.format(_test_onion_id)) hs = yield hs_d self.assertIs(None, hs.private_key)
def test_ephemeral_auth_basic_remove_fails(self): protocol = FakeControlProtocol([]) config = TorConfig(protocol) eph_d = EphemeralAuthenticatedOnionService.create( Mock(), config, ports=["80 127.0.0.1:80"], auth=AuthBasic([ "steve", ("carol", "c4r0ls33kr1t"), ]), ) cmd, d = protocol.commands[0] self.assertTrue( cmd.startswith( u"ADD_ONION NEW:BEST Port=80,127.0.0.1:80 Flags=BasicAuth " ) ) self.assertIn(u"ClientAuth=steve", cmd) self.assertIn(u"ClientAuth=carol:c4r0ls33kr1t", cmd) d.callback( "PrivateKey={}\nServiceID={}\nClientAuth=steve:aseekritofsomekind".format( _test_private_key_blob, _test_onion_id, ) ) cb = protocol.events['HS_DESC'] for x in range(6): cb('UPLOAD {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) for x in range(6): cb('UPLOADED {} UNKNOWN hsdir_{}'.format(_test_onion_id, x)) hs = yield eph_d self.assertEqual( set(["steve", "carol"]), set(hs.client_names()), ) steve = hs.get_client("steve") self.assertEqual( "aseekritofsomekind", steve.auth_token, ) self.assertEqual( "{}.onion".format(_test_onion_id), steve.hostname, ) self.assertEqual( set(["80 127.0.0.1:80"]), steve.ports, ) self.assertTrue(steve.parent is hs) self.assertEqual("steve", steve.name) self.assertEqual(2, steve.version) carol = hs.get_client("carol") self.assertEqual( "c4r0ls33kr1t", carol.auth_token, ) self.assertEqual( "{}.onion".format(_test_onion_id), carol.hostname, ) remove_d = hs.remove() cmd, d = protocol.commands[-1] self.assertEqual(u"DEL_ONION {}".format(_test_onion_id), cmd) d.callback('not okay') with self.assertRaises(RuntimeError): yield remove_d