[Pkg-privacy-commits] [txtorcon] 69/96: Properly treat HiddenServiceAuthorizeClient as a list

Jérémy Bobbio lunar at moszumanska.debian.org
Sun Sep 6 18:33:41 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 7429cd08331a45b1ff9c776dd0f77463dd51bdeb
Author: meejah <meejah at meejah.ca>
Date:   Fri Feb 13 00:30:10 2015 -0700

    Properly treat HiddenServiceAuthorizeClient as a list
    
    Also parses client_keys into HiddenService properly (available
    as .client_keys)
---
 test/test_torconfig.py |  21 ++++++++--
 txtorcon/torconfig.py  | 106 +++++++++++++++++++++++++++----------------------
 2 files changed, 77 insertions(+), 50 deletions(-)

diff --git a/test/test_torconfig.py b/test/test_torconfig.py
index 595d50c..ab9c34e 100644
--- a/test/test_torconfig.py
+++ b/test/test_torconfig.py
@@ -35,6 +35,7 @@ from txtorcon import torconfig
 from txtorcon.torconfig import TorProcessProtocol
 
 from txtorcon.util import delete_file_or_tree
+from txtorcon.torconfig import parse_client_keys
 
 
 class FakeControlProtocol:
@@ -692,12 +693,18 @@ HiddenServiceAuthorizeClient Dependant''')
                 f.write('public')
             with open(os.path.join(d, 'private_key'), 'w') as f:
                 f.write('private')
+            with open(os.path.join(d, 'client_keys'), 'w') as f:
+                f.write('client-name hungry\ndescriptor-cookie omnomnom\n')
 
             conf = TorConfig(self.protocol)
             hs = HiddenService(conf, d, [])
 
             self.assertEqual(hs.hostname, 'public')
             self.assertEqual(hs.private_key, 'private')
+            self.assertEqual(len(hs.client_keys), 1)
+            self.assertEqual(hs.client_keys[0].name, 'hungry')
+            self.assertEqual(hs.client_keys[0].cookie, 'omnomnom')
+            self.assertEqual(hs.client_keys[0].key, None)
 
         finally:
             shutil.rmtree(d, ignore_errors=True)
@@ -745,7 +752,8 @@ HiddenServicePort=90 127.0.0.1:2345''')
 
         self.assertEqual(conf.hiddenservices[0].dir, '/fake/path')
         self.assertEqual(conf.hiddenservices[0].version, 2)
-        self.assertEqual(conf.hiddenservices[0].authorize_client, 'basic')
+        self.assertEqual(len(conf.hiddenservices[0].authorize_client), 1)
+        self.assertEqual(conf.hiddenservices[0].authorize_client[0], 'basic')
         self.assertEqual(len(conf.hiddenservices[0].ports), 1)
         self.assertEqual(conf.hiddenservices[0].ports[0], '80 127.0.0.1:1234')
 
@@ -794,7 +802,7 @@ HiddenServicePort=90 127.0.0.1:2345''')
         self.assertEqual(len(conf.hiddenservices), 1)
         self.assertEqual(conf.hiddenservices[0].dir, '/fake/path')
         self.assertEqual(conf.hiddenservices[0].version, 3)
-        self.assertEqual(conf.hiddenservices[0].authorize_client, '')
+        self.assertEqual(0, len(conf.hiddenservices[0].authorize_client))
         conf.hiddenservices[0].ports = ['123 127.0.0.1:4321']
         conf.save()
 
@@ -1504,7 +1512,6 @@ class HiddenServiceAuthTests(unittest.TestCase):
 
     def test_parse_client_keys(self):
         data = StringIO(keydata)
-        from txtorcon.torconfig import parse_client_keys
 
         clients = list(parse_client_keys(data))
 
@@ -1520,3 +1527,11 @@ class HiddenServiceAuthTests(unittest.TestCase):
         self.assertEqual('quux', clients[2].name)
         self.assertEqual('asdlkjasdlfkjalsdkfffj==', clients[2].cookie)
         self.assertEqual(None, clients[2].key)
+
+    def test_parse_error(self):
+        data = StringIO('client-name foo\nclient-name xxx\n')
+
+        self.assertRaises(
+            RuntimeError,
+            parse_client_keys, data
+        )
diff --git a/txtorcon/torconfig.py b/txtorcon/torconfig.py
index b8d1f89..878f7b0 100644
--- a/txtorcon/torconfig.py
+++ b/txtorcon/torconfig.py
@@ -642,6 +642,23 @@ class _ListWrapper(list):
         return '_ListWrapper' + super(_ListWrapper, self).__repr__()
 
 
+class HiddenServiceClientAuth(object):
+    """
+    Encapsulates a single client-authorization, as parsed from a
+    HiddenServiceDir's "client_keys" file if you have stealth or basic
+    authentication turned on.
+
+    :param name: the name you gave it in the HiddenServiceAuthorizeClient line
+    :param cookie: random password
+    :param key: RSA private key, or None if this was basic auth
+    """
+
+    def __init__(self, name, cookie, key=None):
+        self.name = name
+        self.cookie = cookie
+        self.key = parse_rsa_blob(key) if key else None
+
+
 class HiddenService(object):
     """
     Because hidden service configuration is handled specially by Tor,
@@ -659,31 +676,47 @@ class HiddenService(object):
     """
 
     def __init__(self, config, thedir, ports,
-                 auth=None, ver=2, group_readable=0):
+                 auth=[], ver=2, group_readable=0):
         """
-        config is the TorConfig to which this will belong (FIXME,
-        can't we make this automatic somehow?), thedir corresponds to
-        'HiddenServiceDir' and will ultimately contain a 'hostname'
-        and 'private_key' file, ports is a list of lines corresponding
-        to HiddenServicePort (like '80 127.0.0.1:1234' to advertise a
-        hidden service at port 80 and redirect it internally on
-        127.0.0.1:1234). auth corresponds to
-        HiddenServiceAuthenticateClient line (FIXME: is that lines?)
-        and ver corresponds to HiddenServiceVersion and is always 2
-        right now.
+        config is the TorConfig to which this will belong, thedir
+        corresponds to 'HiddenServiceDir' and will ultimately contain
+        a 'hostname' and 'private_key' file, ports is a list of lines
+        corresponding to HiddenServicePort (like '80 127.0.0.1:1234'
+        to advertise a hidden service at port 80 and redirect it
+        internally on 127.0.0.1:1234). auth corresponds to the
+        HiddenServiceAuthenticateClient lines and can be either a
+        string or a list of strings (like 'basic client0,client1' or
+        'stealth client5,client6') and ver corresponds to
+        HiddenServiceVersion and is always 2 right now.
+
+        XXX FIXME can we avoid having to pass the config object
+        somehow? Like provide a factory-function on TorConfig for
+        users instead?
         """
 
         self.conf = config
         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
+        # HiddenServiceAuthorizeClient is a list
+        # in case people are passing '' for the auth
+        if not auth:
+            auth = []
+        elif not isinstance(auth, types.ListType):
+            auth = [auth]
+        self.authorize_client = _ListWrapper(
+            auth, functools.partial(
+                self.conf.mark_unsaved, 'HiddenServices'
+            )
+        )
+
+        # there are three magic attributes, "hostname" and
+        # "private_key" are gotten from the dir if they're still None
+        # when accessed. "client_keys" parses out any client
+        # authorizations. 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]
@@ -708,6 +741,13 @@ class HiddenService(object):
         if name in ('hostname', 'private_key'):
             with open(os.path.join(self.dir, name)) as f:
                 self.__dict__[name] = f.read().strip()
+        elif name == 'client_keys':
+            fname = os.path.join(self.dir, name)
+            keys = []
+            if os.path.exists(fname):
+                with open(fname) as f:
+                    keys = parse_client_keys(f)
+            self.__dict__[name] = keys
         return self.__dict__[name]
 
     def config_attributes(self):
@@ -728,38 +768,10 @@ class HiddenService(object):
         return rtn
 
 
-'''
-client-name bar
-descriptor-cookie O4rQyZ+IJr2PNHUdeXi0nA==
-client-key
------BEGIN RSA PRIVATE KEY-----
-MIICXQIBAAKBgQC1R/bPGTWnpGJpNCfT1KIfFq1QEGHz4enKSEKUDkz1CSEPOMGS
-bV37dfqTuI4klsFvdUsR3NpYXLin9xRWvw1viKwAN0y8cv5totl4qMxO5i+zcfVh
-oBqwzxFD0JVZVLlZjNYfSlkNnkDPmb7btcluzNETBP4IDo8rb2p2zCQc1wIDAQAB
-AoGAWhgg7n5N7zpAep6kKKAlzqObkQ4DUIz3f0P4atLMpn9aAdGoSpi2O7I/zcjM
-RBz0l+tIWuFTVtUGJNwkLJSZHP3FDkoZtOv1JDRD0cbnVClHQ6cOW7Asn/VhOiud
-0yTMkytN2wMpi/vpcQTs28yQdNi1486xPEx8/WEQH2azLJECQQDmkQ18+2gp0eBS
-AdW+9WPsd9RhwKKmDKCJ2TUMN+/4u1WLMx2pARuHqKKOvrWP7vlv7epEoKqWFajc
-3M4B4oupAkEAyUckoM4SOi1YNky9DqFUXrZ1Bl2UVVv15J0BB4jMnYFoSjirVn+i
-4cYHwOBPsvUdkW6OQWvn3gc69Dj5ht60fwJABPFlJaHKKONb+MYbS/28x6wF/JaB
-pietJWdnsLxeQ6nYeqR85UulyHHAEmlaQRyxcknadOAw6AjM1vdQ3095CQJBAKGG
-LzXAyc3YL887nAiOnTd4sscN+AjcSKNS/819Eb9gZ0IQ4icDPMJ0eiplmG/j1vur
-vgtwPd3m7X+p7U03kZ8CQQCHS0lciMezXoDVoi7uljnsFFbbB0HMNXKxcsxym1eQ
-bJiNvVv2EjfEyQaZfAy2PUfp/tAPYZMsyfps2DptWyNR
------END RSA PRIVATE KEY-----
-'''
-
 def parse_rsa_blob(lines):
     return ''.join(lines[1:-1])
 
 
-class HiddenServiceClientAuth(object):
-    def __init__(self, name, cookie, key=None):
-        self.name = name
-        self.cookie = cookie
-        self.key = parse_rsa_blob(key) if key else None
-
-
 def parse_client_keys(stream):
     '''
     This parses a hidden-service "client_keys" file, either stealth or
@@ -1232,7 +1244,7 @@ class TorConfig(object):
                 directory = v
                 ports = []
                 ver = None
-                auth = None
+                auth = []
                 group_read = 0
 
             elif k == 'HiddenServicePort':
@@ -1242,7 +1254,7 @@ class TorConfig(object):
                 ver = int(v)
 
             elif k == 'HiddenServiceAuthorizeClient':
-                auth = v
+                auth.append(v)
 
             elif k == 'HiddenServiceDirGroupReadable':
                 group_read = int(v)

-- 
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