# HG changeset patch # User Matt Johnston # Date 1392133673 -28800 # Node ID 4fa8cbf31065e06dce39202e07f505ac9d760145 # Parent e13146001852d4264c1a39b7985e8fcbd73a9191 working kinda diff -r e13146001852 -r 4fa8cbf31065 web/config.py --- a/web/config.py Tue Feb 11 22:11:03 2014 +0800 +++ b/web/config.py Tue Feb 11 23:47:53 2014 +0800 @@ -4,11 +4,15 @@ SERIAL_HOST='home.example.com' SERIAL_PORT=1999 + DATA_PATH = '/home/matt/templog/web/data' -HMAC_KEY = 'a hmac key' # override in local config file - -ALLOWED_USERS = [] # local config. list of sha1 hashes of client ssl keys +# local config items +HMAC_KEY = 'a hmac key' +ALLOWED_USERS = [] # list of sha1 hashes of client ssl keys +SSH_HOST = 'remotehost' +SSH_KEYFILE = '/home/matt/.ssh/somekey' +SSH_PROG = 'ssh' UPDATE_URL = 'http://evil.ucc.asn.au/~matt/templog/update' diff -r e13146001852 -r 4fa8cbf31065 web/log.py --- a/web/log.py Tue Feb 11 22:11:03 2014 +0800 +++ b/web/log.py Tue Feb 11 23:47:53 2014 +0800 @@ -15,6 +15,7 @@ import struct import binascii import json +import subprocess from colorsys import hls_to_rgb import config @@ -269,24 +270,25 @@ debugf.write("Updated sensors in %.2f secs\n" % timedelta) debugf.flush() +_FIELD_DEFAULTS = { + 'fridge_setpoint': 16, + 'fridge_difference': 0.2, + 'overshoot_delay': 720, # 12 minutes + 'overshoot_factor': 1, # ºC + 'disabled': False, + 'nowort': True, + 'fridge_range_lower': 3, + 'fridge_range_upper': 3, + } + def get_params(): - _FIELD_DEFAULTS = { - 'fridge_setpoint': 16, - 'fridge_difference': 0.2, - 'overshoot_delay': 720, # 12 minutes - 'overshoot_factor': 1, # ºC - 'disabled': False, - 'nowort': True, - 'fridge_range_lower': 3, - 'fridge_range_upper': 3, - } r = [] vals = read_current_params() for k, v in _FIELD_DEFAULTS.iteritems(): - n = {'name': k, 'value': vals[k]} + n = {'name': k, 'value': type(v)(vals[k])} if type(v) is bool: kind = 'yesno' else: @@ -305,6 +307,54 @@ return json.dumps(r, sort_keys=True, indent=4) +def send_params(params): + # 'templog_receive' is ignored due to authorized_keys + # restrictions + args = [config.SSH_PROG, '-i', config.SSH_KEYFILE, + config.SSH_HOST, 'templog_receive'] + try: + p = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + (out, err) = p.communicate(json.dumps(params)) + except OSError, e: + print>>sys.stderr, e + return "Failed update" -def get_csrf_blob(user_ident): - return "aaa" + if 'Good Update' in out: + return True + + print>>sys.stderr, "Strange return from update:" + print>>sys.stderr, out + return "Unexpected update result" + +def same_type(a, b): + ta = type(a) + tb = type(b) + + if ta == int: + ta = float + if tb == int: + tb = float + + return (ta == tb) + +def update_params(p): + params = {} + for i in p: + params[i['name']] = i['value'] + + if params.viewkeys() != _FIELD_DEFAULTS.viewkeys(): + diff = params.viewkeys() ^ _FIELD_DEFAULTS.viewkeys() + return "Key mismatch, difference %s" % str(diff) + + for k, v in params.items(): + if not same_type(v, _FIELD_DEFAULTS[k]): + return "Bad type for %s, %s vs %s" % (k , type(v), type(_FIELD_DEFAULTS[k])) + + ret = send_params(params) + if ret is not True: + return "Failed sending params: %s" % ret + + return True + + + diff -r e13146001852 -r 4fa8cbf31065 web/secure.py --- a/web/secure.py Tue Feb 11 22:11:03 2014 +0800 +++ b/web/secure.py Tue Feb 11 23:47:53 2014 +0800 @@ -54,27 +54,33 @@ def check_csrf_blob(blob): toks = blob.split('-') if len(toks) != 3: + print>>sys.stderr, "wrong toks" return False user, expiry, mac = toks if user != get_user_hash(): + print>>sys.stderr, "wrong user" return False try: exp = int(expiry) except ValueError: + print>>sys.stderr, "failed exp" return False if exp < 1000000000: return False - if exp > time.time(): + if exp < time.time(): + print>>sys.stderr, "expired %d %d" % (exp, time.time()) return False check_content = "%s-%s" % (user, expiry) - check_mac = hmac.new(_csrf_key, content).hexdigest() + check_mac = hmac.new(_csrf_key, check_content).hexdigest() if mac == check_mac: + print>>sys.stderr, "good hmac" return True + print>>sys.stderr, "fail" return False diff -r e13146001852 -r 4fa8cbf31065 web/templog.py --- a/web/templog.py Tue Feb 11 22:11:03 2014 +0800 +++ b/web/templog.py Tue Feb 11 23:47:53 2014 +0800 @@ -50,12 +50,21 @@ return log.graph_png(start_epoch, length_minutes * 60) @route('/set/update', method='post') -def update(): +def set_update(): post_json = json.loads(request.forms.data) csrf_blob = post_json['csrf_blob'] - return str(post_json['params']) + if not secure.check_csrf_blob(csrf_blob): + bottle.response.status = 403 + return "Bad csrf" + + ret = log.update_params(post_json['params']) + if not ret is True: + bottle.response.status = 403 + return ret + + return "Good" @route('/set') def set(): @@ -139,4 +148,3 @@ if __name__ == '__main__': main() - diff -r e13146001852 -r 4fa8cbf31065 web/views/set.tpl --- a/web/views/set.tpl Tue Feb 11 22:11:03 2014 +0800 +++ b/web/views/set.tpl Tue Feb 11 23:47:53 2014 +0800 @@ -76,6 +76,10 @@ margin-top: 10pt; } +span.inputrow { + //vertical-align: center; +} + Set templog @@ -85,9 +89,11 @@
{title} {oldvaluetext}{unit}
+ +
@@ -95,8 +101,10 @@
{title} {oldvaluetext}
+ +
@@ -158,7 +166,8 @@ req.fail(function(data, status, hdr) { self.trigger("status", - "Failed: " + status + "\n" + hdr.responseText) + "Failed: " + data.status + ' ' + + data.statusText + ' ' + data.responseText) }); } }