Mercurial > templog
annotate web/templog.py @ 541:bde53484df3c
sha256 hmac now
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 19 May 2015 23:56:56 +0800 |
parents | 0f665a84b581 |
children | 2071d939e4ff |
rev | line source |
---|---|
333 | 1 #!/usr/bin/env python2.7 |
2 | |
334 | 3 import binascii |
445
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
4 import json |
334 | 5 import hmac |
335 | 6 import zlib |
375 | 7 from datetime import datetime, timedelta |
337
f575ef538f5d
- Various fixes for web server, kind of works
Matt Johnston <matt@ucc.asn.au>
parents:
336
diff
changeset
|
8 import time |
375 | 9 import urllib |
10 import sys | |
482 | 11 import os |
485 | 12 import traceback |
13 import fcntl | |
541 | 14 import hashlib |
334 | 15 |
333 | 16 import bottle |
337
f575ef538f5d
- Various fixes for web server, kind of works
Matt Johnston <matt@ucc.asn.au>
parents:
336
diff
changeset
|
17 from bottle import route, request, response |
333 | 18 |
334 | 19 import config |
20 import log | |
485 | 21 import secure |
489 | 22 import atomicfile |
334 | 23 |
375 | 24 DATE_FORMAT = '%Y%m%d-%H.%M' |
25 ZOOM_SCALE = 2.0 | |
26 | |
539 | 27 class TemplogBottle(bottle.Bottle): |
28 def run(*args, **argm): | |
29 argm['server'] = 'gevent' | |
30 super(TemplogBottle, self).run(*args, **argm) | |
31 print "ran custom bottle" | |
32 | |
540
0f665a84b581
gevent doesn't work well with subprocess
Matt Johnston <matt@ucc.asn.au>
parents:
539
diff
changeset
|
33 #bottle.default_app.push(TemplogBottle()) |
539 | 34 |
35 secure.setup_csrf() | |
36 | |
333 | 37 @route('/update', method='post') |
38 def update(): | |
445
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
39 js_enc = request.forms.data |
334 | 40 mac = request.forms.hmac |
41 | |
541 | 42 h = hmac.new(config.HMAC_KEY, js_enc.strip(), hashlib.sha256).hexdigest() |
43 if h != mac: | |
391 | 44 raise bottle.HTTPError(code = 403, output = "Bad key") |
334 | 45 |
445
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
46 js = zlib.decompress(binascii.a2b_base64(js_enc)) |
334 | 47 |
445
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
48 params = json.loads(js) |
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
49 |
5b9dc87c988f
update web to handle new style params
Matt Johnston <matt@ucc.asn.au>
parents:
409
diff
changeset
|
50 log.parse(params) |
334 | 51 |
52 return "OK" | |
333 | 53 |
54 @route('/graph.png') | |
55 def graph(): | |
375 | 56 length_minutes = int(request.query.length) |
57 end = datetime.strptime(request.query.end, DATE_FORMAT) | |
58 start = end - timedelta(minutes=length_minutes) | |
336
ba4c4df13487
parse the arguments for start/length
Matt Johnston <matt@ucc.asn.au>
parents:
335
diff
changeset
|
59 |
ba4c4df13487
parse the arguments for start/length
Matt Johnston <matt@ucc.asn.au>
parents:
335
diff
changeset
|
60 response.set_header('Content-Type', 'image/png') |
375 | 61 start_epoch = time.mktime(start.timetuple()) |
62 return log.graph_png(start_epoch, length_minutes * 60) | |
333 | 63 |
487 | 64 @route('/set/update', method='post') |
492 | 65 def set_update(): |
487 | 66 post_json = json.loads(request.forms.data) |
67 | |
68 csrf_blob = post_json['csrf_blob'] | |
69 | |
492 | 70 if not secure.check_csrf_blob(csrf_blob): |
71 bottle.response.status = 403 | |
72 return "Bad csrf" | |
73 | |
74 ret = log.update_params(post_json['params']) | |
75 if not ret is True: | |
76 bottle.response.status = 403 | |
77 return ret | |
78 | |
79 return "Good" | |
487 | 80 |
482 | 81 @route('/set') |
82 def set(): | |
505
ad846b9bdd10
key fingerprints are case- and whitespace-insensitive.
Matt Johnston <matt@ucc.asn.au>
parents:
501
diff
changeset
|
83 allowed = ["false", "true"][secure.check_user_hash(config.ALLOWED_USERS)] |
501
236e5d131b3e
Add url link, improve atomicfile
Matt Johnston <matt@ucc.asn.au>
parents:
492
diff
changeset
|
84 response.set_header('Cache-Control', 'no-cache') |
485 | 85 return bottle.template('set', |
86 inline_data = log.get_params(), | |
488 | 87 csrf_blob = secure.get_csrf_blob(), |
88 allowed = allowed) | |
482 | 89 |
333 | 90 @route('/') |
91 def top(): | |
375 | 92 |
93 minutes = int(request.query.get('length', 26*60)) | |
94 | |
95 if 'end' in request.query: | |
96 end = datetime.strptime(request.query.end, DATE_FORMAT) | |
97 else: | |
98 end = datetime.now() | |
99 | |
100 if 'zoom' in request.query: | |
101 orig_start = end - timedelta(minutes=minutes) | |
102 orig_end = end | |
103 xpos = int(request.query.x) | |
383 | 104 xpos -= config.GRAPH_LEFT_MARGIN * config.ZOOM |
375 | 105 |
383 | 106 if xpos >= 0 and xpos < config.GRAPH_WIDTH * config.ZOOM: |
375 | 107 click_time = orig_start \ |
383 | 108 + timedelta(minutes=(float(xpos) / (config.GRAPH_WIDTH * config.ZOOM)) * minutes) |
375 | 109 minutes = int(minutes / ZOOM_SCALE) |
110 | |
111 end = click_time + timedelta(minutes=minutes/2) | |
112 else: | |
113 # zoom out | |
114 minutes = int(minutes*ZOOM_SCALE) | |
115 end += timedelta(minutes=minutes/2) | |
116 | |
117 if end > datetime.now(): | |
118 end = datetime.now() | |
119 | |
120 request.query.replace('length', minutes) | |
121 request.query.replace('end', end.strftime(DATE_FORMAT)) | |
122 | |
123 urlparams = urllib.urlencode(request.query) | |
124 return bottle.template('top', urlparams=urlparams, | |
125 end = end.strftime(DATE_FORMAT), | |
126 length = minutes) | |
333 | 127 |
409 | 128 @route('/debug') |
129 def debuglog(): | |
130 response.set_header('Content-Type', 'text/plain') | |
131 return log.tail_debug_log() | |
344
ea1779d27641
- Getting there, update has problems
Matt Johnston <matt@ucc.asn.au>
parents:
337
diff
changeset
|
132 |
482 | 133 @route('/env') |
134 def env(): | |
135 response.set_header('Content-Type', 'text/plain') | |
488 | 136 #return '\n'.join(traceback.format_stack()) |
137 return '\n'.join(("%s %s" % k) for k in request.environ.items()) | |
482 | 138 #return str(request.environ) |
139 #yield "\n" | |
140 #var_lookup = environ['mod_ssl.var_lookup'] | |
141 #return var_lookup("SSL_SERVER_I_DN_O") | |
142 | |
143 @bottle.get('/<filename:re:.*\.js>') | |
144 def javascripts(filename): | |
485 | 145 response.set_header('Cache-Control', "public, max-age=1296000") |
482 | 146 return bottle.static_file(filename, root='static') |
147 | |
333 | 148 def main(): |
367 | 149 #bottle.debug(True) |
150 #bottle.run(reloader=True) | |
151 bottle.run(server='cgi', reloader=True) | |
346 | 152 #bottle.run(port=9999, reloader=True) |
333 | 153 |
154 if __name__ == '__main__': | |
155 main() | |
156 |