From b02bc29d29b4b916ae5f42cf9debfa040a3430c2 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 13 Oct 2024 22:48:20 +0200 Subject: [PATCH] UI communication progress --- readme.md | 3 +++ wled00/crypto.cpp | 14 ++++++++++++++ wled00/data/index.js | 37 +++++++++++++++++++++++++++++++++++++ wled00/wled_server.cpp | 30 +++++++++++++++++++++++++++++- 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 11c1733f87..a406bfd3ce 100644 --- a/readme.md +++ b/readme.md @@ -10,6 +10,9 @@

+> [!CAUTION] +> This branch is actively used for research purposes. **Please do not push** to it. + # Welcome to my project WLED! ✨ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102! diff --git a/wled00/crypto.cpp b/wled00/crypto.cpp index 818c0f2d24..142f1561e3 100644 --- a/wled00/crypto.cpp +++ b/wled00/crypto.cpp @@ -31,6 +31,20 @@ bool hmac_verify(const char* message, const char* psk, const byte* signature) { return true; } +bool verify_json_hmac(JsonObject root) { + JsonObject msg = root["msg"]; + if (!msg) { + Serial.println(F("No message object found in JSON.")); + return false; + } + const char *sig = msg["sig"]; + if (sig == nullptr) { + Serial.println(F("No signature found in JSON.")); + return false; + } + +} + bool hmac_test() { Serial.println(F("Testing HMAC...")); unsigned long start = millis(); diff --git a/wled00/data/index.js b/wled00/data/index.js index 25ade11639..35b4cd502a 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -214,6 +214,10 @@ function loadSkinCSS(cId) } } +var useSRA = false; +var sraWindow = null; +var sraOrigin = ''; + function getURL(path) { return (loc ? locproto + "//" + locip : "") + path; } @@ -243,6 +247,13 @@ function onLoad() var sett = localStorage.getItem('wledUiCfg'); if (sett) cfg = mergeDeep(cfg, JSON.parse(sett)); + if (window.opener) { + // can't get opener origin due to cross-origin browser policy + //var openerOrigin = window.opener.location.origin; + //console.log("WLED-UI opener origin: " + openerOrigin); + window.opener.postMessage('{"wled-ui":"onload"}', '*'); //openerOrigin); + } + tooltip(); resetPUtil(); initFilters(); @@ -301,6 +312,26 @@ function onLoad() }); } +function handleWindowMessageEvent(event) { + console.log(`Received message: ${event.data}`); + console.log(`origin: ${event.origin}`); + try { + var json = JSON.parse(event.data) + } catch (e) { + console.log(`Error parsing JSON: ${e}`); + return; + } + if (json['wled-rc'] === 'ready') { + useSRA = true; + sraWindow = event.source; + sraOrigin = event.origin; + } else if (json['wled-rc'] === 'hmac') { + console.log(`Received HMAC: ${json['hmac']}`); + } +} + +onmessage = (event) => { handleWindowMessageEvent(event) }; + function updateTablinks(tabI) { var tablinks = gEBCN("tablinks"); @@ -1703,6 +1734,12 @@ function requestJson(command=null) if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes }; + if (command && useSRA && !command['sig']) { // secure remote access integration, need to get HMAC from rc.wled.me + // if we already have a command including a signature, we are good to go + sraWindow.postMessage(JSON.stringify({"wled-ui":"hmac-req", "msg":command}), sraOrigin); + return; // TODO need a sort of pending indicator + } + if (useWs) { ws.send(req?req:'{"v":true}'); return; diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 4a616f9aa5..cace011866 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -297,9 +297,26 @@ void initServer() DeserializationError error = deserializeJson(*pDoc, (uint8_t*)(request->_tempObject)); // if enabled, calculate HMAC and verify it - Serial.println("HMAC verification"); + Serial.println(F("HMAC verification")); Serial.write((const char*)request->_tempObject, request->contentLength()); + // actually we need to verify the HMAC of the nested "msg" object + if (strlen((const char*)request->_tempObject) > request->contentLength()) { + Serial.println(F("HMAC verification failed: content is not null-terminated")); + releaseJSONBufferLock(); + serveJsonError(request, 400, ERR_JSON); + return; + } + // find the "msg" object in JSON + char * msgPtr = strstr((const char*)request->_tempObject, "\"msg\":"); + if (msgPtr == NULL) { + Serial.println(F("HMAC verification failed: no \"msg\" object found")); + releaseJSONBufferLock(); + serveJsonError(request, 400, ERR_JSON); + return; + } + char * objStart = strchr(msgPtr, '{'); + JsonObject root = pDoc->as(); if (error || root.isNull()) { releaseJSONBufferLock(); @@ -307,6 +324,17 @@ void initServer() return; } + // if (root.containsKey("sig")) { + // const char* hmacProvided = root["sig"]; + // char hmac_calculated[SHA256HMAC_SIZE]; + // hmac_sign((const char*)request->_tempObject, settings.hmacKey, (byte*)hmac_calculated); + // if (memcmp(hmac_calculated, hmac, SHA256HMAC_SIZE) != 0) { + // releaseJSONBufferLock(); + // serveJsonError(request, 401, ERR_HMAC); + // return; + // } + // } + // old 4-digit pin logic for settings authentication (no transport encryption) if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as());