mirror of
https://github.com/wled/WLED.git
synced 2025-12-25 17:38:17 +00:00
Compare commits
5 Commits
secure-api
...
lto_size_o
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a3298cddc | ||
|
|
d3f4326b1c | ||
|
|
d3c401ed4e | ||
|
|
10d8cfde85 | ||
|
|
6f221852a2 |
@@ -141,7 +141,6 @@ lib_deps =
|
||||
makuna/NeoPixelBus @ 2.8.0
|
||||
#https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta
|
||||
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1
|
||||
https://github.com/Aircoookie/arduino-crypto.git
|
||||
# for I2C interface
|
||||
;Wire
|
||||
# ESP-NOW library
|
||||
@@ -269,7 +268,7 @@ AR_lib_deps = kosme/arduinoFFT @ 2.0.1
|
||||
;;
|
||||
;; please note that you can NOT update existing ESP32 installs with a "V4" build. Also updating by OTA will not work properly.
|
||||
;; You need to completely erase your device (esptool erase_flash) first, then install the "V4" build from VSCode+platformio.
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform = espressif32@ ~6.6.0 ;; supports -flto
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-Wshadow=compatible-local ;; emit warning in case a local variable "shadows" another local one
|
||||
@@ -282,7 +281,7 @@ lib_deps =
|
||||
|
||||
[esp32s2]
|
||||
;; generic definitions for all ESP32-S2 boards
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform = espressif32@ ~6.6.0 ;; supports -flto
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-DARDUINO_ARCH_ESP32
|
||||
@@ -317,7 +316,7 @@ lib_deps =
|
||||
|
||||
[esp32s3]
|
||||
;; generic definitions for all ESP32-S3 boards
|
||||
platform = espressif32@ ~6.3.2
|
||||
platform = espressif32@ ~6.6.0 ;; supports -flto
|
||||
platform_packages = platformio/framework-arduinoespressif32 @ 3.20009.0 ;; select arduino-esp32 v2.0.9 (arduino-esp32 2.0.10 thru 2.0.14 are buggy so avoid them)
|
||||
build_flags = -g
|
||||
-DESP32
|
||||
@@ -425,7 +424,9 @@ board = esp32dev
|
||||
platform = ${esp32_idf_V4.platform}
|
||||
platform_packages = ${esp32_idf_V4.platform_packages}
|
||||
build_unflags = ${common.build_unflags}
|
||||
-fno-lto
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_8M #-D WLED_DISABLE_BROWNOUT_DET
|
||||
-g3 -ggdb -flto=auto ;; enable size optimization by the linker - comment out when debugging. ("=4" just means "use 4 cores in parallel")
|
||||
${esp32.AR_build_flags}
|
||||
lib_deps = ${esp32_idf_V4.lib_deps}
|
||||
${esp32.AR_lib_deps}
|
||||
@@ -469,7 +470,9 @@ board_build.f_flash = 80000000L
|
||||
board_build.flash_mode = qio
|
||||
board_build.partitions = ${esp32.extended_partitions}
|
||||
build_unflags = ${common.build_unflags}
|
||||
-fno-lto
|
||||
build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_NAME=ESP32_WROVER
|
||||
-g3 -ggdb -flto=4 ;; enable size optimization by the linker - comment out when debugging. ("=4" just means "use 4 cores in parallel")
|
||||
-DBOARD_HAS_PSRAM -mfix-esp32-psram-cache-issue ;; Older ESP32 (rev.<3) need a PSRAM fix (increases static RAM used) https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/external-ram.html
|
||||
-D DATA_PINS=25
|
||||
${esp32.AR_build_flags}
|
||||
@@ -541,7 +544,9 @@ platform = ${esp32s3.platform}
|
||||
platform_packages = ${esp32s3.platform_packages}
|
||||
upload_speed = 921600
|
||||
build_unflags = ${common.build_unflags}
|
||||
-fno-lto
|
||||
build_flags = ${common.build_flags} ${esp32s3.build_flags} -D WLED_RELEASE_NAME=ESP32-S3_4M_qspi
|
||||
-g3 -ggdb -flto=4 ;; enable size optimization by the linker - comment out when debugging. ("=4" just means "use 4 cores in parallel")
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 ;; for boards with USB-OTG connector only (USBCDC or "TinyUSB")
|
||||
-DBOARD_HAS_PSRAM
|
||||
-DLOLIN_WIFI_FIX ; seems to work much better with this
|
||||
@@ -562,7 +567,9 @@ board_build.partitions = ${esp32.default_partitions}
|
||||
board_build.flash_mode = qio
|
||||
board_build.f_flash = 80000000L
|
||||
build_unflags = ${common.build_unflags}
|
||||
-fno-lto
|
||||
build_flags = ${common.build_flags} ${esp32s2.build_flags} -D WLED_RELEASE_NAME=ESP32-S2
|
||||
-g3 -ggdb -flto=4 ;; enable size optimization by the linker - comment out when debugging. ("=4" just means "use 4 cores in parallel")
|
||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||
-DARDUINO_USB_MSC_ON_BOOT=0
|
||||
-DARDUINO_USB_DFU_ON_BOOT=0
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
|
||||
</p>
|
||||
|
||||
> [!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!
|
||||
|
||||
7
tools/WLED_ESP32_4MB_512KB_FS.csv
Normal file
7
tools/WLED_ESP32_4MB_512KB_FS.csv
Normal file
@@ -0,0 +1,7 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x5000,
|
||||
otadata, data, ota, 0xe000, 0x2000,
|
||||
app0, app, ota_0, 0x10000, 0x1B0000,
|
||||
app1, app, ota_1, 0x1C0000,0x1B0000,
|
||||
spiffs, data, spiffs, 0x370000,0x80000,
|
||||
coredump, data, coredump,,64K
|
||||
|
@@ -704,11 +704,14 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel
|
||||
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)};
|
||||
// multiply the intensities by the colour, and saturating-add them to the pixels
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CRGB led = getPixelColorXY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1));
|
||||
int wu_x = (x >> 8) + (i & 1); // precalculate x
|
||||
int wu_y = (y >> 8) + ((i >> 1) & 1); // precalculate y
|
||||
CRGB led = getPixelColorXY(wu_x, wu_y);
|
||||
CRGB oldLed = led;
|
||||
led.r = qadd8(led.r, c.r * wu[i] >> 8);
|
||||
led.g = qadd8(led.g, c.g * wu[i] >> 8);
|
||||
led.b = qadd8(led.b, c.b * wu[i] >> 8);
|
||||
setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led);
|
||||
if (led != oldLed) setPixelColorXY(wu_x, wu_y, led); // don't repaint if same color
|
||||
}
|
||||
}
|
||||
#undef WU_WEIGHT
|
||||
|
||||
@@ -421,8 +421,6 @@
|
||||
#define SEG_CAPABILITY_W 0x02
|
||||
#define SEG_CAPABILITY_CCT 0x04
|
||||
|
||||
#define SESSION_ID_SIZE 16
|
||||
|
||||
// WLED Error modes
|
||||
#define ERR_NONE 0 // All good :)
|
||||
#define ERR_DENIED 1 // Permission denied
|
||||
@@ -440,11 +438,6 @@
|
||||
#define ERR_OVERTEMP 30 // An attached temperature sensor has measured above threshold temperature (not implemented)
|
||||
#define ERR_OVERCURRENT 31 // An attached current sensor has measured a current above the threshold (not implemented)
|
||||
#define ERR_UNDERVOLT 32 // An attached voltmeter has measured a voltage below the threshold (not implemented)
|
||||
#define ERR_NONCE 40 // Invalid nonce
|
||||
#define ERR_REPLAY 41 // Replay attack detected
|
||||
#define ERR_HMAC 42 // HMAC verification failed
|
||||
#define ERR_HMAC_MISS 43 // HMAC missing
|
||||
#define ERR_HMAC_GEN 44 // HMAC handling error
|
||||
|
||||
// Timer mode types
|
||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||
|
||||
@@ -1,320 +0,0 @@
|
||||
#include <Crypto.h>
|
||||
#include "wled.h"
|
||||
|
||||
#define HMAC_KEY_SIZE 32
|
||||
|
||||
#define MAX_SESSION_IDS 8
|
||||
|
||||
void printByteArray(const byte* arr, size_t len) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
Serial.print(arr[i], HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
struct Nonce {
|
||||
byte sessionId[SESSION_ID_SIZE];
|
||||
uint32_t counter;
|
||||
};
|
||||
|
||||
Nonce knownSessions[MAX_SESSION_IDS] = {};
|
||||
|
||||
void moveToFirst(uint32_t i) {
|
||||
if (i >= MAX_SESSION_IDS) return;
|
||||
|
||||
Nonce tmp = knownSessions[i];
|
||||
for (int j = i; j > 0; j--) {
|
||||
knownSessions[j] = knownSessions[j - 1];
|
||||
}
|
||||
knownSessions[0] = tmp;
|
||||
}
|
||||
|
||||
uint8_t verifyNonce(const byte* sid, uint32_t counter) {
|
||||
Serial.println(F("check sid"));
|
||||
printByteArray(sid, SESSION_ID_SIZE);
|
||||
|
||||
uint32_t sum = 0;
|
||||
for (size_t i = 0; i < SESSION_ID_SIZE; i++) {
|
||||
sum += sid[i];
|
||||
}
|
||||
if (sum == 0) { // all-zero session ID is invalid as it is used for uninitialized entries
|
||||
return ERR_NONCE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_SESSION_IDS; i++) {
|
||||
if (memcmp(knownSessions[i].sessionId, sid, SESSION_ID_SIZE) == 0) {
|
||||
Serial.print(F("Session ID matches e"));
|
||||
Serial.println(i);
|
||||
if (counter <= knownSessions[i].counter) {
|
||||
Serial.println(F("Retransmission detected!"));
|
||||
return ERR_REPLAY;
|
||||
}
|
||||
knownSessions[i].counter = counter;
|
||||
// nonce good, move this entry to the first position of knownSessions
|
||||
moveToFirst(i);
|
||||
return ERR_NONE;
|
||||
}
|
||||
}
|
||||
Serial.println(F("Unknown session ID!"));
|
||||
return ERR_NONCE;
|
||||
}
|
||||
|
||||
void addSessionId(byte* sid) {
|
||||
RNG::fill(sid, SESSION_ID_SIZE);
|
||||
|
||||
// first, try to find a completely unused slot
|
||||
for (int i = 0; i < MAX_SESSION_IDS; i++) {
|
||||
// this is not perfect, but it is extremely unlikely that the first 32 bit of a random session ID are all zeroes
|
||||
if ((uint32_t)(knownSessions[i].sessionId) == 0 && knownSessions[i].counter == 0) {
|
||||
memcpy(knownSessions[i].sessionId, sid, SESSION_ID_SIZE);
|
||||
moveToFirst(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// next, find oldest slot that has counter 0 (not used before)
|
||||
// but leave the two most recent slots alone
|
||||
for (int i = MAX_SESSION_IDS - 1; i > 1; i--) {
|
||||
if (knownSessions[i].counter == 0) {
|
||||
memcpy(knownSessions[i].sessionId, sid, SESSION_ID_SIZE);
|
||||
moveToFirst(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// if all else fails, overwrite the oldest slot
|
||||
memcpy(knownSessions[MAX_SESSION_IDS - 1].sessionId, sid, SESSION_ID_SIZE);
|
||||
moveToFirst(MAX_SESSION_IDS - 1);
|
||||
}
|
||||
|
||||
void hexStringToByteArray(const char* hexString, unsigned char* byteArray, size_t byteArraySize) {
|
||||
size_t lenStr = strlen(hexString);
|
||||
if (lenStr < 2 * byteArraySize) byteArraySize = lenStr / 2;
|
||||
|
||||
for (size_t i = 0; i < byteArraySize; i++) {
|
||||
char c[3] = {hexString[2 * i], hexString[2 * i + 1], '\0'}; // Get two characters
|
||||
byteArray[i] = (unsigned char)strtoul(c, NULL, 16); // Convert to byte
|
||||
}
|
||||
}
|
||||
|
||||
// requires hexString to be at least 2 * byteLen + 1 characters long
|
||||
char* byteArrayToHexString(char* hexString, const byte* byteArray, size_t byteLen) {
|
||||
|
||||
for (size_t i = 0; i < byteLen; ++i) {
|
||||
// Convert each byte to a two-character hex string
|
||||
sprintf(&hexString[i * 2], "%02x", byteArray[i]);
|
||||
}
|
||||
|
||||
// Null-terminate the string
|
||||
hexString[byteLen * 2] = '\0';
|
||||
|
||||
return hexString;
|
||||
}
|
||||
|
||||
void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* signature) {
|
||||
size_t len = strlen(pskHex) / 2; // This will drop the last character if the string has an odd length
|
||||
if (len > HMAC_KEY_SIZE) {
|
||||
Serial.println(F("PSK too long!"));
|
||||
return;
|
||||
}
|
||||
unsigned char pskByteArray[len];
|
||||
hexStringToByteArray(pskHex, pskByteArray, len);
|
||||
|
||||
SHA256HMAC hmac(pskByteArray, len);
|
||||
hmac.doUpdate(message, msgLen);
|
||||
hmac.doFinal(signature);
|
||||
}
|
||||
|
||||
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature) {
|
||||
byte sigCalculated[SHA256HMAC_SIZE];
|
||||
hmacSign(message, msgLen, pskHex, sigCalculated);
|
||||
//Serial.print(F("Calculated: "));
|
||||
//printByteArray(sigCalculated, SHA256HMAC_SIZE);
|
||||
if (memcmp(sigCalculated, signature, SHA256HMAC_SIZE) != 0) {
|
||||
Serial.println(F("HMAC verification failed!"));
|
||||
Serial.print(F("Expected: "));
|
||||
printByteArray(signature, SHA256HMAC_SIZE);
|
||||
return false;
|
||||
}
|
||||
Serial.println(F("HMAC verification successful!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
#define WLED_HMAC_TEST_PW "guessihadthekeyafterall"
|
||||
#define WLED_HMAC_TEST_PSK "a6f8488da62c5888d7f640276676e78da8639faf0495110b43e226b35ac37a4c"
|
||||
|
||||
uint8_t verifyHmacFromJsonString0Term(byte* jsonStr, size_t len) {
|
||||
// Zero-terminate the JSON string (replace the last character, usually '}', with a null terminator temporarily)
|
||||
byte lastChar = jsonStr[len-1];
|
||||
jsonStr[len-1] = '\0';
|
||||
uint8_t result = verifyHmacFromJsonStr((const char*)jsonStr, len);
|
||||
jsonStr[len-1] = lastChar;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) {
|
||||
// Extract the signature from the JSON string
|
||||
size_t jsonLen = strlen(jsonStr);
|
||||
Serial.print(F("Length: "));
|
||||
Serial.println(jsonLen);
|
||||
if (jsonLen > maxLen) { // memory safety
|
||||
Serial.print(F("JSON string too long!"));
|
||||
Serial.print(F(", max: "));
|
||||
Serial.println(maxLen);
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
Serial.print(F("Received JSON: "));
|
||||
Serial.println(jsonStr);
|
||||
|
||||
const char* macPos = strstr(jsonStr, "\"mac\":\"");
|
||||
if (macPos == nullptr) {
|
||||
Serial.println(F("No MAC found in JSON."));
|
||||
return ERR_HMAC_MISS;
|
||||
}
|
||||
StaticJsonDocument<128> macDoc;
|
||||
DeserializationError error = deserializeJson(macDoc, macPos +6);
|
||||
if (error) {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(error.c_str());
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
const char* mac = macDoc.as<const char*>();
|
||||
if (mac == nullptr) {
|
||||
Serial.println(F("Failed MAC JSON."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
Serial.print(F("Received MAC: "));
|
||||
Serial.println(mac);
|
||||
|
||||
// extract the message object from the JSON string
|
||||
char* msgPos = strstr(jsonStr, "\"msg\":");
|
||||
char* objStart = strchr(msgPos + 6, '{');
|
||||
if (objStart == nullptr) {
|
||||
Serial.println(F("Couldn't find msg object start."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
size_t maxObjLen = jsonLen - (objStart - jsonStr);
|
||||
Serial.print(F("Max object length: ")); Serial.println(maxObjLen);
|
||||
int32_t objDepth = 0;
|
||||
char* objEnd = nullptr;
|
||||
|
||||
for (size_t i = 0; i < maxObjLen; i++) {
|
||||
Serial.write(objStart[i]);
|
||||
if (objStart[i] == '{') objDepth++;
|
||||
if (objStart[i] == '}') objDepth--;
|
||||
if (objDepth == 0) {
|
||||
Serial.print(F("Found msg object end: "));
|
||||
Serial.println(i);
|
||||
objEnd = objStart + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (objEnd == nullptr) {
|
||||
Serial.println(F("Couldn't find msg object end."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
|
||||
// get nonce (note: the nonce implementation uses "nc" for the key instead of "n" to avoid conflicts with segment names)
|
||||
const char* noncePos = strstr(objStart, "\"nc\":");
|
||||
if (noncePos == nullptr || noncePos > objEnd) {
|
||||
// note that it is critical to check that the nonce is within the "msg" object and thus authenticated
|
||||
Serial.println(F("No nonce found in msg."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
|
||||
// Convert the MAC from hex string to byte array
|
||||
size_t len = strlen(mac) / 2; // This will drop the last character if the string has an odd length
|
||||
if (len != SHA256HMAC_SIZE) {
|
||||
Serial.println(F("Received MAC not expected size!"));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
unsigned char macByteArray[len];
|
||||
hexStringToByteArray(mac, macByteArray, len);
|
||||
|
||||
// Calculate the HMAC of the message object
|
||||
if (!hmacVerify((const byte*)objStart, objEnd - objStart + 1, WLED_HMAC_TEST_PSK, macByteArray)) {
|
||||
return ERR_HMAC;
|
||||
}
|
||||
|
||||
// Nonce verification (Replay attack prevention)
|
||||
{
|
||||
StaticJsonDocument<128> nonceDoc;
|
||||
DeserializationError error = deserializeJson(nonceDoc, noncePos +5);
|
||||
if (error) {
|
||||
Serial.print(F("deser nc failed: "));
|
||||
Serial.println(error.c_str());
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
JsonObject nonceObj = nonceDoc.as<JsonObject>();
|
||||
if (nonceObj.isNull()) {
|
||||
Serial.println(F("Failed nonce JSON."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
const char* sessionId = nonceObj["sid"];
|
||||
if (sessionId == nullptr) {
|
||||
Serial.println(F("No session ID found in nonce."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
uint32_t counter = nonceObj["c"] | 0;
|
||||
if (counter == 0) {
|
||||
Serial.println(F("No counter found in nonce."));
|
||||
return ERR_HMAC_GEN;
|
||||
}
|
||||
if (counter > UINT32_MAX - 100) {
|
||||
Serial.println(F("Counter too large."));
|
||||
return ERR_NONCE;
|
||||
}
|
||||
byte sidBytes[SESSION_ID_SIZE] = {};
|
||||
hexStringToByteArray(sessionId, sidBytes, SESSION_ID_SIZE);
|
||||
uint8_t nonceResult = verifyNonce(sidBytes, counter);
|
||||
|
||||
return nonceResult ? nonceResult : ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool hmacTest() {
|
||||
Serial.println(F("Testing HMAC..."));
|
||||
unsigned long start = millis();
|
||||
const char message[] = "Hello, World!";
|
||||
const char psk[] = "d0c0ffeedeadbeef";
|
||||
byte mac[SHA256HMAC_SIZE];
|
||||
hmacSign((const byte*)message, strlen(message), psk, mac);
|
||||
Serial.print(F("Took "));
|
||||
Serial.print(millis() - start);
|
||||
Serial.println(F("ms to sign message."));
|
||||
Serial.print(F("MAC: "));
|
||||
printByteArray(mac, SHA256HMAC_SIZE);
|
||||
start = millis();
|
||||
bool result = hmacVerify((const byte*)message, strlen(message), psk, mac);
|
||||
Serial.print(F("Took "));
|
||||
Serial.print(millis() - start);
|
||||
Serial.println(F("ms to verify MAC."));
|
||||
return result;
|
||||
}
|
||||
|
||||
void printDuration(unsigned long start) {
|
||||
unsigned long end = millis();
|
||||
Serial.print(F("Took "));
|
||||
Serial.print(end - start);
|
||||
Serial.println(F(" ms."));
|
||||
yield();
|
||||
}
|
||||
|
||||
#define HMAC_BENCH_ITERATIONS 100
|
||||
|
||||
void hmacBenchmark(const char* message) {
|
||||
Serial.print(F("Starting HMAC benchmark with message length:"));
|
||||
Serial.println(strlen(message));
|
||||
Serial.println(F("100 iterations signing message."));
|
||||
unsigned long start = millis();
|
||||
byte mac[SHA256HMAC_SIZE];
|
||||
for (int i = 0; i < HMAC_BENCH_ITERATIONS; i++) {
|
||||
hmacSign((const byte*)message, strlen(message), WLED_HMAC_TEST_PSK, mac);
|
||||
}
|
||||
printDuration(start);
|
||||
|
||||
Serial.println(F("100 iterations verifying message."));
|
||||
start = millis();
|
||||
for (int i = 0; i < HMAC_BENCH_ITERATIONS; i++) {
|
||||
hmacVerify((const byte*)message, strlen(message), WLED_HMAC_TEST_PSK, mac);
|
||||
}
|
||||
printDuration(start);
|
||||
}
|
||||
@@ -35,6 +35,7 @@
|
||||
--sgp: "block";
|
||||
--bmt: 0;
|
||||
--sti: 42px;
|
||||
--stp: 42px;
|
||||
}
|
||||
|
||||
html {
|
||||
@@ -468,7 +469,7 @@ button {
|
||||
padding: 4px 2px;
|
||||
position: relative;
|
||||
opacity: 1;
|
||||
transition: opacity .5s linear, height .25s, transform .25s;
|
||||
transition: opacity .25s linear, height .2s, transform .2s;
|
||||
}
|
||||
|
||||
.filter {
|
||||
@@ -1335,10 +1336,12 @@ TD .checkmark, TD .radiomark {
|
||||
top: 42px;
|
||||
}
|
||||
|
||||
#fxlist .lstI.selected,
|
||||
#pallist .lstI.selected {
|
||||
#fxlist .lstI.selected {
|
||||
top: calc(var(--sti) + 42px);
|
||||
}
|
||||
#pallist .lstI.selected {
|
||||
top: calc(var(--stp) + 42px);
|
||||
}
|
||||
|
||||
dialog::backdrop {
|
||||
backdrop-filter: blur(10px);
|
||||
@@ -1353,10 +1356,12 @@ dialog {
|
||||
color: var(--c-f);
|
||||
}
|
||||
|
||||
#fxlist .lstI.sticky,
|
||||
#pallist .lstI.sticky {
|
||||
#fxlist .lstI.sticky {
|
||||
top: var(--sti);
|
||||
}
|
||||
#pallist .lstI.sticky {
|
||||
top: var(--stp);
|
||||
}
|
||||
|
||||
/* list item content */
|
||||
.lstIcontent {
|
||||
|
||||
@@ -32,7 +32,6 @@ var cfg = {
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:false,
|
||||
css:true, hdays:false, fxdef:true, on:0, off:0, idsort: false}
|
||||
};
|
||||
var sra_lat_start = 0;
|
||||
// [year, month (0 -> January, 11 -> December), day, duration in days, image url]
|
||||
var hol = [
|
||||
[0, 11, 24, 4, "https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@@ -215,10 +214,6 @@ function loadSkinCSS(cId)
|
||||
}
|
||||
}
|
||||
|
||||
var useSRA = false;
|
||||
var sraWindow = null;
|
||||
var sraOrigin = '';
|
||||
|
||||
function getURL(path) {
|
||||
return (loc ? locproto + "//" + locip : "") + path;
|
||||
}
|
||||
@@ -248,13 +243,6 @@ 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();
|
||||
@@ -313,28 +301,6 @@ 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['mac']}`);
|
||||
// Pass the message containing the HMAC to the ESP
|
||||
requestJson(json);
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = (event) => { handleWindowMessageEvent(event) };
|
||||
|
||||
function updateTablinks(tabI)
|
||||
{
|
||||
var tablinks = gEBCN("tablinks");
|
||||
@@ -714,12 +680,6 @@ function parseInfo(i) {
|
||||
} else {
|
||||
gId("filter2D").classList.remove('hide');
|
||||
}
|
||||
|
||||
if (useSRA && i.sid) {
|
||||
if (sraWindow) {
|
||||
sraWindow.postMessage(JSON.stringify({"wled-ui":"sid","sid":i.sid}), sraOrigin);
|
||||
}
|
||||
}
|
||||
// if (i.noaudio) {
|
||||
// gId("filterVol").classList.add("hide");
|
||||
// gId("filterFreq").classList.add("hide");
|
||||
@@ -1429,9 +1389,6 @@ function makeWS() {
|
||||
ws = new WebSocket(url);
|
||||
ws.binaryType = "arraybuffer";
|
||||
ws.onmessage = (e)=>{
|
||||
sra_lat_stop = performance.now(); // end roundtrip latency measurement
|
||||
sra_lat = sra_lat_stop - sra_lat_start;
|
||||
console.log("SRA latency: "+sra_lat+" ms");
|
||||
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
||||
var json = JSON.parse(e.data);
|
||||
if (json.leds) return; // JSON liveview packet
|
||||
@@ -1447,23 +1404,6 @@ function makeWS() {
|
||||
if (isInfo) populateInfo(i);
|
||||
} else
|
||||
i = lastinfo;
|
||||
if (json.error) {
|
||||
if (json.error == 42) {
|
||||
showToast('HMAC verification failed! Please make sure you used the right password!', true);
|
||||
return;
|
||||
} else if (json.error == 43) {
|
||||
showToast("This light's control is password protected. Please access it through rc.wled.me", true);
|
||||
return;
|
||||
} else if (json.error == 41) {
|
||||
showToast('Replayed message detected!', true);
|
||||
return;
|
||||
} else if (json.error == 40) {
|
||||
showToast('Invalid nonce', true);
|
||||
return;
|
||||
}
|
||||
showToast(json.error, true);
|
||||
return;
|
||||
}
|
||||
var s = json.state ? json.state : json;
|
||||
displayRover(i, s);
|
||||
readState(s);
|
||||
@@ -1763,13 +1703,6 @@ function requestJson(command=null)
|
||||
if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes
|
||||
};
|
||||
|
||||
if (command && useSRA && !command['mac']) { // secure remote access integration, need to get HMAC from rc.wled.me
|
||||
// if we already have a command including a MAC, we are good to go
|
||||
sra_lat_start = performance.now(); // start roundtrip latency measurement
|
||||
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;
|
||||
@@ -2895,7 +2828,12 @@ function search(field, listId = null) {
|
||||
// restore default preset sorting if no search term is entered
|
||||
if (!search) {
|
||||
if (listId === 'pcont') { populatePresets(); return; }
|
||||
if (listId === 'pallist') { populatePalettes(); return; }
|
||||
if (listId === 'pallist') {
|
||||
let id = parseInt(d.querySelector('#pallist input[name="palette"]:checked').value); // preserve selected palette
|
||||
populatePalettes();
|
||||
updateSelectedPalette(id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// clear filter if searching in fxlist
|
||||
@@ -2954,18 +2892,25 @@ function initFilters() {
|
||||
|
||||
function filterFocus(e) {
|
||||
const f = gId("filters");
|
||||
if (e.type === "focus") f.classList.remove('fade'); // immediately show (still has transition)
|
||||
// compute sticky top (with delay for transition)
|
||||
setTimeout(() => {
|
||||
const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti')) + (e.type === "focus" ? 1 : -1) * f.offsetHeight;
|
||||
sCol('--sti', sti + "px");
|
||||
}, 252);
|
||||
const c = !!f.querySelectorAll("input[type=checkbox]:checked").length;
|
||||
const h = f.offsetHeight;
|
||||
const sti = parseInt(getComputedStyle(d.documentElement).getPropertyValue('--sti'));
|
||||
if (e.type === "focus") {
|
||||
// compute sticky top (with delay for transition)
|
||||
if (!h) setTimeout(() => {
|
||||
sCol('--sti', (sti+f.offsetHeight) + "px"); // has an unpleasant consequence on palette offset
|
||||
}, 255);
|
||||
f.classList.remove('fade'); // immediately show (still has transition)
|
||||
}
|
||||
if (e.type === "blur") {
|
||||
setTimeout(() => {
|
||||
if (e.target === document.activeElement && document.hasFocus()) return;
|
||||
// do not hide if filter is active
|
||||
if (gId("filters").querySelectorAll("input[type=checkbox]:checked").length) return;
|
||||
f.classList.add('fade');
|
||||
if (!c) {
|
||||
// compute sticky top
|
||||
sCol('--sti', (sti-h) + "px"); // has an unpleasant consequence on palette offset
|
||||
f.classList.add('fade');
|
||||
}
|
||||
}, 255); // wait with hiding
|
||||
}
|
||||
}
|
||||
@@ -2978,7 +2923,7 @@ function filterFx() {
|
||||
gId("fxlist").querySelectorAll('.lstI').forEach((listItem,i) => {
|
||||
const listItemName = listItem.querySelector('.lstIname').innerText;
|
||||
let hide = false;
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = true; });
|
||||
gId("filters").querySelectorAll("input[type=checkbox]").forEach((e) => { if (e.checked && !listItemName.includes(e.dataset.flt)) hide = i>0 /*true*/; });
|
||||
listItem.style.display = hide ? 'none' : '';
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
} catch (e) {}
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
//console.info("Peek uses top WS");
|
||||
ws.send('{"lv":true}');
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
//console.info("Peek WS opening");
|
||||
let l = window.location;
|
||||
@@ -80,7 +80,7 @@
|
||||
ws = new WebSocket(url+"/ws");
|
||||
ws.onopen = function () {
|
||||
//console.info("Peek WS open");
|
||||
ws.send('{"lv":true}');
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
}
|
||||
ws.binaryType = "arraybuffer";
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
ws = top.window.ws;
|
||||
} catch (e) {}
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send('{"lv":true}');
|
||||
ws.send("{'lv':true}");
|
||||
} else {
|
||||
let l = window.location;
|
||||
let pathn = l.pathname;
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
ws = new WebSocket(url+"/ws");
|
||||
ws.onopen = ()=>{
|
||||
ws.send('{"lv":true}');
|
||||
ws.send("{'lv':true}");
|
||||
}
|
||||
}
|
||||
ws.binaryType = "arraybuffer";
|
||||
|
||||
@@ -95,16 +95,6 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||
void setRandomColor(byte* rgb);
|
||||
|
||||
//crypto.cpp
|
||||
void addSessionId(byte* sid);
|
||||
char* byteArrayToHexString(char* hexString, const byte* byteArray, size_t byteLen);
|
||||
void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* signature);
|
||||
bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature);
|
||||
uint8_t verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen);
|
||||
uint8_t verifyHmacFromJsonString0Term(byte* jsonStr, size_t len);
|
||||
bool hmacTest();
|
||||
void hmacBenchmark(const char* message);
|
||||
|
||||
//dmx.cpp
|
||||
void initDMX();
|
||||
void handleDMX();
|
||||
@@ -462,7 +452,7 @@ void serveSettingsJS(AsyncWebServerRequest* request);
|
||||
//ws.cpp
|
||||
void handleWs();
|
||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len);
|
||||
void sendDataWs(AsyncWebSocketClient * client = nullptr, bool initialConnection = false);
|
||||
void sendDataWs(AsyncWebSocketClient * client = nullptr);
|
||||
|
||||
//xml.cpp
|
||||
void XML_response(Print& dest);
|
||||
|
||||
@@ -359,13 +359,6 @@ void WLED::setup()
|
||||
#if !defined(WLED_DEBUG) && defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DEBUG_HOST) && ARDUINO_USB_CDC_ON_BOOT
|
||||
Serial.setDebugOutput(false); // switch off kernel messages when using USBCDC
|
||||
#endif
|
||||
{
|
||||
//hmacTest();
|
||||
//const char testMsg[] = "WLED HMAC test!!";
|
||||
//hmacBenchmark(testMsg);
|
||||
//const char longMsg[] = "LoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIpsumLoremIps";
|
||||
//hmacBenchmark(longMsg);
|
||||
}
|
||||
DEBUG_PRINTLN();
|
||||
DEBUG_PRINTF_P(PSTR("---WLED %s %u INIT---\n"), versionString, VERSION);
|
||||
DEBUG_PRINTLN();
|
||||
|
||||
@@ -287,50 +287,18 @@ void initServer()
|
||||
bool verboseResponse = false;
|
||||
bool isConfig = false;
|
||||
|
||||
Serial.println("JSON request");
|
||||
Serial.println((const char*)request->_tempObject);
|
||||
if (!verifyHmacFromJsonString0Term((byte*)request->_tempObject, request->contentLength())) {
|
||||
//releaseJSONBufferLock();
|
||||
serveJsonError(request, 401, ERR_DENIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestJSONBufferLock(14)) {
|
||||
serveJsonError(request, 503, ERR_NOBUF);
|
||||
return;
|
||||
}
|
||||
|
||||
DeserializationError error = deserializeJson(*pDoc, (uint8_t*)(request->_tempObject));
|
||||
|
||||
// // if enabled, calculate HMAC and verify it
|
||||
// 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<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
serveJsonError(request, 400, ERR_JSON);
|
||||
return;
|
||||
}
|
||||
|
||||
// old 4-digit pin logic for settings authentication (no transport encryption)
|
||||
if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as<const char*>());
|
||||
|
||||
const String& url = request->url();
|
||||
@@ -343,11 +311,7 @@ void initServer()
|
||||
DEBUG_PRINTLN();
|
||||
#endif
|
||||
*/
|
||||
if (root.containsKey("msg")) {
|
||||
verboseResponse = deserializeState(root["msg"]);
|
||||
} else {
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
verboseResponse = deserializeState(root);
|
||||
} else {
|
||||
if (!correctPIN && strlen(settingsPIN)>0) {
|
||||
releaseJSONBufferLock();
|
||||
|
||||
@@ -11,28 +11,12 @@ unsigned long wsLastLiveTime = 0;
|
||||
|
||||
#define WS_LIVE_INTERVAL 40
|
||||
|
||||
void sendWsError(AsyncWebSocketClient * client, uint8_t error)
|
||||
{
|
||||
if (!ws.count()) return;
|
||||
|
||||
char errorStr[16];
|
||||
strcpy_P(errorStr, PSTR("{\"error\":"));
|
||||
strcpy(errorStr + 9, itoa(error, errorStr + 9, 10));
|
||||
strcat(errorStr + 10, "}");
|
||||
|
||||
if (client) {
|
||||
client->text(errorStr); // ERR_NOBUF
|
||||
} else {
|
||||
ws.textAll(errorStr); // ERR_NOBUF
|
||||
}
|
||||
}
|
||||
|
||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
||||
{
|
||||
if(type == WS_EVT_CONNECT){
|
||||
//client connected
|
||||
DEBUG_PRINTLN(F("WS client connected."));
|
||||
sendDataWs(client, true);
|
||||
sendDataWs(client);
|
||||
} else if(type == WS_EVT_DISCONNECT){
|
||||
//client disconnected
|
||||
if (client->id() == wsLiveClientId) wsLiveClientId = 0;
|
||||
@@ -52,48 +36,27 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
|
||||
bool verboseResponse = false;
|
||||
|
||||
Serial.print(F("WS message: "));
|
||||
Serial.write(data, len);
|
||||
Serial.println();
|
||||
|
||||
if (len < 11 && memcmp(data, "{\"v\":true}", 10) == 0) {
|
||||
// if the received value is just "{"v":true}", send only to this client
|
||||
verboseResponse = true;
|
||||
Serial.println(F("Simple state query."));
|
||||
} else if (len < 13 && memcmp(data, "{\"lv\":", 6) == 0) {
|
||||
wsLiveClientId = data[6] == 't' ? client->id() : 0;
|
||||
} else {
|
||||
// check HMAC, must do before parsing JSON as that modifies "data" to store strings
|
||||
uint8_t hmacVerificationResult = verifyHmacFromJsonString0Term(data, len);
|
||||
if (hmacVerificationResult != ERR_NONE) {
|
||||
sendWsError(client, hmacVerificationResult);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestJSONBufferLock(11)) {
|
||||
sendWsError(client, 3); // ERR_NOBUF
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print(F("deser input: "));
|
||||
Serial.write(data, len);
|
||||
Serial.println();
|
||||
DeserializationError error = deserializeJson(*pDoc, data, len);
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
Serial.print(F("deserializeJson() failed: "));
|
||||
Serial.println(error.c_str());
|
||||
//Serial.println(F("WS JSON parse F!"));
|
||||
sendWsError(client, 9); // ERR_JSON
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
verboseResponse = deserializeState(root["msg"]);
|
||||
|
||||
releaseJSONBufferLock();
|
||||
if (!requestJSONBufferLock(11)) {
|
||||
client->text(F("{\"error\":3}")); // ERR_NOBUF
|
||||
return;
|
||||
}
|
||||
|
||||
DeserializationError error = deserializeJson(*pDoc, data, len);
|
||||
JsonObject root = pDoc->as<JsonObject>();
|
||||
if (error || root.isNull()) {
|
||||
releaseJSONBufferLock();
|
||||
return;
|
||||
}
|
||||
if (root["v"] && root.size() == 1) {
|
||||
//if the received value is just "{"v":true}", send only to this client
|
||||
verboseResponse = true;
|
||||
} else if (root.containsKey("lv")) {
|
||||
wsLiveClientId = root["lv"] ? client->id() : 0;
|
||||
} else {
|
||||
verboseResponse = deserializeState(root);
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
|
||||
if (!interfaceUpdateCallMode) { // individual client response only needed if no WS broadcast soon
|
||||
if (verboseResponse) {
|
||||
sendDataWs(client);
|
||||
@@ -119,7 +82,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
if((info->index + len) == info->len){
|
||||
if(info->final){
|
||||
if(info->message_opcode == WS_TEXT) {
|
||||
sendWsError(client, 9); // ERR_JSON we do not handle split packets right now
|
||||
client->text(F("{\"error\":9}")); // ERR_JSON we do not handle split packets right now
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,7 +101,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
||||
}
|
||||
}
|
||||
|
||||
void sendDataWs(AsyncWebSocketClient * client, bool initialConnection)
|
||||
void sendDataWs(AsyncWebSocketClient * client)
|
||||
{
|
||||
if (!ws.count()) return;
|
||||
|
||||
@@ -157,16 +120,6 @@ void sendDataWs(AsyncWebSocketClient * client, bool initialConnection)
|
||||
JsonObject info = pDoc->createNestedObject("info");
|
||||
serializeInfo(info);
|
||||
|
||||
if (initialConnection) {
|
||||
char sid[SESSION_ID_SIZE*2+1] = {};
|
||||
byte sidBytes[SESSION_ID_SIZE] = {};
|
||||
addSessionId(sidBytes);
|
||||
byteArrayToHexString(sid, sidBytes, SESSION_ID_SIZE);
|
||||
Serial.print(F("New session ID: "));
|
||||
Serial.println(sid);
|
||||
info["sid"] = sid;
|
||||
}
|
||||
|
||||
size_t len = measureJson(*pDoc);
|
||||
DEBUG_PRINTF_P(PSTR("JSON buffer size: %u for WS request (%u).\n"), pDoc->memoryUsage(), len);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user