fix: preserve web panel session across Wi-Fi reconnects
This commit is contained in:
1 parent
4aa2a3dabd
commit
0fcb010a6f
4 files changed
+62
-27
No files matched your search
@@ -108,7 +108,8 @@ Example:
|
||||
- the connection is HTTPS, but the certificate is self-signed
|
||||
- browsers will warn the first time you connect
|
||||
- the panel exposes the repeater CLI after login
|
||||
- the browser keeps the session token while changing between `/app` and `/stats`; the page switches views in place until logout, idle lock, or server restart
|
||||
- the browser keeps the session token while changing between `/app` and `/stats`; the page switches views in place until logout, idle lock, or device restart
|
||||
- brief Wi-Fi drops can interrupt in-flight page loads, but should not force a new login when the web panel restarts
|
||||
- after a device restart or reflash, the app checks the stored token before loading settings and returns to login if the session is stale
|
||||
|
||||
This is intended for local admin use on a trusted network, not for open internet exposure.
|
||||
@@ -248,7 +249,7 @@ This section includes:
|
||||
- `mqtt.owner`: owner public key.
|
||||
- `mqtt.email`: owner contact email.
|
||||
- MQTT server toggles: `eastmesh-au`, `letsmesh-eu`, `letsmesh-us`, and custom MQTT.
|
||||
- custom MQTT host, port, username, and password fields.
|
||||
- custom MQTT `host:port`, username, and password fields.
|
||||
|
||||
`UNSET - To be configured` is the default for new observer installs until a real saved value exists.
|
||||
|
||||
|
||||
@@ -1005,22 +1005,12 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
</div>
|
||||
</div>
|
||||
<div class="broker-card">
|
||||
<div class="row">
|
||||
<div class="field-card">
|
||||
<label class="label" for="mqttCustomHost">Host</label>
|
||||
<div class="inline-actions">
|
||||
<input id="mqttCustomHost" placeholder="mqtt.example.net" maxlength="95">
|
||||
<button class="iconbtn" data-load-cmd="get mqtt.custom.host" data-load-input="mqttCustomHost" title="Refresh custom MQTT host">↻</button>
|
||||
<button class="savebtn" data-prefix="set mqtt.custom.host " data-input="mqttCustomHost">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field-card">
|
||||
<label class="label" for="mqttCustomPort">Port</label>
|
||||
<div class="inline-actions">
|
||||
<input id="mqttCustomPort" inputmode="numeric" placeholder="1883" maxlength="5">
|
||||
<button class="iconbtn" data-load-cmd="get mqtt.custom.port" data-load-input="mqttCustomPort" title="Refresh custom MQTT port">↻</button>
|
||||
<button class="savebtn" data-prefix="set mqtt.custom.port " data-input="mqttCustomPort">Save</button>
|
||||
</div>
|
||||
<div class="field-card">
|
||||
<label class="label" for="mqttCustomEndpoint">Host:Port</label>
|
||||
<div class="inline-actions">
|
||||
<input id="mqttCustomEndpoint" placeholder="mqtt.xnet.wtf:1883" maxlength="101">
|
||||
<button id="refreshCustomEndpointBtn" class="iconbtn" title="Refresh custom MQTT host and port">↻</button>
|
||||
<button id="saveCustomEndpointBtn" class="savebtn">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
@@ -2325,7 +2315,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
} else if (format === "uppercase") {
|
||||
value = value.toUpperCase();
|
||||
}
|
||||
if ((inputId === "mqttCustomHost" || inputId === "mqttCustomUsername") && value === "-") {
|
||||
if (inputId === "mqttCustomUsername" && value === "-") {
|
||||
value = "";
|
||||
}
|
||||
document.getElementById(inputId).value = value;
|
||||
@@ -2492,6 +2482,43 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
if (!result.ok) return;
|
||||
setBrokerToggle(inputId, parseReplyValue(result.text));
|
||||
}
|
||||
async function loadCustomEndpoint(options = {}) {
|
||||
const hostResult = await runCommand("get mqtt.custom.host", options);
|
||||
if (!hostResult.ok) return;
|
||||
const portResult = await runCommand("get mqtt.custom.port", options);
|
||||
if (!portResult.ok) return;
|
||||
const host = parseReplyValue(hostResult.text);
|
||||
const port = parseReplyValue(portResult.text) || "1883";
|
||||
const input = document.getElementById("mqttCustomEndpoint");
|
||||
if (input) {
|
||||
input.value = host && host !== "-" ? `${host}:${port}` : "";
|
||||
}
|
||||
}
|
||||
function parseCustomEndpoint(value) {
|
||||
const endpoint = String(value || "").trim();
|
||||
const separator = endpoint.lastIndexOf(":");
|
||||
if (separator <= 0 || separator === endpoint.length - 1) return null;
|
||||
const host = endpoint.slice(0, separator).trim();
|
||||
const port = endpoint.slice(separator + 1).trim();
|
||||
if (!host || !/^[0-9]+$/.test(port)) return null;
|
||||
const portNumber = Number.parseInt(port, 10);
|
||||
if (!Number.isFinite(portNumber) || portNumber < 1 || portNumber > 65535) return null;
|
||||
return { host, port:String(portNumber) };
|
||||
}
|
||||
async function saveCustomEndpoint() {
|
||||
const input = document.getElementById("mqttCustomEndpoint");
|
||||
if (!input) return;
|
||||
const parsed = parseCustomEndpoint(input.value);
|
||||
if (!parsed) {
|
||||
statusEl.textContent = "Use host:port, for example mqtt.xnet.wtf:1883";
|
||||
return;
|
||||
}
|
||||
const hostResult = await runCommand("set mqtt.custom.host " + parsed.host);
|
||||
if (!hostResult.ok) return;
|
||||
const portResult = await runCommand("set mqtt.custom.port " + parsed.port);
|
||||
if (!portResult.ok) return;
|
||||
input.value = `${parsed.host}:${parsed.port}`;
|
||||
}
|
||||
async function loadRadioConfig(options = {}) {
|
||||
const result = await runCommand("get radio", options);
|
||||
if (!result.ok) {
|
||||
@@ -2669,6 +2696,8 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
setCustomMqttMode((Number.parseInt(customMqttModeSlider.value, 10) || 0) >= 1);
|
||||
});
|
||||
}
|
||||
document.getElementById("refreshCustomEndpointBtn").onclick = () => loadCustomEndpoint();
|
||||
document.getElementById("saveCustomEndpointBtn").onclick = () => saveCustomEndpoint();
|
||||
async function setLetsmeshMode(mode) {
|
||||
const eastmesh = document.getElementById("mqttEastmeshAu");
|
||||
if (mode === "both" && eastmesh && eastmesh.checked) {
|
||||
@@ -2859,8 +2888,7 @@ const char kWebPanelAppHtml[] PROGMEM = R"HTML(
|
||||
() => loadBrokerState("get mqtt.letsmesh-eu", "mqttLetsmeshEu", quiet),
|
||||
() => loadBrokerState("get mqtt.letsmesh-us", "mqttLetsmeshUs", quiet),
|
||||
() => loadBrokerState("get mqtt.custom", "mqttCustom", quiet),
|
||||
() => loadField("get mqtt.custom.host", "mqttCustomHost", null, quiet),
|
||||
() => loadField("get mqtt.custom.port", "mqttCustomPort", null, quiet),
|
||||
() => loadCustomEndpoint(quiet),
|
||||
() => loadField("get mqtt.custom.username", "mqttCustomUsername", null, quiet)
|
||||
]);
|
||||
if (!isCurrentPageLoad(generation)) return;
|
||||
@@ -2966,7 +2994,7 @@ bool WebPanelServer::start() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WebPanelServer::stop() {
|
||||
void WebPanelServer::stop(bool clear_session) {
|
||||
stopRedirectServer();
|
||||
if (_server != nullptr) {
|
||||
httpd_handle_t server = _server;
|
||||
@@ -2974,8 +3002,10 @@ void WebPanelServer::stop() {
|
||||
WEB_PANEL_LOG("server stopped");
|
||||
httpd_ssl_stop(server);
|
||||
}
|
||||
_token[0] = 0;
|
||||
_last_activity_ms = 0;
|
||||
if (clear_session) {
|
||||
_token[0] = 0;
|
||||
_last_activity_ms = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool WebPanelServer::isRunning() const {
|
||||
@@ -3242,7 +3272,7 @@ bool WebPanelServer::start() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebPanelServer::stop() {
|
||||
void WebPanelServer::stop(bool) {
|
||||
}
|
||||
|
||||
void WebPanelServer::stopRedirectServer() {
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
|
||||
void setCommandRunner(WebPanelCommandRunner* runner);
|
||||
bool start();
|
||||
void stop();
|
||||
void stop(bool clear_session = true);
|
||||
void stopRedirectServer();
|
||||
bool isRunning() const;
|
||||
bool hasSessionToken() const;
|
||||
|
||||
@@ -104,10 +104,14 @@ void WebService::ensureWebServer() {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_runner == nullptr || _prefs.web_enabled == 0 || _network == nullptr || !_network->isWifiConnected()) {
|
||||
if (_runner == nullptr || _prefs.web_enabled == 0) {
|
||||
_panel.stop();
|
||||
return;
|
||||
}
|
||||
if (_network == nullptr || !_network->isWifiConnected()) {
|
||||
_panel.stop(false);
|
||||
return;
|
||||
}
|
||||
if (_panel.isRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user