Add config capabilities

This commit is contained in:
sqozz 2018-11-17 23:23:33 +01:00
parent f4d951a088
commit ee2e55e174
3 changed files with 88 additions and 18 deletions

25
config.json Normal file
View file

@ -0,0 +1,25 @@
{
"devices" : {
"84:F3:EB:B4:4D:A7" : {
"role" : "ota_test",
"version" : "latest"
},
"AA:BB:CC:DD:EE:FF" : {
"role" : "non_existant",
"version" : "latest"
}
},
"firmwares" : {
"ota_test" : {
"latest" : {
"filename" : "latest.bin",
"hash" : "d41d8cd98f00b204e9800998ecf8427e"
},
"backup" : {
"filename" : "backup.bin",
"hash" : ""
}
}
}
}

View file

View file

@ -1,33 +1,71 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import hashlib
from bottle import route, run, request, HTTPResponse, response from bottle import route, run, request, HTTPResponse, response
import hashlib
import json
import pdb import pdb
import os
updated = True updated = True
filename = "firmware.bin" filename = "firmware.bin"
@route('/update') @route('/update')
def update(): def updateRequest():
#for header in request.headers.keys(): #for header in request.headers.keys():
# print("{}: {}".format(header, request.headers.get(header, ""))) # print("{}: {}".format(header, request.headers.get(header, "")))
requestor_mac = request.headers.get("X-Esp8266-Sta-Mac") if not "X-Esp8266-Sta-Mac" in request.headers:
running_fw_md5 = request.headers.get("X-Esp8266-Sketch-Md5", "") return "Hello fellow friend! Looking for updates?"
print("Update request from {} with fw {}".format(requestor_mac, running_fw_md5))
available_fw_md5 = md5(filename) readConfig()
global config
requestor_mac = request.headers.get("X-Esp8266-Sta-Mac", "")
running_fw_md5 = request.headers.get("X-Esp8266-Sketch-Md5", "")
role, version, fw_filename, fw_hash = getProperties(config, requestor_mac)
if role == "" and version == "" and fw_filename == "" and fw_hash == "":
print("No configuration for {} found. Serving 304 - No Firmware".format(requestor_mac))
return nofirmware()
print("Update request from {} with role {} (running fw hash: {}).".format(requestor_mac, role, running_fw_md5))
fw_path = os.path.join("firmwares", role, version, fw_filename)
try:
latest_fw_md5 = md5(fw_path)
except FileNotFoundError:
print("Configured firmware not found at {}".format(fw_path))
return nofirmware()
if latest_fw_md5 != fw_hash:
print("Configured hash ({}) does not match calculeted one ({})".format(fw_hash, latest_fw_md5))
return nofirmware()
print("Latest firmware for role \"{}\" is \"{}\" ({}) - ".format(role, fw_filename, latest_fw_md5), end="")
if latest_fw_md5 == running_fw_md5:
print("Same, skipping…")
return nofirmware()
print("Lates firmware available is {} - ".format(available_fw_md5), end="")
if available_fw_md5 != running_fw_md5:
print("Differs, updating…") print("Differs, updating…")
response.set_header('Content-Type', 'application/octet-stream') response.set_header('Content-Type', 'application/octet-stream')
response.set_header('Content-Disposition', ' attachment; filename={}'.format(filename)) response.set_header('Content-Disposition', ' attachment; filename={}'.format(filename))
with open(filename, "rb") as firmware: with open(fw_path, "rb") as fw:
fw = firmware.read() firmware = fw.read()
response.set_header('Content-Length', '{}'.format(len(fw))) response.set_header('Content-Length', '{}'.format(len(firmware)))
response.set_header('X-MD5', available_fw_md5) response.set_header('X-MD5', latest_fw_md5)
return fw print("Serving {} bytes to {} with role {}".format(len(firmware), requestor_mac, role))
else: return firmware
print("Same, skipping…")
def getProperties(config, mac):
configured_devices = config.get("devices", {}).keys()
devices = config.get("devices", {})
firmwares = config.get("firmwares", {})
match = devices.get(mac, {"role":"", "version":""})
role = match.get("role", "")
version = match.get("version", "")
role_firmwares = firmwares.get(role, {})
firmware = role_firmwares.get(version, {})
firmware_filename = firmware.get("filename", "")
firmware_hash = firmware.get("hash", "")
return role, version, firmware_filename, firmware_hash
def nofirmware():
return HTTPResponse(status=304, body="") return HTTPResponse(status=304, body="")
def md5(fname): def md5(fname):
@ -37,4 +75,11 @@ def md5(fname):
hash_md5.update(chunk) hash_md5.update(chunk)
return hash_md5.hexdigest() return hash_md5.hexdigest()
def readConfig(config_name="config.json"):
global config
config = ""
with open(config_name, "r") as conf:
config = json.loads(conf.read())
readConfig()
run(host='localhost', port=8080, debug=True) run(host='localhost', port=8080, debug=True)