From b20b5a011c0cab3bcba025392615e17e39ac7fc7 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:16:26 +0200 Subject: [PATCH] sync common.js with upstream import latest changes to common.js from upstream. Only needed for 3rd party tools. --- wled00/data/common.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/wled00/data/common.js b/wled00/data/common.js index eb51eb93..94a47433 100644 --- a/wled00/data/common.js +++ b/wled00/data/common.js @@ -90,7 +90,7 @@ function loadJS(FILE_URL, async = true, preGetV = undefined, postGetV = undefine scE.setAttribute("type", "text/javascript"); scE.setAttribute("async", async); d.body.appendChild(scE); - // success event + // success event scE.addEventListener("load", () => { //console.log("File loaded"); if (preGetV) preGetV(); @@ -126,6 +126,10 @@ function getLoc() { } } function getURL(path) { return (loc ? locproto + "//" + locip : "") + path; } +// HTML entity escaper – use on any remote/user-supplied text inserted into innerHTML +function esc(s) { return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); } +// URL sanitizer – blocks javascript: and data: URIs, use for externally supplied URLs for some basic safety +function safeUrl(u) { return /^https?:\/\//.test(u) ? u : '#'; } function B() { window.open(getURL("/settings"),"_self"); } var timeout; function showToast(text, error = false) { @@ -137,16 +141,26 @@ function showToast(text, error = false) { x.style.animation = 'none'; timeout = setTimeout(function(){ x.className = x.className.replace("show", ""); }, 2900); } -function uploadFile(fileObj, name) { +async function uploadFile(fileObj, name, callback) { + let file = fileObj.files?.[0]; // get first file, "?"" = optional chaining in case no file is selected + if (!file) { callback?.(false); return; } + if (/\.json$/i.test(name)) { // same as name.toLowerCase().endsWith('.json') + try { + const minified = JSON.stringify(JSON.parse(await file.text())); // validate and minify JSON + file = new Blob([minified], { type: file.type || "application/json" }); + } catch (err) { + if (!confirm("JSON invalid. Continue?")) { callback?.(false); return; } + // proceed with original file if invalid but user confirms + } + } var req = new XMLHttpRequest(); - req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)}); - req.addEventListener('error', function(e){showToast(e.stack,true);}); + req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400); if(callback) callback(this.status < 400);}); + req.addEventListener('error', function(e){showToast("Upload failed",true); if(callback) callback(false);}); req.open("POST", "/upload"); var formData = new FormData(); - formData.append("data", fileObj.files[0], name); + formData.append("data", file, name); req.send(formData); fileObj.value = ''; - return false; } // connect to WebSocket, use parent WS or open new, callback function gets passed the new WS object function connectWs(onOpen) {