fix: keep stored secrets when an older UI sends them empty

Firmware and UI files update separately, so an old index.js can run
against firmware that no longer returns secrets. It sends "" for the
field it can't fill in, which cleared the WiFi passphrase (reboot into
AP mode) or the MQTT password.

The firmware now decides: "" keeps the stored secret, unless the same
request changes the SSID or MQTT username, then it clears it (open
network). /setNetwork compares the settings after applying them, so a
kept passphrase no longer triggers a reboot. The UI cache-buster moves
to 3.0.14d.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-18 20:07:31 +02:00
parent 1fb4c4cfcd
commit 9383ebec2e
6 changed files with 77 additions and 34 deletions

View file

@ -6,6 +6,7 @@
#include "ConfigSettings.h"
#include "ConfigFile.h"
#include "Utils.h"
#include "Secrets.h"
#include "SSDP.h"
#include "Somfy.h"
#include "WResp.h"
@ -781,16 +782,13 @@ void registerWebUiRoutes(AsyncWebServer &server) {
}
if(!obj["wifi"].isNull()) {
JsonObject objWifi = obj["wifi"];
if(settings.connType == conn_types_t::wifi) {
if(!objWifi["ssid"].isNull() && objWifi["ssid"].as<String>().compareTo(settings.WIFI.ssid) != 0) {
if(WiFi.softAPgetStationNum() == 0) reboot = true;
}
if(!objWifi["passphrase"].isNull() && objWifi["passphrase"].as<String>().compareTo(settings.WIFI.passphrase) != 0) {
if(WiFi.softAPgetStationNum() == 0) reboot = true;
}
}
// Compared after fromJSON, which decides whether an empty passphrase keeps the stored one.
WifiSettings before = settings.WIFI;
settings.WIFI.fromJSON(objWifi);
settings.WIFI.save();
if(settings.connType == conn_types_t::wifi && WiFi.softAPgetStationNum() == 0 &&
(strcmp(before.ssid, settings.WIFI.ssid) != 0 || strcmp(before.passphrase, settings.WIFI.passphrase) != 0))
reboot = true;
}
if(!obj["ethernet"].isNull()) {
JsonObject objEth = obj["ethernet"];
@ -833,19 +831,19 @@ void registerWebUiRoutes(AsyncWebServer &server) {
JsonObject obj = json.as<JsonObject>();
ESP_LOGD(TAG, "Settings WIFI connection...");
String ssid = "";
// Clients never receive the stored passphrase, so an omitted one keeps it.
String passphrase = settings.WIFI.passphrase;
if(!obj["ssid"].isNull()) ssid = obj["ssid"].as<String>();
if(!obj["passphrase"].isNull()) passphrase = obj["passphrase"].as<String>();
bool reboot = false;
if(ssid.compareTo(settings.WIFI.ssid) != 0) reboot = true;
if(passphrase.compareTo(settings.WIFI.passphrase) != 0) reboot = true;
bool newSsid = ssid.compareTo(settings.WIFI.ssid) != 0;
// Clients never receive the stored passphrase: an omitted or empty one keeps it unless the SSID changes.
char passphrase[sizeof(settings.WIFI.passphrase)];
SETCHARPROP(passphrase, settings.WIFI.passphrase, sizeof(passphrase));
bool newPassphrase = applySecret(obj["passphrase"].as<const char *>(), passphrase, sizeof(passphrase), newSsid);
bool reboot = newSsid || newPassphrase;
if(!settings.WIFI.ssidExists(ssid.c_str()) && ssid.length() > 0) {
request->send(400, _encoding_json, "{\"status\":\"ERROR\",\"desc\":\"WiFi Network Does not exist\"}");
}
else {
SETCHARPROP(settings.WIFI.ssid, ssid.c_str(), sizeof(settings.WIFI.ssid));
SETCHARPROP(settings.WIFI.passphrase, passphrase.c_str(), sizeof(settings.WIFI.passphrase));
SETCHARPROP(settings.WIFI.passphrase, passphrase, sizeof(settings.WIFI.passphrase));
settings.WIFI.save();
settings.WIFI.print();
request->send(201, _encoding_json, "{\"status\":\"OK\",\"desc\":\"Successfully set server connection\"}");