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
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()
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)
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]
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']
import simplejson
+from twisted.web.server import UnsupportedMethod
+
from nevow import rend, url, tags as T
from nevow.inevow import IRequest
"""
def __init__(self, client):
- ##rend.Page.__init__(self, storage)
super(MagicFolderWebApi, self).__init__(client)
self.client = client
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)