]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
webish: localfile=/localdir= are now disabled by default, a special switch is require...
authorBrian Warner <warner@lothar.com>
Sat, 11 Aug 2007 01:21:22 +0000 (18:21 -0700)
committerBrian Warner <warner@lothar.com>
Sat, 11 Aug 2007 01:21:22 +0000 (18:21 -0700)
src/allmydata/client.py
src/allmydata/test/test_web.py
src/allmydata/webish.py

index 8f31a9bba2aa48dfa3a7ce4d48ac68decbca358a..949e6dc7b19db81a3bd92641ca2911f6fcb6633a 100644 (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)
index 3e58cf3e3307a60849a58b0625a646fdbf197f6a..add61e56bd61828f8a376552081e57b8861a1307 100644 (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
index 62a973b52ba95c1c63340bd1a6e09069bc5f95fb..c4aafc5531bf760e526e5e419f655d27ef794853 100644 (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