From d3e1e9b3e8c673e46662c0b7a0204edf829858bb Mon Sep 17 00:00:00 2001 From: wellenvogel Date: Wed, 15 Dec 2021 18:48:06 +0100 Subject: [PATCH] check image before uploading --- web/index.css | 3 + web/index.html | 4 ++ web/index.js | 178 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 141 insertions(+), 44 deletions(-) diff --git a/web/index.css b/web/index.css index a4ad5bb..c4db397 100644 --- a/web/index.css +++ b/web/index.css @@ -334,4 +334,7 @@ body { background-color: blue; width: 0px; height: 100%; +} +.error{ + color: red; } \ No newline at end of file diff --git a/web/index.html b/web/index.html index 571dde1..8ae9a09 100644 --- a/web/index.html +++ b/web/index.html @@ -88,6 +88,10 @@ New Firmware +
+ + +
diff --git a/web/index.js b/web/index.js index dc1757f..3a366ca 100644 --- a/web/index.js +++ b/web/index.js @@ -1453,54 +1453,125 @@ function uploadBin(){ let progressEl=document.getElementById("uploadDone"); if (! el) return; if ( el.files.length < 1) return; - ensurePass() - .then (function(hash){ - let file=el.files[0]; - let len=file.size; - let req = new XMLHttpRequest(); - req.onloadend=function(){ - let result="unknown error"; - try{ - let jresult=JSON.parse(req.responseText); - if (jresult.status == 'OK'){ - result=''; - } - else{ - if (jresult.status) { - result=jresult.status; + let file=el.files[0]; + checkImageFile(file) + .then(function (result) { + let currentType; + let currentVersion; + forEl('.status-version', function (el) { currentVersion = el.textContent }); + forEl('.status-fwtype', function (el) { currentType = el.textContent }); + let confirmText = 'Ready to update firmware?\n'; + if (currentType != result.fwtype) { + confirmText += "WARNING: image has different type: " + result.fwtype + "\n"; + confirmText += "** Really update anyway? - device can become unusable **"; + } + else { + if (currentVersion == result.version) { + confirmText += "WARNING: image has the same version as current " + result.version; + } + else { + confirmText += "version in image: " + result.version; + } + } + if (!confirm(confirmText)) return; + ensurePass() + .then(function (hash) { + let len = file.size; + let req = new XMLHttpRequest(); + req.onloadend = function () { + let result = "unknown error"; + try { + let jresult = JSON.parse(req.responseText); + if (jresult.status == 'OK') { + result = ''; + } + else { + if (jresult.status) { + result = jresult.status; + } + } + } catch (e) { + result = "Error " + req.status; + } + if (progressEl) { + progressEl.style.width = 0; + } + if (!result) { + alertRestart(); + } + else { + alert("update error: " + result); } } - }catch (e){ - result="Error "+req.status; - } - if (progressEl){ - progressEl.style.width=0; - } - if (! result){ - alertRestart(); - } - else{ - alert("update error: "+result); - } - } - req.onerror=function(e){ - alert("unable to upload: "+e); - } - if (progressEl){ - progressEl.style.width=0; - req.upload.onprogress=function(ev){ - if (ev.lengthComputable){ - let percent=100*ev.loaded/ev.total; - progressEl.style.width=percent+"%"; + req.onerror = function (e) { + alert("unable to upload: " + e); } - } - } - let formData = new FormData(); - formData.append("file1", el.files[0]); - req.open("POST", '/api/update?_hash='+encodeURIComponent(hash)); - req.send(formData); + if (progressEl) { + progressEl.style.width = 0; + req.upload.onprogress = function (ev) { + if (ev.lengthComputable) { + let percent = 100 * ev.loaded / ev.total; + progressEl.style.width = percent + "%"; + } + } + } + let formData = new FormData(); + formData.append("file1", el.files[0]); + req.open("POST", '/api/update?_hash=' + encodeURIComponent(hash)); + req.send(formData); + }) + .catch(function (e) { }); }) - .catch(function(e){}); + .catch(function (e) { + alert("This file is an invalid image file:\n" + e); + }) +} +let HDROFFSET=288; +let VERSIONOFFSET=16; +let NAMEOFFSET=48; +let MINSIZE=HDROFFSET+NAMEOFFSET+32; +let imageCheckBytes={ + 0: 0xe9, //image magic + 288: 0x32, //app header magic + 289: 0x54, + 290: 0xcd, + 291: 0xab +}; +function decodeFromBuffer(buffer,start,length){ + while (length > 0 && buffer[start+length-1] == 0){ + length--; + } + if (length <= 0) return ""; + let decoder=new TextDecoder(); + let rt=decoder.decode(buffer.slice( + start, + start+length)); + return rt; +} +function checkImageFile(file){ + return new Promise(function(resolve,reject){ + if (! file) reject("no file"); + if (file.size < MINSIZE) reject("file is too small"); + let slice=file.slice(0,MINSIZE); + let reader=new FileReader(); + reader.addEventListener('load',function(e){ + let content=new Uint8Array(e.target.result); + for (let idx in imageCheckBytes){ + if (content[idx] != imageCheckBytes[idx] ){ + reject("missing magic byte at position "+idx+", expected "+ + imageCheckBytes[idx]+", got "+content[idx]); + } + } + let version=decodeFromBuffer(content,HDROFFSET+VERSIONOFFSET,32); + let fwtype=decodeFromBuffer(content,HDROFFSET+NAMEOFFSET,32); + let rt={ + fwtype:fwtype, + version: version, + }; + resolve(rt); + }); + reader.readAsArrayBuffer(slice); + }); } window.setInterval(update, 1000); window.setInterval(function () { @@ -1550,4 +1621,23 @@ window.addEventListener('load', function () { even=!even; } } + forEl('#uploadFile',function(el){ + el.addEventListener('change',function(ev){ + if (ev.target.files.length < 1) return; + let file=ev.target.files[0]; + checkImageFile(file) + .then(function(res){ + forEl('#imageProperties',function(iel){ + iel.textContent=res.fwtype+", "+res.version; + iel.classList.remove("error"); + }) + }) + .catch(function(e){ + forEl('#imageProperties',function(iel){ + iel.textContent=e; + iel.classList.add("error"); + }) + }) + }) + }) }); \ No newline at end of file