webish: localfile=/localdir= are now disabled by default, a special switch is required to enable them

This commit is contained in:
Brian Warner 2007-08-10 18:21:22 -07:00
parent b4a0effe30
commit 2f5a27316f
3 changed files with 98 additions and 8 deletions

View File

@ -26,6 +26,7 @@ class Client(node.Node, Referenceable):
STOREDIR = 'storage'
NODETYPE = "client"
WEBPORTFILE = "webport"
WEB_ALLOW_LOCAL_ACCESS_FILE = "webport_allow_localfile"
INTRODUCER_FURL_FILE = "introducer.furl"
MY_FURL_FILE = "myself.furl"
SUICIDE_PREVENTION_HOTLINE_FILE = "suicide_prevention_hotline"
@ -49,7 +50,12 @@ class Client(node.Node, Referenceable):
f = open(WEBPORTFILE, "r")
webport = f.read().strip() # strports string
f.close()
self.add_service(WebishServer(webport))
ws = WebishServer(webport)
local_access_file = os.path.join(self.basedir,
self.WEB_ALLOW_LOCAL_ACCESS_FILE)
if os.path.exists(local_access_file):
ws.allow_local_access(True)
self.add_service(ws)
INTRODUCER_FURL_FILE = os.path.join(self.basedir,
self.INTRODUCER_FURL_FILE)

View File

@ -158,7 +158,8 @@ class WebMixin(object):
def setUp(self):
self.s = MyClient()
self.s.startService()
s = webish.WebishServer("0")
self.ws = s = webish.WebishServer("0")
s.allow_local_access(True)
s.setServiceParent(self.s)
port = s.listener._port.getHost().port
self.webish_url = "http://localhost:%d" % port
@ -461,11 +462,15 @@ class Web(WebMixin, unittest.TestCase):
d.addBoth(self.should404, "test_GET_FILEURL_json_missing")
return d
def disable_local_access(self, res=None):
self.ws.allow_local_access(False)
return res
def test_GET_FILEURL_localfile(self):
localfile = os.path.abspath("web/GET_FILEURL_localfile")
url = "/vdrive/global/foo/bar.txt?t=download&localfile=%s" % localfile
fileutil.make_dirs("web")
d = self.GET("/vdrive/global/foo/bar.txt?t=download&localfile=%s"
% localfile)
d = self.GET(url)
def _done(res):
self.failUnless(os.path.exists(localfile))
data = open(localfile, "rb").read()
@ -473,6 +478,17 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(_done)
return d
def test_GET_FILEURL_localfile_disabled(self):
localfile = os.path.abspath("web/GET_FILEURL_localfile_disabled")
url = "/vdrive/global/foo/bar.txt?t=download&localfile=%s" % localfile
fileutil.make_dirs("web")
self.disable_local_access()
d = self.GET(url)
d.addBoth(self.shouldFail, error.Error, "localfile disabled",
"403 Forbidden",
"local file access is disabled")
return d
def test_GET_FILEURL_localfile_nonlocal(self):
# TODO: somehow pretend that we aren't local, and verify that the
# server refuses to write to local files, probably by changing the
@ -510,12 +526,12 @@ class Web(WebMixin, unittest.TestCase):
def test_PUT_NEWFILEURL_localfile(self):
localfile = os.path.abspath("web/PUT_NEWFILEURL_localfile")
url = "/vdrive/global/foo/new.txt?t=upload&localfile=%s" % localfile
fileutil.make_dirs("web")
f = open(localfile, "wb")
f.write(self.NEWFILE_CONTENTS)
f.close()
d = self.PUT("/vdrive/global/foo/new.txt?t=upload&localfile=%s" %
localfile, "")
d = self.PUT(url, "")
def _check(res):
self.failUnless("new.txt" in self._foo_node.children)
new_uri = self._foo_node.children["new.txt"]
@ -525,6 +541,20 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(_check)
return d
def test_PUT_NEWFILEURL_localfile_disabled(self):
localfile = os.path.abspath("web/PUT_NEWFILEURL_localfile_disabled")
url = "/vdrive/global/foo/new.txt?t=upload&localfile=%s" % localfile
fileutil.make_dirs("web")
f = open(localfile, "wb")
f.write(self.NEWFILE_CONTENTS)
f.close()
self.disable_local_access()
d = self.PUT(url, "")
d.addBoth(self.shouldFail, error.Error, "put localfile disabled",
"403 Forbidden",
"local file access is disabled")
return d
def test_PUT_NEWFILEURL_localfile_mkdirs(self):
localfile = os.path.abspath("web/PUT_NEWFILEURL_localfile_mkdirs")
fileutil.make_dirs("web")
@ -715,6 +745,16 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(_check)
return d
def test_GET_DIRURL_localdir_disabled(self):
localdir = os.path.abspath("web/GET_DIRURL_localdir_disabled")
fileutil.make_dirs("web")
self.disable_local_access()
d = self.GET("/vdrive/global/foo?t=download&localdir=%s" % localdir)
d.addBoth(self.shouldFail, error.Error, "localfile disabled",
"403 Forbidden",
"local file access is disabled")
return d
def test_GET_DIRURL_localdir_nonabsolute(self):
localdir = "web/nonabsolute/dirpath"
fileutil.make_dirs("web/nonabsolute")
@ -778,6 +818,25 @@ class Web(WebMixin, unittest.TestCase):
d.addCallback(_check)
return d
def test_PUT_NEWDIRURL_localdir_disabled(self):
localdir = os.path.abspath("web/PUT_NEWDIRURL_localdir_disabled")
# create some files there
fileutil.make_dirs(os.path.join(localdir, "one"))
fileutil.make_dirs(os.path.join(localdir, "one/sub"))
fileutil.make_dirs(os.path.join(localdir, "two"))
fileutil.make_dirs(os.path.join(localdir, "three"))
self.touch(localdir, "three/foo.txt")
self.touch(localdir, "three/bar.txt")
self.touch(localdir, "zap.zip")
self.disable_local_access()
d = self.PUT("/vdrive/global/newdir?t=upload&localdir=%s"
% localdir, "")
d.addBoth(self.shouldFail, error.Error, "localfile disabled",
"403 Forbidden",
"local file access is disabled")
return d
def test_PUT_NEWDIRURL_localdir_mkdirs(self):
localdir = os.path.abspath("web/PUT_NEWDIRURL_localdir_mkdirs")
# create some files there

View File

@ -19,6 +19,9 @@ def getxmlfile(name):
class IClient(Interface):
pass
class ILocalAccess(Interface):
def allow_local_access():
pass
# we must override twisted.web.http.Request.requestReceived with a version
@ -347,7 +350,15 @@ class NeedAbsolutePathError:
req.setHeader("content-type", "text/plain")
return "localfile= or localdir= requires an absolute path"
class LocalAccessDisabledError:
implements(inevow.IResource)
def renderHTTP(self, ctx):
req = inevow.IRequest(ctx)
req.setResponseCode(http.FORBIDDEN)
req.setHeader("content-type", "text/plain")
return "local file access is disabled"
class LocalFileDownloader(resource.Resource):
def __init__(self, filenode, local_filename):
@ -832,6 +843,8 @@ class VDrive(rend.Page):
if localdir != os.path.abspath(localdir):
return NeedAbsolutePathError(), ()
if localfile or localdir:
if not ILocalAccess(ctx).allow_local_access():
return LocalAccessDisabledError(), ()
if req.getHost().host != LOCALHOST:
return NeedLocalhostError(), ()
# TODO: think about clobbering/revealing config files and node secrets
@ -1032,18 +1045,30 @@ class Root(rend.Page):
return T.div[form]
class LocalAccess:
implements(ILocalAccess)
def __init__(self):
self.local_access = False
def allow_local_access(self):
return self.local_access
class WebishServer(service.MultiService):
name = "webish"
def __init__(self, webport):
def __init__(self, webport, local_access=False):
service.MultiService.__init__(self)
self.root = Root()
self.site = site = appserver.NevowSite(self.root)
self.site.requestFactory = MyRequest
self.allow_local = LocalAccess()
self.site.remember(self.allow_local, ILocalAccess)
s = strports.service(webport, site)
s.setServiceParent(self)
self.listener = s # stash it so the tests can query for the portnum
def allow_local_access(self, enable=True):
self.allow_local.local_access = enable
def startService(self):
service.MultiService.startService(self)
# to make various services available to render_* methods, we stash a