Harden web UI auth, input handling, and SD path validation

- Add optional Basic Auth with NVS-backed credentials and STA/AP flags; protect status, wifi, history, and download routes

- Stop pre-filling WiFi/MQTT/Web UI password fields; keep stored secrets on blank and add clear-password checkboxes

- Add HTML escaping + URL encoding helpers and apply to user-controlled strings; add unit test

- Harden /sd/download path validation (prefix, length, dotdot, slashes) and log rejections

- Enforce protocol version in LoRa receive and release GPIO14 before SD init

- Update README security, SD, and GPIO sharing notes
This commit is contained in:
2026-02-02 21:07:37 +01:00
parent b5477262ea
commit 0e12b406de
10 changed files with 260 additions and 30 deletions

49
src/html_util.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "html_util.h"
String html_escape(const String &input) {
String out;
out.reserve(input.length() + 8);
for (size_t i = 0; i < input.length(); ++i) {
char c = input[i];
switch (c) {
case '&':
out += "&amp;";
break;
case '<':
out += "&lt;";
break;
case '>':
out += "&gt;";
break;
case '"':
out += "&quot;";
break;
case '\'':
out += "&#39;";
break;
default:
out += c;
break;
}
}
return out;
}
String url_encode_component(const String &input) {
String out;
out.reserve(input.length() * 3);
const char *hex = "0123456789ABCDEF";
for (size_t i = 0; i < input.length(); ++i) {
unsigned char c = static_cast<unsigned char>(input[i]);
bool safe = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~';
if (safe) {
out += static_cast<char>(c);
} else {
out += '%';
out += hex[(c >> 4) & 0x0F];
out += hex[c & 0x0F];
}
}
return out;
}