]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/commitdiff
Add simple auth-token to get JSON data
authormeejah <meejah@meejah.ca>
Wed, 27 Jan 2016 06:49:23 +0000 (23:49 -0700)
committermeejah <meejah@meejah.ca>
Mon, 8 Feb 2016 17:12:32 +0000 (10:12 -0700)
src/allmydata/client.py
src/allmydata/scripts/magic_folder_cli.py
src/allmydata/web/magic_folder.py

index a919d9a1c8953ea88bb69663cd39f8526dbd29e3..12ebb148aa2672f0f9d988991110956b69a24969 100644 (file)
@@ -1,5 +1,6 @@
 import os, stat, time, weakref
 from allmydata import node
+from base64 import urlsafe_b64encode
 
 from zope.interface import implements
 from twisted.internet import reactor, defer
@@ -334,6 +335,9 @@ class Client(node.Node, pollmixin.PollMixin):
         DEP["n"] = int(self.get_config("client", "shares.total", DEP["n"]))
         DEP["happy"] = int(self.get_config("client", "shares.happy", DEP["happy"]))
 
+        # for the CLI to authenticate to local JSON endpoints
+        self._auth_token = self._create_or_read_auth_token()
+
         self.init_client_storage_broker()
         self.history = History(self.stats_provider)
         self.terminator = Terminator()
@@ -343,6 +347,33 @@ class Client(node.Node, pollmixin.PollMixin):
         self.init_blacklist()
         self.init_nodemaker()
 
+    def get_auth_token(self):
+        """
+        This returns a local authentication token, which is just some
+        random data in "api_auth_token" which must be echoed to API
+        calls.
+
+        Currently only the URI '/magic' for magic-folder status; other
+        endpoints are invited to include this as well, as appropriate.
+        """
+        return self._auth_token
+
+    def _create_or_read_auth_token(self):
+        """
+        This returns the current auth-token data, possibly creating it and
+        writing 'private/api_auth_token' in the process.
+        """
+        fname = os.path.join(self.basedir, 'private', 'api_auth_token')
+        try:
+            with open(fname, 'rb') as f:
+                data = f.read()
+        except (OSError, IOError):
+            log.msg("Creating '%s'." % (fname,))
+            with open(fname, 'wb') as f:
+                data = urlsafe_b64encode(os.urandom(32))
+                f.write(data)
+        return data
+
     def init_client_storage_broker(self):
         # create a StorageFarmBroker object, for use by Uploader/Downloader
         # (and everybody else who wants to use storage servers)
index 4c9a469beff980523c9e6e406a6af358cdc74a9f..dc26a36b4343abeebfedbf4b6187ae449bd269f9 100644 (file)
@@ -217,7 +217,7 @@ class StatusOptions(BasedirOptions):
             self['node-url'] = f.read().strip()
 
 
-def _get_json_for_fragment(options, fragment):
+def _get_json_for_fragment(options, fragment, method='GET'):
     nodeurl = options['node-url']
     if nodeurl.endswith('/'):
         nodeurl = nodeurl[:-1]
@@ -334,7 +334,13 @@ def status(options):
             nice_created = humanize.naturaltime(now - created)
             print "    %s (%s): %s, version=%s, created %s" % (n, nice_size, status, version, nice_created)
 
-    magicdata = _get_json_for_fragment(options, 'magic_folder?t=json')
+    with open(os.path.join(nodedir, u'private', u'api_auth_token'), 'rb') as f:
+        token = f.read()
+    magicdata = _get_json_for_fragment(
+        options,
+        'magic_folder?t=json&token=' + token,
+        method='POST',
+    )
     if len(magicdata):
         uploads = [item for item in magicdata if item['kind'] == 'upload']
         downloads = [item for item in magicdata if item['kind'] == 'download']
index 5d2f3e5ed9c7df6cd0627823d0509f3f886bcb7e..bf72cc39416b60fccf8bef35b191382071e1368c 100644 (file)
@@ -1,5 +1,7 @@
 import simplejson
 
+from twisted.web.server import UnsupportedMethod
+
 from nevow import rend, url, tags as T
 from nevow.inevow import IRequest
 
@@ -12,7 +14,6 @@ class MagicFolderWebApi(rend.Page):
     """
 
     def __init__(self, client):
-        ##rend.Page.__init__(self, storage)
         super(MagicFolderWebApi, self).__init__(client)
         self.client = client
 
@@ -47,6 +48,13 @@ class MagicFolderWebApi(rend.Page):
     def renderHTTP(self, ctx):
         req = IRequest(ctx)
         t = get_arg(req, "t", None)
+        if req.method != 'POST':
+            raise UnsupportedMethod(('POST',))
+
+        token = get_arg(req, "token", None)
+        # XXX need constant-time comparison?
+        if token is None or token != self.client.get_auth_token():
+            raise WebError("Missing or invalid token.", 400)
 
         if t is None:
             return rend.Page.renderHTTP(self, ctx)