Add admin firmware upload support

Implement authenticated HTTPS OTA uploads with bounded streaming, image
validation, reboot coordination, and lifecycle exclusion. Add the admin
UI,
regression tests, and Phase 10 acceptance documentation.
This commit is contained in:
2026-09-18 22:22:11 +02:00
parent 4f628a4098
commit 31a22eba06
31 changed files with 1442 additions and 88 deletions
+31
View File
@@ -31,6 +31,7 @@
#include "web_broker_settings.h"
#include "web_ssh_settings.h"
#include "web_lifecycle_settings.h"
#include "web_firmware_update.h"
#include "web_admin_transport.h"
#include "web_session_store.h"
#include "web_cookie_auth.h"
@@ -573,6 +574,12 @@ static const httpd_uri_t s_logo_uri = {
.user_ctx = (void *)(uintptr_t)WEB_UI_RESOURCE_LOGO_PNG,
};
static const httpd_uri_t s_firmware_uri = {
.uri = WEB_FIRMWARE_UPDATE_URI,
.method = HTTP_POST,
.handler = web_firmware_update_handler,
};
static const httpd_uri_t *const s_uri_handlers[] = {
&s_root_uri,
&s_status_uri,
@@ -583,6 +590,7 @@ static const httpd_uri_t *const s_uri_handlers[] = {
&s_addon_fit_js_uri,
&s_app_js_uri,
&s_logo_uri,
&s_firmware_uri,
};
static const httpd_uri_t s_auth_uris[] = {
@@ -944,6 +952,29 @@ esp_err_t web_server_restart_current(uint32_t expected_generation)
return stop_server(expected_generation, true, false);
}
/* The upload retains the existing lifecycle fence, not the mutex. This also
* excludes canonical stop/start and service-coordinated identity replacement. */
esp_err_t web_firmware_update_reserve(httpd_handle_t server)
{
if (!s_server_mutex || xSemaphoreTake(s_server_mutex, 0U) != pdTRUE)
return ESP_ERR_INVALID_STATE;
if (!server || s_server != server || s_transitioning || s_last_error != ESP_OK) {
xSemaphoreGive(s_server_mutex);
return ESP_ERR_INVALID_STATE;
}
s_transitioning = true;
if (s_generation != UINT32_MAX) ++s_generation;
xSemaphoreGive(s_server_mutex);
return ESP_OK;
}
void web_firmware_update_release(void)
{
xSemaphoreTake(s_server_mutex, portMAX_DELAY);
s_transitioning = false;
xSemaphoreGive(s_server_mutex);
}
esp_err_t web_server_reboot_current(uint32_t expected_generation)
{
if (!expected_generation) return ESP_ERR_INVALID_ARG;