[Pkg-privacy-commits] [txtorcon] 31/96: HiddenServiceDirGroupReadable support
Jérémy Bobbio
lunar at moszumanska.debian.org
Sun Sep 6 18:33:36 UTC 2015
This is an automated email from the git hooks/post-receive script.
lunar pushed a commit to branch master
in repository txtorcon.
commit 94b0e30aec8e37ecf80e9bf740efb22e9d23eedc
Author: meejah <meejah at meejah.ca>
Date: Sat Jan 17 01:10:56 2015 -0700
HiddenServiceDirGroupReadable support
---
test/test_torconfig.py | 60 ++++++++++++++++++++++++---------------
txtorcon/endpoints.py | 6 ++--
txtorcon/stream.py | 7 ++---
txtorcon/torconfig.py | 76 ++++++++++++++++++++++++++++----------------------
4 files changed, 86 insertions(+), 63 deletions(-)
diff --git a/test/test_torconfig.py b/test/test_torconfig.py
index be4c294..4d7bae3 100644
--- a/test/test_torconfig.py
+++ b/test/test_torconfig.py
@@ -3,6 +3,7 @@ import shutil
import tempfile
import functools
from getpass import getuser
+from mock import patch
from StringIO import StringIO
from mock import Mock, patch
@@ -267,12 +268,13 @@ class ConfigTests(unittest.TestCase):
conf.save()
def test_get_type(self):
- self.protocol.answers.append('config/names=\nSomethingExciting CommaList')
+ self.protocol.answers.append('config/names=\nSomethingExciting CommaList\nHiddenServices Dependant')
self.protocol.answers.append({'SomethingExciting': 'a,b'})
conf = TorConfig(self.protocol)
- from txtorcon.torconfig import CommaList
+ from txtorcon.torconfig import CommaList, HiddenService
self.assertEqual(conf.get_type('SomethingExciting'), CommaList)
+ self.assertEqual(conf.get_type('HiddenServices'), HiddenService)
def foo(self, *args):
print "FOOO", args
@@ -531,7 +533,7 @@ class CreateTorrcTests(unittest.TestCase):
config = TorConfig()
config.SocksPort = 1234
config.hiddenservices = [HiddenService(config, '/some/dir', '80 127.0.0.1:1234',
- 'auth', 2)]
+ 'auth', 2, True)]
config.Log = ['80 127.0.0.1:80', '90 127.0.0.1:90']
config.save()
torrc = config.create_torrc()
@@ -554,30 +556,36 @@ class HiddenServiceTests(unittest.TestCase):
self.protocol.answers.append('''config/names=
HiddenServiceOptions Virtual
HiddenServiceVersion Dependant
+HiddenServiceDirGroupReadable Dependant
HiddenServiceAuthorizeClient Dependant''')
+ @defer.inlineCallbacks
def test_options_hidden(self):
- self.protocol.answers.append('HiddenServiceDir=/fake/path\nHiddenServicePort=80 127.0.0.1:1234\n')
+ self.protocol.answers.append('HiddenServiceDir=/fake/path\nHiddenServicePort=80 127.0.0.1:1234\nHiddenServiceDirGroupReadable=1\n')
conf = TorConfig(self.protocol)
+ yield conf.post_bootstrap
+ self.assertTrue(conf.post_bootstrap.called)
self.assertTrue('HiddenServiceOptions' not in conf.config)
+ self.assertTrue('HiddenServices' in conf.config)
self.assertEqual(len(conf.HiddenServices), 1)
self.assertTrue(not conf.needs_save())
- conf.hiddenservices.append(HiddenService(conf, '/some/dir', '80 127.0.0.1:2345', 'auth', 2))
+ conf.hiddenservices.append(HiddenService(conf, '/some/dir', '80 127.0.0.1:2345', 'auth', 2, True))
conf.hiddenservices[0].ports.append('443 127.0.0.1:443')
self.assertTrue(conf.needs_save())
conf.save()
- self.assertEqual(conf.get_type('HiddenServices'), HiddenService)
- self.assertEqual(len(self.protocol.sets), 7)
+ self.assertEqual(len(self.protocol.sets), 9)
self.assertEqual(self.protocol.sets[0], ('HiddenServiceDir', '/fake/path'))
- self.assertEqual(self.protocol.sets[1], ('HiddenServicePort', '80 127.0.0.1:1234'))
- self.assertEqual(self.protocol.sets[2], ('HiddenServicePort', '443 127.0.0.1:443'))
- self.assertEqual(self.protocol.sets[3], ('HiddenServiceDir', '/some/dir'))
- self.assertEqual(self.protocol.sets[4], ('HiddenServicePort', '80 127.0.0.1:2345'))
- self.assertEqual(self.protocol.sets[5], ('HiddenServiceVersion', '2'))
- self.assertEqual(self.protocol.sets[6], ('HiddenServiceAuthorizeClient', 'auth'))
+ self.assertEqual(self.protocol.sets[1], ('HiddenServiceDirGroupReadable', '1'))
+ self.assertEqual(self.protocol.sets[2], ('HiddenServicePort', '80 127.0.0.1:1234'))
+ self.assertEqual(self.protocol.sets[3], ('HiddenServicePort', '443 127.0.0.1:443'))
+ self.assertEqual(self.protocol.sets[4], ('HiddenServiceDir', '/some/dir'))
+ self.assertEqual(self.protocol.sets[5], ('HiddenServiceDirGroupReadable', '1'))
+ self.assertEqual(self.protocol.sets[6], ('HiddenServicePort', '80 127.0.0.1:2345'))
+ self.assertEqual(self.protocol.sets[7], ('HiddenServiceVersion', '2'))
+ self.assertEqual(self.protocol.sets[8], ('HiddenServiceAuthorizeClient', 'auth'))
def test_save_no_protocol(self):
conf = TorConfig()
@@ -592,6 +600,7 @@ HiddenServiceAuthorizeClient Dependant''')
self.assertEqual(2, len(conf.HiddenServices))
def test_onion_keys(self):
+ # FIXME test without crapping on filesystem
self.protocol.answers.append('HiddenServiceDir=/fake/path\n')
d = tempfile.mkdtemp()
@@ -629,11 +638,14 @@ HiddenServiceAuthorizeClient Dependant''')
conf = TorConfig()
h0 = HiddenService(conf, '/fake/path', ['80 127.0.0.1:1234'], '', 3)
h1 = HiddenService(conf, '/fake/path', ['90 127.0.0.1:4321'], '', 3)
- conf.hiddenservices.append(h0)
+ h2 = HiddenService(conf, '/fake/path', ['90 127.0.0.1:5432'], '', 3, True)
+ conf.hiddenservices = [h0]
conf.hiddenservices.append(h1)
- self.assertEqual(len(conf.hiddenservices), 2)
+ conf.hiddenservices.append(h2)
+ self.assertEqual(len(conf.hiddenservices), 3)
self.assertEqual(h0, conf.hiddenservices[0])
self.assertEqual(h1, conf.hiddenservices[1])
+ self.assertEqual(h2, conf.hiddenservices[2])
self.assertTrue(conf.needs_save())
def test_multiple_startup_services(self):
@@ -707,7 +719,6 @@ HiddenServicePort=90 127.0.0.1:2345''')
conf.hiddenservices[0].ports.append('90 127.0.0.1:2345')
self.assertTrue(conf.needs_save())
-
class FakeReactor(task.Clock):
implements(IReactorCore)
@@ -882,13 +893,18 @@ class LaunchTorTests(unittest.TestCase):
return self.assertRaises(RuntimeError,
launch_tor, config, None, timeout=5, tor_binary='/bin/echo')
- def test_launch_root_changes_tmpdir_ownership(self):
+ @patch('txtorcon.torconfig.sys')
+ @patch('txtorcon.torconfig.pwd')
+ @patch('txtorcon.torconfig.os.geteuid')
+ @patch('txtorcon.torconfig.os.chown')
+ def test_launch_root_changes_tmpdir_ownership(self, chown, euid, _pwd, _sys):
+ _pwd.return_value = 1000
+ _sys.platform = 'linux2'
+ euid.return_value = 0
config = TorConfig()
- try:
- launch_tor(config, None, timeout=5, tor_binary='/bin/echo')
- self.fail("Should have thrown an error")
- except RuntimeError:
- pass
+ config.User = 'chuffington'
+ d = launch_tor(config, Mock(), tor_binary='/bin/echo')
+ self.assertEqual(1, chown.call_count)
@defer.inlineCallbacks
def test_launch_timeout_exception(self):
diff --git a/txtorcon/endpoints.py b/txtorcon/endpoints.py
index bcae171..ef3c93c 100644
--- a/txtorcon/endpoints.py
+++ b/txtorcon/endpoints.py
@@ -169,7 +169,6 @@ class TCPHiddenServiceEndpoint(object):
"""
This returns a TCPHiddenServiceEndpoint connected to the
endpoint you specify in `control_endpoint`. After connecting, a
-
single hidden service is added. The endpoint can be a Unix
socket if Tor's `ControlSocket` option was used (instead of
`ControlPort`).
@@ -177,7 +176,7 @@ class TCPHiddenServiceEndpoint(object):
.. note::
If Tor bug #11291 is not yet fixed, this won't work if you
- only have Group access.
+ only have Group access. XXX FIXME re-test
"""
@defer.inlineCallbacks
@@ -333,8 +332,7 @@ class TCPHiddenServiceEndpoint(object):
@defer.inlineCallbacks
def listen(self, protocolfactory):
- """
- Implement :api:`twisted.internet.interfaces.IStreamServerEndpoint
+ """Implement :api:`twisted.internet.interfaces.IStreamServerEndpoint
<IStreamServerEndpoint>`.
Returns a Deferred that delivers an
diff --git a/txtorcon/stream.py b/txtorcon/stream.py
index ea3ab85..3cc8ec5 100644
--- a/txtorcon/stream.py
+++ b/txtorcon/stream.py
@@ -228,10 +228,9 @@ class Stream(object):
else:
raise RuntimeError("Unknown state: %s" % self.state)
- ## see if we attached to a circuit. I believe this only
- ## happens on a SENTCONNECT or REMAP. DETACHED is excluded so
- ## we don't immediately re-add the circuit we just detached
- ## from
+ # see if we attached to a circuit. I believe this only happens
+ # on a SENTCONNECT or REMAP. DETACHED is excluded so we don't
+ # immediately re-add the circuit we just detached from
if self.state not in ['CLOSED', 'FAILED', 'DETACHED']:
cid = int(args[2])
if cid == 0:
diff --git a/txtorcon/torconfig.py b/txtorcon/torconfig.py
index 577446f..b715383 100644
--- a/txtorcon/torconfig.py
+++ b/txtorcon/torconfig.py
@@ -130,12 +130,12 @@ class TorProcessProtocol(protocol.ProcessProtocol):
if self.stdout:
self.stdout.write(data)
- ## minor hack: we can't try this in connectionMade because
- ## that's when the process first starts up so Tor hasn't
- ## opened any ports properly yet. So, we presume that after
- ## its first output we're good-to-go. If this fails, we'll
- ## reset and try again at the next output (see this class'
- ## tor_connection_failed)
+ # minor hack: we can't try this in connectionMade because
+ # that's when the process first starts up so Tor hasn't
+ # opened any ports properly yet. So, we presume that after
+ # its first output we're good-to-go. If this fails, we'll
+ # reset and try again at the next output (see this class'
+ # tor_connection_failed)
txtorlog.msg(data)
if not self.attempted_connect and self.connection_creator \
@@ -174,7 +174,7 @@ class TorProcessProtocol(protocol.ProcessProtocol):
Clean up my temporary files.
"""
- [delete_file_or_tree(f) for f in self.to_delete]
+ all([delete_file_or_tree(f) for f in self.to_delete])
self.to_delete = []
def processEnded(self, status):
@@ -215,10 +215,10 @@ class TorProcessProtocol(protocol.ProcessProtocol):
## the below are all callbacks
def tor_connection_failed(self, failure):
- ## FIXME more robust error-handling please, like a timeout so
- ## we don't just wait forever after 100% bootstrapped (that
- ## is, we're ignoring these errors, but shouldn't do so after
- ## we'll stop trying)
+ # FIXME more robust error-handling please, like a timeout so
+ # we don't just wait forever after 100% bootstrapped (that
+ # is, we're ignoring these errors, but shouldn't do so after
+ # we'll stop trying)
self.attempted_connect = False
def status_client(self, arg):
@@ -666,12 +666,13 @@ class HiddenService(object):
self.dir = thedir
self.version = ver
self.authorize_client = auth
+ self.group_readable = group_readable
- ## there are two magic attributes, "hostname" and "private_key"
- ## these are gotten from the dir if they're still None when
- ## accessed. Note that after a SETCONF has returned '250 OK'
- ## it seems from tor code that the keys will always have been
- ## created on disk by that point
+ # there are two magic attributes, "hostname" and "private_key"
+ # these are gotten from the dir if they're still None when
+ # accessed. Note that after a SETCONF has returned '250 OK'
+ # it seems from tor code that the keys will always have been
+ # created on disk by that point
if not isinstance(ports, types.ListType):
ports = [ports]
@@ -703,13 +704,15 @@ class HiddenService(object):
Helper method used by TorConfig when generating a torrc file.
"""
- rtn = [('HiddenServiceDir', self.dir)]
+ rtn = [('HiddenServiceDir', str(self.dir))]
+ if self.conf._supports['HiddenServiceDirGroupReadable'] and self.group_readable:
+ rtn.append(('HiddenServiceDirGroupReadable', str(1)))
for x in self.ports:
- rtn.append(('HiddenServicePort', x))
+ rtn.append(('HiddenServicePort', str(x)))
if self.version:
- rtn.append(('HiddenServiceVersion', self.version))
+ rtn.append(('HiddenServiceVersion', str(self.version)))
if self.authorize_client:
- rtn.append(('HiddenServiceAuthorizeClient', self.authorize_client))
+ rtn.append(('HiddenServiceAuthorizeClient', str(self.authorize_client)))
return rtn
@@ -783,6 +786,14 @@ class TorConfig(object):
self.list_parsers = set(['hiddenservices'])
'''All the names (keys from .parsers) that are a List of something.'''
+ # during bootstrapping we decide whether we support the
+ # following features. A thing goes in here if TorConfig
+ # behaves differently depending upon whether it shows up in
+ # "GETINFO config/names"
+ self._supports = dict(
+ HiddenServiceDirGroupReadable=False
+ )
+
self.post_bootstrap = defer.Deferred()
if self.protocol:
if self.protocol.post_bootstrap:
@@ -977,17 +988,9 @@ class TorConfig(object):
if key == 'HiddenServices':
self.config['HiddenServices'] = value
for hs in value:
- args.append('HiddenServiceDir')
- args.append(hs.dir)
- for p in hs.ports:
- args.append('HiddenServicePort')
- args.append(str(p))
- if hs.version:
- args.append('HiddenServiceVersion')
- args.append(str(hs.version))
- if hs.authorize_client:
- args.append('HiddenServiceAuthorizeClient')
- args.append(hs.authorize_client)
+ for (k, v) in hs.config_attributes():
+ args.append(k)
+ args.append(v)
continue
if isinstance(value, types.ListType):
@@ -1033,6 +1036,9 @@ class TorConfig(object):
continue
(name, value) = line.split()
+ if name in self._supports:
+ self._supports[name] = True
+
if name == 'HiddenServiceOptions':
## set up the "special-case" hidden service stuff
servicelines = yield self.protocol.get_conf_raw(
@@ -1087,11 +1093,12 @@ class TorConfig(object):
k, v = line.split('=')
if k == 'HiddenServiceDir':
if directory is not None:
- hs.append(HiddenService(self, directory, ports, auth, ver))
+ hs.append(HiddenService(self, directory, ports, auth, ver, group_read))
directory = v
ports = []
ver = None
auth = None
+ group_read = 0
elif k == 'HiddenServicePort':
ports.append(v)
@@ -1102,11 +1109,14 @@ class TorConfig(object):
elif k == 'HiddenServiceAuthorizeClient':
auth = v
+ elif k == 'HiddenServiceDirGroupReadable':
+ group_read = int(v)
+
else:
raise RuntimeError("Can't parse HiddenServiceOptions: " + k)
if directory is not None:
- hs.append(HiddenService(self, directory, ports, auth, ver))
+ hs.append(HiddenService(self, directory, ports, auth, ver, group_read))
name = 'HiddenServices'
self.config[name] = _ListWrapper(
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/txtorcon.git
More information about the Pkg-privacy-commits
mailing list