Mercurial > templog
diff web/templog.py @ 293:d15dda1b1f76
merge
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 06 Jul 2019 18:29:45 +0800 |
parents | f7261dd970da |
children | 6bacd8ca9f8f |
line wrap: on
line diff
--- a/web/templog.py Thu Mar 19 21:50:52 2015 +0800 +++ b/web/templog.py Sat Jul 06 18:29:45 2019 +0800 @@ -11,6 +11,7 @@ import os import traceback import fcntl +import hashlib import bottle from bottle import route, request, response @@ -23,12 +24,22 @@ DATE_FORMAT = '%Y%m%d-%H.%M' ZOOM_SCALE = 2.0 +class TemplogBottle(bottle.Bottle): + def run(*args, **argm): + argm['server'] = 'gevent' + super(TemplogBottle, self).run(*args, **argm) + +bottle.default_app.push(TemplogBottle()) + +secure.setup_csrf() + @route('/update', method='post') def update(): js_enc = request.forms.data mac = request.forms.hmac - if hmac.new(config.HMAC_KEY, js_enc).hexdigest() != mac: + h = hmac.new(config.HMAC_KEY, js_enc.strip(), hashlib.sha256).hexdigest() + if h != mac: raise bottle.HTTPError(code = 403, output = "Bad key") js = zlib.decompress(binascii.a2b_base64(js_enc)) @@ -39,50 +50,69 @@ return "OK" -@route('/graph.png') -def graph(): - length_minutes = int(request.query.length) - end = datetime.strptime(request.query.end, DATE_FORMAT) +def make_graph(length, end): + length_minutes = int(length) + end = datetime.strptime(end, DATE_FORMAT) start = end - timedelta(minutes=length_minutes) - response.set_header('Content-Type', 'image/png') start_epoch = time.mktime(start.timetuple()) return log.graph_png(start_epoch, length_minutes * 60) +def encode_data(data, mimetype): + return 'data:%s;base64,%s' % (mimetype, binascii.b2a_base64(data).rstrip()) + +@route('/graph.png') +def graph(): + response.set_header('Content-Type', 'image/png') + minutes, endstr = get_request_zoom() + return make_graph(minutes, endstr) + @route('/set/update', method='post') def set_update(): + if not secure.check_cookie(config.ALLOWED_USERS): + # the "Save" button should be disabled if the cert wasn't + # good + response.status = 403 + return "No cert, dodginess" + post_json = json.loads(request.forms.data) csrf_blob = post_json['csrf_blob'] if not secure.check_csrf_blob(csrf_blob): - bottle.response.status = 403 + response.status = 403 return "Bad csrf" ret = log.update_params(post_json['params']) if not ret is True: - bottle.response.status = 403 + response.status = 409 # Conflict return ret return "Good" @route('/set') def set(): - allowed = ["false", "true"][secure.check_user_hash(config.ALLOWED_USERS)] + cookie_hash = secure.init_cookie() + allowed = ["false", "true"][secure.check_cookie(config.ALLOWED_USERS)] response.set_header('Cache-Control', 'no-cache') - return bottle.template('set', - inline_data = log.get_params(), - csrf_blob = secure.get_csrf_blob(), - allowed = allowed) + if request.query.fake: + inline_data = log.fake_params() + else: + inline_data = log.get_params() + if not inline_data: + response.status = 503 # Service Unavailable + return bottle.template('noparamsyet') -@route('/set_current.json') -def set_fresh(): - response.set_header('Content-Type', 'application/javascript') - return log.get_current() + return bottle.template('set', + inline_data = inline_data, + csrf_blob = secure.get_csrf_blob(), + allowed = allowed, + cookie_hash = cookie_hash, + email = urllib.quote(config.EMAIL)) -@route('/') -def top(): - +def get_request_zoom(): + """ returns (length, end) tuple. + length is in minutes, end is a DATE_FORMAT string """ minutes = int(request.query.get('length', 26*60)) if 'end' in request.query: @@ -93,7 +123,8 @@ if 'zoom' in request.query: orig_start = end - timedelta(minutes=minutes) orig_end = end - xpos = int(request.query.x) + scale = float(request.query.scaledwidth) / config.GRAPH_WIDTH + xpos = int(request.query.x) / scale xpos -= config.GRAPH_LEFT_MARGIN * config.ZOOM if xpos >= 0 and xpos < config.GRAPH_WIDTH * config.ZOOM: @@ -109,14 +140,24 @@ if end > datetime.now(): end = datetime.now() - + + endstr = end.strftime(DATE_FORMAT) + return (minutes, endstr) + +@route('/') +def top(): + minutes, endstr = get_request_zoom() + request.query.replace('length', minutes) - request.query.replace('end', end.strftime(DATE_FORMAT)) + request.query.replace('end', endstr) urlparams = urllib.urlencode(request.query) + graphdata = encode_data(make_graph(minutes, endstr), 'image/png') return bottle.template('top', urlparams=urlparams, - end = end.strftime(DATE_FORMAT), - length = minutes) + end = endstr, + length = minutes, + graphwidth = config.GRAPH_WIDTH, + graphdata = graphdata) @route('/debug') def debuglog(): @@ -133,14 +174,37 @@ #var_lookup = environ['mod_ssl.var_lookup'] #return var_lookup("SSL_SERVER_I_DN_O") +@route('/h') +def headers(): + response.set_header('Content-Type', 'text/plain') + return '\n'.join("%s: %s" % x for x in request.headers.items()) + +@route('/get_settings') +def get_settings(): + response.set_header('Cache-Control', 'no-cache') + req_etag = request.headers.get('etag', None) + if req_etag: + # wait for it to change + # XXX this is meant to return True if it has been woken up + # but it isn't working. Instead compare epochtag below. + log.fridge_settings.wait(req_etag, timeout=config.LONG_POLL_TIMEOUT) + + contents, epoch_tag = log.fridge_settings.get() + if epoch_tag == req_etag: + response.status = 304 + return "Nothing happened" + + response.set_header('Content-Type', 'application/json') + return json.dumps({'params': contents, 'epoch_tag': epoch_tag}) + @bottle.get('/<filename:re:.*\.js>') def javascripts(filename): response.set_header('Cache-Control', "public, max-age=1296000") return bottle.static_file(filename, root='static') -secure.setup_csrf() def main(): + """ for standalone testing """ #bottle.debug(True) #bottle.run(reloader=True) bottle.run(server='cgi', reloader=True)