Error if a .furl config entry contains an unescaped '#'. fixes #2128

Author: Andrew Miller <amiller@dappervision.com>
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
This commit is contained in:
Daira Hopwood 2014-05-05 22:55:50 +01:00
parent c85060c436
commit 883dd9795b
3 changed files with 59 additions and 2 deletions

View File

@ -55,6 +55,11 @@ class OldConfigError(Exception):
class OldConfigOptionError(Exception): class OldConfigOptionError(Exception):
pass pass
class UnescapedHashError(Exception):
def __str__(self):
return ("The configuration entry %s contained an unescaped '#' character."
% quote_output(self.args[0]))
class Node(service.MultiService): class Node(service.MultiService):
# this implements common functionality of both Client nodes and Introducer # this implements common functionality of both Client nodes and Introducer
@ -101,11 +106,27 @@ class Node(service.MultiService):
test_name = tempfile.mktemp() test_name = tempfile.mktemp()
_assert(os.path.dirname(test_name) == tempdir, test_name, tempdir) _assert(os.path.dirname(test_name) == tempdir, test_name, tempdir)
@staticmethod
def _contains_unescaped_hash(item):
characters = iter(item)
for c in characters:
if c == '\\':
characters.next()
elif c == '#':
return True
return False
def get_config(self, section, option, default=_None, boolean=False): def get_config(self, section, option, default=_None, boolean=False):
try: try:
if boolean: if boolean:
return self.config.getboolean(section, option) return self.config.getboolean(section, option)
return self.config.get(section, option)
item = self.config.get(section, option)
if option.endswith(".furl") and self._contains_unescaped_hash(item):
raise UnescapedHashError(item)
return item
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
if default is _None: if default is _None:
fn = os.path.join(self.basedir, u"tahoe.cfg") fn = os.path.join(self.basedir, u"tahoe.cfg")

View File

@ -3,7 +3,7 @@ from twisted.trial import unittest
from twisted.application import service from twisted.application import service
import allmydata import allmydata
from allmydata.node import OldConfigError, OldConfigOptionError, MissingConfigEntry from allmydata.node import Node, OldConfigError, OldConfigOptionError, MissingConfigEntry, UnescapedHashError
from allmydata import client from allmydata import client
from allmydata.storage_client import StorageFarmBroker from allmydata.storage_client import StorageFarmBroker
from allmydata.util import base32, fileutil from allmydata.util import base32, fileutil
@ -30,6 +30,31 @@ class Basic(testutil.ReallyEqualMixin, unittest.TestCase):
BASECONFIG) BASECONFIG)
client.Client(basedir) client.Client(basedir)
def test_comment(self):
dummy = "pb://wl74cyahejagspqgy4x5ukrvfnevlknt@127.0.0.1:58889/bogus"
should_fail = [r"test#test", r"#testtest", r"test\\#test"]
should_not_fail = [r"test\#test", r"test\\\#test", r"testtest"]
basedir = "test_client.Basic.test_comment"
os.mkdir(basedir)
def write_config(shouldfail, s):
config = ("[client]\n"
"introducer.furl = %s\n" % s)
fileutil.write(os.path.join(basedir, "tahoe.cfg"), config)
for s in should_fail:
self.failUnless(Node._contains_unescaped_hash(s))
write_config(s)
self.failUnlessRaises(UnescapedHashError, client.Client, basedir)
for s in should_not_fail:
self.failIf(Node._contains_unescaped_hash(s))
write_config(s)
client.Client(basedir)
@mock.patch('twisted.python.log.msg') @mock.patch('twisted.python.log.msg')
def test_error_on_old_config_files(self, mock_log_msg): def test_error_on_old_config_files(self, mock_log_msg):
basedir = "test_client.Basic.test_error_on_old_config_files" basedir = "test_client.Basic.test_error_on_old_config_files"

View File

@ -87,6 +87,17 @@ class TestCase(testutil.SignalMixin, unittest.TestCase):
u"\u2621")) u"\u2621"))
return d return d
def test_tahoe_cfg_hash_in_name(self):
basedir = "test_node/test_cfg_hash_in_name"
nickname = "Hash#Bang!" # a clever nickname containing a hash
fileutil.make_dirs(basedir)
f = open(os.path.join(basedir, 'tahoe.cfg'), 'wt')
f.write("[node]\n")
f.write("nickname = %s\n" % (nickname,))
f.close()
n = TestNode(basedir)
self.failUnless(n.nickname == nickname)
def test_private_config(self): def test_private_config(self):
basedir = "test_node/test_private_config" basedir = "test_node/test_private_config"
privdir = os.path.join(basedir, "private") privdir = os.path.join(basedir, "private")