From 4053e31a5e80f22991bc0afe15336bf514aa02a9 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Thu, 4 Jan 2024 13:42:39 +0100 Subject: [PATCH] Prevent config corruption by checking whether memory allocation was successfull. --- include/WebApi.h | 3 +++ include/WebApi_errors.h | 1 + src/Configuration.cpp | 17 +++++++++++++++++ src/WebApi.cpp | 12 ++++++++++++ src/WebApi_device.cpp | 6 +----- src/WebApi_dtu.cpp | 5 +---- src/WebApi_inverter.cpp | 22 ++++------------------ src/WebApi_mqtt.cpp | 5 +---- src/WebApi_network.cpp | 5 +---- src/WebApi_ntp.cpp | 5 +---- src/WebApi_security.cpp | 5 +---- webapp/src/locales/de.json | 1 + webapp/src/locales/en.json | 1 + webapp/src/locales/fr.json | 1 + 14 files changed, 46 insertions(+), 43 deletions(-) diff --git a/include/WebApi.h b/include/WebApi.h index 61b9591..d8895f9 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -5,6 +5,7 @@ #include "WebApi_device.h" #include "WebApi_devinfo.h" #include "WebApi_dtu.h" +#include "WebApi_errors.h" #include "WebApi_eventlog.h" #include "WebApi_firmware.h" #include "WebApi_gridprofile.h" @@ -34,6 +35,8 @@ public: static void sendTooManyRequests(AsyncWebServerRequest* request); + static void writeConfig(JsonObject& retMsg, const WebApiError code = WebApiError::GenericSuccess, const String& message = "Settings saved!"); + private: void loop(); diff --git a/include/WebApi_errors.h b/include/WebApi_errors.h index 31ddae0..e5703a8 100644 --- a/include/WebApi_errors.h +++ b/include/WebApi_errors.h @@ -8,6 +8,7 @@ enum WebApiError { GenericDataTooLarge, GenericParseError, GenericValueMissing, + GenericWriteFailed, DtuBase = 2000, DtuSerialZero, diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 9ca9aae..7070f42 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -26,6 +26,11 @@ bool ConfigurationClass::write() DynamicJsonDocument doc(JSON_BUFFER_SIZE); + if (doc.capacity() == 0) { + MessageOutput.println("Failed to allocate memory"); + return false; + } + JsonObject cfg = doc.createNestedObject("cfg"); cfg["version"] = config.Cfg.Version; cfg["save_count"] = config.Cfg.SaveCount; @@ -151,6 +156,12 @@ bool ConfigurationClass::read() File f = LittleFS.open(CONFIG_FILENAME, "r", false); DynamicJsonDocument doc(JSON_BUFFER_SIZE); + + if (doc.capacity() == 0) { + MessageOutput.println("Failed to allocate memory"); + return false; + } + // Deserialize the JSON document const DeserializationError error = deserializeJson(doc, f); if (error) { @@ -311,6 +322,12 @@ void ConfigurationClass::migrate() } DynamicJsonDocument doc(JSON_BUFFER_SIZE); + + if (doc.capacity() == 0) { + MessageOutput.println("Failed to allocate memory"); + return; + } + // Deserialize the JSON document const DeserializationError error = deserializeJson(doc, f); if (error) { diff --git a/src/WebApi.cpp b/src/WebApi.cpp index f4aea1d..b7c85c5 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -101,4 +101,16 @@ void WebApiClass::sendTooManyRequests(AsyncWebServerRequest* request) request->send(response); } +void WebApiClass::writeConfig(JsonObject& retMsg, const WebApiError code, const String& message) +{ + if (!Configuration.write()) { + retMsg["message"] = "Write failed!"; + retMsg["code"] = WebApiError::GenericWriteFailed; + } else { + retMsg["type"] = "success"; + retMsg["message"] = message; + retMsg["code"] = code; + } +} + WebApiClass WebApi; \ No newline at end of file diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index f8f93d9..9d241df 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -175,11 +175,7 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) Display.setLanguage(config.Display.Language); Display.Diagram().updatePeriod(); - Configuration.write(); - - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index e13d9f5..6e22a63 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -154,11 +154,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as(); config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as(); config.Dtu.Cmt.Frequency = root["cmt_frequency"].as(); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index 88ddd37..dcec28c 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -167,11 +167,8 @@ void WebApiInverterClass::onInverterAdd(AsyncWebServerRequest* request) inverter->Serial = strtoll(root["serial"].as().c_str(), NULL, 16); strncpy(inverter->Name, root["name"].as().c_str(), INV_MAX_NAME_STRLEN); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Inverter created!"; - retMsg["code"] = WebApiError::InverterAdded; + WebApi.writeConfig(retMsg, WebApiError::InverterAdded, "Inverter created!"); response->setLength(); request->send(response); @@ -294,11 +291,7 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) arrayCount++; } - Configuration.write(); - - retMsg["type"] = "success"; - retMsg["code"] = WebApiError::InverterChanged; - retMsg["message"] = "Inverter changed!"; + WebApi.writeConfig(retMsg, WebApiError::InverterChanged, "Inverter changed!"); response->setLength(); request->send(response); @@ -395,11 +388,8 @@ void WebApiInverterClass::onInverterDelete(AsyncWebServerRequest* request) inverter.Serial = 0; strncpy(inverter.Name, "", sizeof(inverter.Name)); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Inverter deleted!"; - retMsg["code"] = WebApiError::InverterDeleted; + WebApi.writeConfig(retMsg, WebApiError::InverterDeleted, "Inverter deleted!"); response->setLength(); request->send(response); @@ -466,11 +456,7 @@ void WebApiInverterClass::onInverterOrder(AsyncWebServerRequest* request) order++; } - Configuration.write(); - - retMsg["type"] = "success"; - retMsg["message"] = "Inverter order saved!"; - retMsg["code"] = WebApiError::InverterOrdered; + WebApi.writeConfig(retMsg, WebApiError::InverterOrdered, "Inverter order saved!"); response->setLength(); request->send(response); diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 4290b4d..368f770 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -334,11 +334,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as(); config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as(); strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as().c_str(), sizeof(config.Mqtt.Hass.Topic)); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/src/WebApi_network.cpp b/src/WebApi_network.cpp index a6e91f3..bb6271b 100644 --- a/src/WebApi_network.cpp +++ b/src/WebApi_network.cpp @@ -238,11 +238,8 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request) } config.WiFi.ApTimeout = root["aptimeout"].as(); config.Mdns.Enabled = root["mdnsenabled"].as(); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index ed841ba..ff39762 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -179,11 +179,8 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) config.Ntp.Latitude = root["latitude"].as(); config.Ntp.Longitude = root["longitude"].as(); config.Ntp.SunsetType = root["sunsettype"].as(); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp index 274d0eb..2b5fa48 100644 --- a/src/WebApi_security.cpp +++ b/src/WebApi_security.cpp @@ -101,11 +101,8 @@ void WebApiSecurityClass::onSecurityPost(AsyncWebServerRequest* request) CONFIG_T& config = Configuration.get(); strlcpy(config.Security.Password, root["password"].as().c_str(), sizeof(config.Security.Password)); config.Security.AllowReadonly = root["allow_readonly"].as(); - Configuration.write(); - retMsg["type"] = "success"; - retMsg["message"] = "Settings saved!"; - retMsg["code"] = WebApiError::GenericSuccess; + WebApi.writeConfig(retMsg); response->setLength(); request->send(response); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 164c8fd..88cdf8a 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -39,6 +39,7 @@ "1003": "Daten zu groß!", "1004": "Fehler beim interpretieren der Daten!", "1005": "Benötigte Werte fehlen!", + "1006": "Schreiben fehlgeschlagen!", "2001": "Die Seriennummer darf nicht 0 sein!", "2002": "Das Abfraginterval muss größer als 0 sein!", "2003": "Ungültige Sendeleistung angegeben!", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 7c6a74f..a04d9c4 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -39,6 +39,7 @@ "1003": "Data too large!", "1004": "Failed to parse data!", "1005": "Values are missing!", + "1006": "Write failed!", "2001": "Serial cannot be zero!", "2002": "Poll interval must be greater zero!", "2003": "Invalid power level setting!", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 9c31ad6..e41436e 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -39,6 +39,7 @@ "1003": "Données trop importantes !", "1004": "Échec de l'analyse des données !", "1005": "Certaines valeurs sont manquantes !", + "1006": "Write failed!", "2001": "Le numéro de série ne peut pas être nul !", "2002": "L'intervalle de sondage doit être supérieur à zéro !", "2003": "Réglage du niveau de puissance invalide !",