From 2093ce8665366ce056d5ee5894e52c3445287233 Mon Sep 17 00:00:00 2001 From: Markus Frey Date: Tue, 15 Oct 2019 09:28:10 +0200 Subject: [PATCH] Optimize JSON code * Simplify JSON lookups * Remove unnecessary lookups * Add null checks for JSON strings before calling strlen() --- src/Homie/Boot/BootConfig.cpp | 8 +- src/Homie/Config.cpp | 139 +++------- src/Homie/Utils/Validation.cpp | 462 +++++++++++++++++++-------------- 3 files changed, 317 insertions(+), 292 deletions(-) diff --git a/src/Homie/Boot/BootConfig.cpp b/src/Homie/Boot/BootConfig.cpp index 34c91afa..d3cc1f53 100644 --- a/src/Homie/Boot/BootConfig.cpp +++ b/src/Homie/Boot/BootConfig.cpp @@ -129,13 +129,15 @@ void BootConfig::_onWifiConnectRequest(AsyncWebServerRequest *request) { } JsonObject parsedJson = parseJsonDoc.as(); - if (!parsedJson.containsKey("ssid") || !parsedJson["ssid"].is() || !parsedJson.containsKey("password") || !parsedJson["password"].is()) { + JsonVariant wifiSsid = parsedJson["ssid"]; + JsonVariant wifiPassword = parsedJson["password"]; + if (!wifiSsid.as() || !wifiPassword.is()) { __SendJSONError(request, F("✖ SSID and password required")); return; } Interface::get().getLogger() << F("Connecting to Wi-Fi") << endl; - WiFi.begin(parsedJson["ssid"].as(), parsedJson["password"].as()); + WiFi.begin(wifiSsid.as(), wifiPassword.as()); request->send(202, FPSTR(PROGMEM_CONFIG_APPLICATION_JSON), FPSTR(PROGMEM_CONFIG_JSON_SUCCESS)); } @@ -190,7 +192,7 @@ void BootConfig::_onProxyControlRequest(AsyncWebServerRequest *request) { } JsonObject parsedJson = parseJsonDoc.as(); - if (!parsedJson.containsKey("enable") || !parsedJson["enable"].is()) { + if (!parsedJson["enable"].is()) { __SendJSONError(request, F("✖ enable parameter is required")); return; } diff --git a/src/Homie/Config.cpp b/src/Homie/Config.cpp index 87735702..ce98fdde 100644 --- a/src/Homie/Config.cpp +++ b/src/Homie/Config.cpp @@ -62,82 +62,35 @@ bool Config::load() { return false; } - const char* reqName = parsedJson["name"]; - const char* reqWifiSsid = parsedJson["wifi"]["ssid"]; - const char* reqWifiPassword = parsedJson["wifi"]["password"]; - - const char* reqMqttHost = parsedJson["mqtt"]["host"]; - const char* reqDeviceId = DeviceId::get(); - if (parsedJson.containsKey("device_id")) { - reqDeviceId = parsedJson["device_id"]; - } - uint16_t regDeviceStatsInterval = STATS_SEND_INTERVAL_SEC; //device_stats_interval - if (parsedJson.containsKey(F("device_stats_interval"))) { - regDeviceStatsInterval = parsedJson[F("device_stats_interval")]; - } - - const char* reqWifiBssid = ""; - if (parsedJson["wifi"].as().containsKey("bssid")) { - reqWifiBssid = parsedJson["wifi"]["bssid"]; - } - uint16_t reqWifiChannel = 0; - if (parsedJson["wifi"].as().containsKey("channel")) { - reqWifiChannel = parsedJson["wifi"]["channel"]; - } - const char* reqWifiIp = ""; - if (parsedJson["wifi"].as().containsKey("ip")) { - reqWifiIp = parsedJson["wifi"]["ip"]; - } - const char* reqWifiMask = ""; - if (parsedJson["wifi"].as().containsKey("mask")) { - reqWifiMask = parsedJson["wifi"]["mask"]; - } - const char* reqWifiGw = ""; - if (parsedJson["wifi"].as().containsKey("gw")) { - reqWifiGw = parsedJson["wifi"]["gw"]; - } - const char* reqWifiDns1 = ""; - if (parsedJson["wifi"].as().containsKey("dns1")) { - reqWifiDns1 = parsedJson["wifi"]["dns1"]; - } - const char* reqWifiDns2 = ""; - if (parsedJson["wifi"].as().containsKey("dns2")) { - reqWifiDns2 = parsedJson["wifi"]["dns2"]; - } - - uint16_t reqMqttPort = DEFAULT_MQTT_PORT; - if (parsedJson["mqtt"].as().containsKey("port")) { - reqMqttPort = parsedJson["mqtt"]["port"]; - } - bool reqMqttSsl = false; - if (parsedJson["mqtt"].as().containsKey("ssl")) { - reqMqttSsl = parsedJson["mqtt"]["ssl"]; - } - const char* reqMqttFingerprint = ""; - if (parsedJson["mqtt"].as().containsKey("ssl_fingerprint")) { - reqMqttFingerprint = parsedJson["mqtt"]["ssl_fingerprint"]; - } - const char* reqMqttBaseTopic = DEFAULT_MQTT_BASE_TOPIC; - if (parsedJson["mqtt"].as().containsKey("base_topic")) { - reqMqttBaseTopic = parsedJson["mqtt"]["base_topic"]; - } - bool reqMqttAuth = false; - if (parsedJson["mqtt"].as().containsKey("auth")) { - reqMqttAuth = parsedJson["mqtt"]["auth"]; - } - const char* reqMqttUsername = ""; - if (parsedJson["mqtt"].as().containsKey("username")) { - reqMqttUsername = parsedJson["mqtt"]["username"]; - } - const char* reqMqttPassword = ""; - if (parsedJson["mqtt"].as().containsKey("password")) { - reqMqttPassword = parsedJson["mqtt"]["password"]; - } + /* Mandatory config items */ + JsonObject reqWifi = parsedJson["wifi"]; + JsonObject reqMqtt = parsedJson["mqtt"]; - bool reqOtaEnabled = false; - if (parsedJson["ota"].as().containsKey("enabled")) { - reqOtaEnabled = parsedJson["ota"]["enabled"]; - } + const char* reqName = parsedJson["name"]; + const char* reqWifiSsid = reqWifi["ssid"]; + const char* reqWifiPassword = reqWifi["password"]; + const char* reqMqttHost = reqMqtt["host"]; + + /* Optional config items */ + const char* reqDeviceId = parsedJson["device_id"] | DeviceId::get(); + uint16_t regDeviceStatsInterval = parsedJson["device_stats_interval"] | STATS_SEND_INTERVAL_SEC; + bool reqOtaEnabled = parsedJson["ota"]["enabled"] | false; + + uint16_t reqWifiChannel = reqWifi["channel"] | 0; + const char* reqWifiBssid = reqWifi["bssid"] | ""; + const char* reqWifiIp = reqWifi["ip"] | ""; + const char* reqWifiMask = reqWifi["mask"] | ""; + const char* reqWifiGw = reqWifi["gw"] | ""; + const char* reqWifiDns1 = reqWifi["dns1"] | ""; + const char* reqWifiDns2 = reqWifi["dns2"] | ""; + + uint16_t reqMqttPort = reqMqtt["port"] | DEFAULT_MQTT_PORT; + bool reqMqttSsl = reqMqtt["ssl"] | false; + bool reqMqttAuth = reqMqtt["auth"] | false; + const char* reqMqttUsername = reqMqtt["username"] | ""; + const char* reqMqttPassword = reqMqtt["password"] | ""; + const char* reqMqttFingerprint = reqMqtt["ssl_fingerprint"] | ""; + const char* reqMqttBaseTopic = reqMqtt["base_topic"] | DEFAULT_MQTT_BASE_TOPIC; strlcpy(_configStruct.name, reqName, MAX_FRIENDLY_NAME_LENGTH); strlcpy(_configStruct.deviceId, reqDeviceId, MAX_DEVICE_ID_LENGTH); @@ -171,29 +124,21 @@ bool Config::load() { JsonObject settingsObject = parsedJson["settings"].as(); for (IHomieSetting* iSetting : IHomieSetting::settings) { - if (iSetting->isBool()) { - HomieSetting* setting = static_cast*>(iSetting); - - if (settingsObject.containsKey(setting->getName())) { - setting->set(settingsObject[setting->getName()].as()); - } - } else if (iSetting->isLong()) { - HomieSetting* setting = static_cast*>(iSetting); - - if (settingsObject.containsKey(setting->getName())) { - setting->set(settingsObject[setting->getName()].as()); - } - } else if (iSetting->isDouble()) { - HomieSetting* setting = static_cast*>(iSetting); - - if (settingsObject.containsKey(setting->getName())) { - setting->set(settingsObject[setting->getName()].as()); - } - } else if (iSetting->isConstChar()) { - HomieSetting* setting = static_cast*>(iSetting); + JsonVariant reqSetting = settingsObject[iSetting->getName()]; - if (settingsObject.containsKey(setting->getName())) { - setting->set(strdup(settingsObject[setting->getName()].as())); + if (!reqSetting.isNull()) { + if (iSetting->isBool()) { + HomieSetting* setting = static_cast*>(iSetting); + setting->set(reqSetting.as()); + } else if (iSetting->isLong()) { + HomieSetting* setting = static_cast*>(iSetting); + setting->set(reqSetting.as()); + } else if (iSetting->isDouble()) { + HomieSetting* setting = static_cast*>(iSetting); + setting->set(reqSetting.as()); + } else if (iSetting->isConstChar()) { + HomieSetting* setting = static_cast*>(iSetting); + setting->set(strdup(reqSetting.as())); } } } diff --git a/src/Homie/Utils/Validation.cpp b/src/Homie/Utils/Validation.cpp index 0ea36573..713b58cc 100644 --- a/src/Homie/Utils/Validation.cpp +++ b/src/Homie/Utils/Validation.cpp @@ -22,35 +22,49 @@ ConfigValidationResult Validation::validateConfig(const JsonObject object) { ConfigValidationResult Validation::_validateConfigRoot(const JsonObject object) { ConfigValidationResult result; result.valid = false; - if (!object.containsKey("name") || !object["name"].is()) { - result.reason = F("name is not a string"); - return result; - } - if (strlen(object["name"]) + 1 > MAX_FRIENDLY_NAME_LENGTH) { - result.reason = F("name is too long"); - return result; - } - if (object.containsKey("device_id")) { - if (!object["device_id"].is()) { - result.reason = F("device_id is not a string"); + + { + JsonVariant name = object["name"]; + + if (!name.as()) { + result.reason = F("name is not a string"); return result; } - if (strlen(object["device_id"]) + 1 > MAX_DEVICE_ID_LENGTH) { - result.reason = F("device_id is too long"); + if (strlen(name.as()) + 1 > MAX_FRIENDLY_NAME_LENGTH) { + result.reason = F("name is too long"); + return result; + } + + if (strcmp_P(name.as(), PSTR("")) == 0) { + result.reason = F("name is empty"); return result; } } - const char* name = object["name"]; + { + JsonVariant deviceId = object["device_id"]; - if (strcmp_P(name, PSTR("")) == 0) { - result.reason = F("name is empty"); - return result; + if (!deviceId.isNull()) { + if (!deviceId.as()) { + result.reason = F("device_id is not a string"); + return result; + } + if (strlen(deviceId.as()) + 1 > MAX_DEVICE_ID_LENGTH) { + result.reason = F("device_id is too long"); + return result; + } + } } - if (object.containsKey(F("device_stats_interval")) && !object[F("device_stats_interval")].is()) { - result.reason = F("device_stats_interval is not an integer"); - return result; + { + JsonVariant deviceStatsInterval = object["device_stats_interval"]; + + if (!deviceStatsInterval.isNull()) { + if (!deviceStatsInterval.is()) { + result.reason = F("device_stats_interval is not an integer"); + return result; + } + } } result.valid = true; @@ -61,119 +75,152 @@ ConfigValidationResult Validation::_validateConfigWifi(const JsonObject object) ConfigValidationResult result; result.valid = false; - if (!object.containsKey("wifi") || !object["wifi"].is()) { + JsonVariant wifi = object["wifi"]; + + if (!wifi.is()) { result.reason = F("wifi is not an object"); return result; } - if (!object["wifi"].as().containsKey("ssid") || !object["wifi"]["ssid"].is()) { - result.reason = F("wifi.ssid is not a string"); - return result; - } - if (strlen(object["wifi"]["ssid"]) + 1 > MAX_WIFI_SSID_LENGTH) { - result.reason = F("wifi.ssid is too long"); - return result; - } - if (!object["wifi"].as().containsKey("password") || !object["wifi"]["password"].is()) { - result.reason = F("wifi.password is not a string"); - return result; - } - if (object["wifi"]["password"] && strlen(object["wifi"]["password"]) + 1 > MAX_WIFI_PASSWORD_LENGTH) { - result.reason = F("wifi.password is too long"); - return result; - } - // by benzino - if (object["wifi"].as().containsKey("bssid") && !object["wifi"]["bssid"].is()) { - result.reason = F("wifi.bssid is not a string"); - return result; - } - if ((object["wifi"].as().containsKey("bssid") && !object["wifi"].as().containsKey("channel")) || - (!object["wifi"].as().containsKey("bssid") && object["wifi"].as().containsKey("channel"))) { - result.reason = F("wifi.channel_bssid channel and BSSID is required"); - return result; - } - if (object["wifi"].as().containsKey("bssid") && !Helpers::validateMacAddress(object["wifi"].as().getMember("bssid").as())) { - result.reason = F("wifi.bssid is not valid mac"); - return result; - } - if (object["wifi"].as().containsKey("channel") && !object["wifi"]["channel"].is()) { - result.reason = F("wifi.channel is not an integer"); - return result; - } - if (object["wifi"].as().containsKey("ip") && !object["wifi"]["ip"].is()) { - result.reason = F("wifi.ip is not a string"); - return result; - } - if (object["wifi"]["ip"] && strlen(object["wifi"]["ip"]) + 1 > MAX_IP_STRING_LENGTH) { - result.reason = F("wifi.ip is too long"); - return result; - } - if (object["wifi"]["ip"] && !Helpers::validateIP(object["wifi"].as().getMember("ip").as())) { - result.reason = F("wifi.ip is not valid ip address"); - return result; - } - if (object["wifi"].as().containsKey("mask") && !object["wifi"]["mask"].is()) { - result.reason = F("wifi.mask is not a string"); - return result; - } - if (object["wifi"]["mask"] && strlen(object["wifi"]["mask"]) + 1 > MAX_IP_STRING_LENGTH) { - result.reason = F("wifi.mask is too long"); - return result; - } - if (object["wifi"]["mask"] && !Helpers::validateIP(object["wifi"].as().getMember("mask").as())) { - result.reason = F("wifi.mask is not valid mask"); - return result; - } - if (object["wifi"].as().containsKey("gw") && !object["wifi"]["gw"].is()) { - result.reason = F("wifi.gw is not a string"); - return result; - } - if (object["wifi"]["gw"] && strlen(object["wifi"]["gw"]) + 1 > MAX_IP_STRING_LENGTH) { - result.reason = F("wifi.gw is too long"); - return result; - } - if (object["wifi"]["gw"] && !Helpers::validateIP(object["wifi"].as().getMember("gw").as())) { - result.reason = F("wifi.gw is not valid gateway address"); - return result; - } - if ((object["wifi"].as().containsKey("ip") && (!object["wifi"].as().containsKey("mask") || !object["wifi"].as().containsKey("gw"))) || - (object["wifi"].as().containsKey("gw") && (!object["wifi"].as().containsKey("mask") || !object["wifi"].as().containsKey("ip"))) || - (object["wifi"].as().containsKey("mask") && (!object["wifi"].as().containsKey("ip") || !object["wifi"].as().containsKey("gw")))) { - result.reason = F("wifi.staticip ip, gw and mask is required"); - return result; - } - if (object["wifi"].as().containsKey("dns1") && !object["wifi"]["dns1"].is()) { - result.reason = F("wifi.dns1 is not a string"); - return result; - } - if (object["wifi"]["dns1"] && strlen(object["wifi"]["dns1"]) + 1 > MAX_IP_STRING_LENGTH) { - result.reason = F("wifi.dns1 is too long"); - return result; - } - if (object["wifi"]["dns1"] && !Helpers::validateIP(object["wifi"].as().getMember("dns1").as())) { - result.reason = F("wifi.dns1 is not valid dns address"); - return result; - } - if (object["wifi"].as().containsKey("dns2") && !object["wifi"].as().containsKey("dns1")) { - result.reason = F("wifi.dns2 no dns1 defined"); - return result; + + { + JsonVariant wifiSsid = wifi["ssid"]; + + if (!wifiSsid.as()) { + result.reason = F("wifi.ssid is not a string"); + return result; + } + if (strlen(wifiSsid.as()) + 1 > MAX_WIFI_SSID_LENGTH) { + result.reason = F("wifi.ssid is too long"); + return result; + } + if (strcmp_P(wifiSsid.as(), PSTR("")) == 0) { + result.reason = F("wifi.ssid is empty"); + return result; + } } - if (object["wifi"].as().containsKey("dns2") && !object["wifi"]["dns2"].is()) { - result.reason = F("wifi.dns2 is not a string"); - return result; + + { + JsonVariant wifiPassword = wifi["password"]; + + if (!wifiPassword.is()) { + result.reason = F("wifi.password is not a string"); + return result; + } + if (wifiPassword.as() && strlen(wifiPassword.as()) + 1 > MAX_WIFI_PASSWORD_LENGTH) { + result.reason = F("wifi.password is too long"); + return result; + } } - if (object["wifi"]["dns2"] && strlen(object["wifi"]["dns2"]) + 1 > MAX_IP_STRING_LENGTH) { - result.reason = F("wifi.dns2 is too long"); - return result; + + { + JsonVariant wifiBssid = wifi["bssid"]; + JsonVariant wifiChannel = wifi["channel"]; + + if ((wifiBssid.isNull() || wifiChannel.isNull()) != (wifiBssid.isNull() && wifiChannel.isNull())) { + result.reason = F("wifi.channel_bssid channel and BSSID is required"); + return result; + } + if (!wifiBssid.isNull()) { + if (!wifiBssid.as()) { + result.reason = F("wifi.bssid is not a string"); + return result; + } + if (!Helpers::validateMacAddress(wifiBssid.as())) { + result.reason = F("wifi.bssid is not valid mac"); + return result; + } + if (!wifiChannel.is()) { + result.reason = F("wifi.channel is not an integer"); + return result; + } + } } - if (object["wifi"]["dns2"] && !Helpers::validateIP(object["wifi"].as().getMember("dns2").as())) { - result.reason = F("wifi.dns2 is not valid dns address"); - return result; + + { + JsonVariant wifiIp = wifi["ip"]; + JsonVariant wifiMask = wifi["mask"]; + JsonVariant wifiGw = wifi["gw"]; + + if ((wifiIp.isNull() || wifiMask.isNull() || wifiGw.isNull()) != (wifiIp.isNull() && wifiMask.isNull() && wifiGw.isNull())) { + result.reason = F("wifi.staticip ip, gw and mask is required"); + return result; + } + if (!wifiIp.isNull()) { + if (!wifiIp.as()) { + result.reason = F("wifi.ip is not a string"); + return result; + } + if (strlen(wifiIp.as()) + 1 > MAX_IP_STRING_LENGTH) { + result.reason = F("wifi.ip is too long"); + return result; + } + if (!Helpers::validateIP(wifiIp.as())) { + result.reason = F("wifi.ip is not valid ip address"); + return result; + } + if (!wifiMask.as()) { + result.reason = F("wifi.mask is not a string"); + return result; + } + if (strlen(wifiMask.as()) + 1 > MAX_IP_STRING_LENGTH) { + result.reason = F("wifi.mask is too long"); + return result; + } + if (!Helpers::validateIP(wifiMask.as())) { + result.reason = F("wifi.mask is not valid mask"); + return result; + } + if (!wifiGw.as()) { + result.reason = F("wifi.gw is not a string"); + return result; + } + if (strlen(wifiGw.as()) + 1 > MAX_IP_STRING_LENGTH) { + result.reason = F("wifi.gw is too long"); + return result; + } + if (!Helpers::validateIP(wifiGw.as())) { + result.reason = F("wifi.gw is not valid gateway address"); + return result; + } + } } - const char* wifiSsid = object["wifi"]["ssid"]; - if (strcmp_P(wifiSsid, PSTR("")) == 0) { - result.reason = F("wifi.ssid is empty"); - return result; + { + JsonVariant wifiDns1 = wifi["dns1"]; + JsonVariant wifiDns2 = wifi["dns2"]; + + if (!wifiDns1.isNull()) { + if (wifiDns1.as()) { + result.reason = F("wifi.dns1 is not a string"); + return result; + } + if (strlen(wifiDns1.as()) + 1 > MAX_IP_STRING_LENGTH) { + result.reason = F("wifi.dns1 is too long"); + return result; + } + if (!Helpers::validateIP(wifiDns1.as())) { + result.reason = F("wifi.dns1 is not valid dns address"); + return result; + } + } + if (!wifiDns2.isNull()) { + if (wifiDns2.as()) { + result.reason = F("wifi.dns2 is not a string"); + return result; + } + if (strlen(wifiDns2.as()) + 1 > MAX_IP_STRING_LENGTH) { + result.reason = F("wifi.dns2 is too long"); + return result; + } + if (!Helpers::validateIP(wifiDns2.as())) { + result.reason = F("wifi.dns2 is not valid dns address"); + return result; + } + if (wifiDns1.isNull()) { + result.reason = F("wifi.dns2 no dns1 defined"); + return result; + } + } } result.valid = true; @@ -184,80 +231,106 @@ ConfigValidationResult Validation::_validateConfigMqtt(const JsonObject object) ConfigValidationResult result; result.valid = false; - if (!object.containsKey("mqtt") || !object["mqtt"].is()) { + JsonVariant mqtt = object["mqtt"]; + + if (!mqtt.is()) { result.reason = F("mqtt is not an object"); return result; } - if (!object["mqtt"].as().containsKey("host") || !object["mqtt"]["host"].is()) { - result.reason = F("mqtt.host is not a string"); - return result; - } - if (strlen(object["mqtt"]["host"]) + 1 > MAX_HOSTNAME_LENGTH) { - result.reason = F("mqtt.host is too long"); - return result; - } - if (object["mqtt"].as().containsKey("port") && !object["mqtt"]["port"].is()) { - result.reason = F("mqtt.port is not an integer"); - return result; - } - if (object["mqtt"].as().containsKey("ssl")) { - if (!object["mqtt"]["ssl"].is()) { - result.reason = F("mqtt.ssl is not a bool"); + + { + JsonVariant mqttHost = mqtt["host"]; + + if (!mqttHost.as()) { + result.reason = F("mqtt.host is not a string"); return result; } - } - if (object["mqtt"].as().containsKey("ssl_fingerprint")) { - if (!object["mqtt"]["ssl_fingerprint"].is()) { - result.reason = F("mqtt.ssl_fingerprint is not a string"); + if (strlen(mqttHost.as()) + 1 > MAX_HOSTNAME_LENGTH) { + result.reason = F("mqtt.host is too long"); return result; } - - if (strlen(object["mqtt"]["ssl_fingerprint"]) > MAX_FINGERPRINT_SIZE * 2) { - result.reason = F("mqtt.ssl_fingerprint is too long"); + if (strcmp_P(mqttHost.as(), PSTR("")) == 0) { + result.reason = F("mqtt.host is empty"); return result; } } - if (object["mqtt"].as().containsKey("base_topic")) { - if (!object["mqtt"]["base_topic"].is()) { - result.reason = F("mqtt.base_topic is not a string"); - return result; - } - if (strlen(object["mqtt"]["base_topic"]) + 1 > MAX_MQTT_BASE_TOPIC_LENGTH) { - result.reason = F("mqtt.base_topic is too long"); + { + JsonVariant mqttPort = mqtt["port"]; + + if (!mqttPort.isNull() && !mqttPort.is()) { + result.reason = F("mqtt.port is not an integer"); return result; } } - if (object["mqtt"].as().containsKey("auth")) { - if (!object["mqtt"]["auth"].is()) { - result.reason = F("mqtt.auth is not a boolean"); + + { + JsonVariant mqttSsl = mqtt["ssl"]; + if (!mqttSsl.isNull() && !mqttSsl.is()) { + result.reason = F("mqtt.ssl is not a bool"); return result; } + } - if (object["mqtt"]["auth"]) { - if (!object["mqtt"].as().containsKey("username") || !object["mqtt"]["username"].is()) { - result.reason = F("mqtt.username is not a string"); + { + JsonVariant mqttSslFingerprint = mqtt["ssl_fingerprint"]; + if (!mqttSslFingerprint.isNull()) { + if (!mqttSslFingerprint.as()) { + result.reason = F("mqtt.ssl_fingerprint is not a string"); return result; } - if (strlen(object["mqtt"]["username"]) + 1 > MAX_MQTT_CREDS_LENGTH) { - result.reason = F("mqtt.username is too long"); + if (strlen(mqttSslFingerprint.as()) > MAX_FINGERPRINT_SIZE * 2) { + result.reason = F("mqtt.ssl_fingerprint is too long"); return result; } - if (!object["mqtt"].as().containsKey("password") || !object["mqtt"]["password"].is()) { - result.reason = F("mqtt.password is not a string"); + } + } + + { + JsonVariant mqttBaseTopic = mqtt["base_topic"]; + if (!mqttBaseTopic.isNull()) { + if (!mqttBaseTopic.as()) { + result.reason = F("mqtt.base_topic is not a string"); return result; } - if (strlen(object["mqtt"]["password"]) + 1 > MAX_MQTT_CREDS_LENGTH) { - result.reason = F("mqtt.password is too long"); + if (strlen(mqttBaseTopic.as()) + 1 > MAX_MQTT_BASE_TOPIC_LENGTH) { + result.reason = F("mqtt.base_topic is too long"); return result; } } } - const char* host = object["mqtt"]["host"]; - if (strcmp_P(host, PSTR("")) == 0) { - result.reason = F("mqtt.host is empty"); - return result; + { + JsonVariant mqttAuth = mqtt["auth"]; + + if (!mqttAuth.isNull()) { + if (!mqttAuth.is()) { + result.reason = F("mqtt.auth is not a boolean"); + return result; + } + + if (mqttAuth.as()) { + JsonVariant mqttUsername = mqtt["username"]; + JsonVariant mqttPassword = mqtt["password"]; + + if (!mqttUsername.as()) { + result.reason = F("mqtt.username is not a string"); + return result; + } + if (strlen(mqttUsername.as()) + 1 > MAX_MQTT_CREDS_LENGTH) { + result.reason = F("mqtt.username is too long"); + return result; + } + if (!mqttPassword.as()) { + result.reason = F("mqtt.password is not a string"); + return result; + } + if (strlen(mqttPassword.as()) + 1 > MAX_MQTT_CREDS_LENGTH) { + result.reason = F("mqtt.password is too long"); + return result; + } + } + } } result.valid = true; @@ -268,13 +341,20 @@ ConfigValidationResult Validation::_validateConfigOta(const JsonObject object) { ConfigValidationResult result; result.valid = false; - if (!object.containsKey("ota") || !object["ota"].is()) { + JsonVariant ota = object["ota"]; + + if (!ota.is()) { result.reason = F("ota is not an object"); return result; } - if (!object["ota"].as().containsKey("enabled") || !object["ota"]["enabled"].is()) { - result.reason = F("ota.enabled is not a boolean"); - return result; + + { + JsonVariant otaEnabled = ota["enabled"]; + + if (!otaEnabled.is()) { + result.reason = F("ota.enabled is not a boolean"); + return result; + } } result.valid = true; @@ -287,11 +367,7 @@ ConfigValidationResult Validation::_validateConfigSettings(const JsonObject obje StaticJsonDocument<0> emptySettingsDoc; - JsonObject settingsObject = emptySettingsDoc.to(); - - if (object.containsKey("settings") && object["settings"].is()) { - settingsObject = object["settings"].as(); - } + JsonObject settingsObject = object["settings"] | emptySettingsDoc.to(); if (settingsObject.size() > MAX_CONFIG_SETTING_SIZE) {//max settings here and in isettings result.reason = F("settings contains more elements than the set limit"); @@ -318,14 +394,16 @@ ConfigValidationResult Validation::_validateConfigSettings(const JsonObject obje } }; + JsonVariant settingElement = settingsObject[iSetting->getName()]; + if (iSetting->isBool()) { HomieSetting* setting = static_cast*>(iSetting); - if (settingsObject.containsKey(setting->getName())) { - if (!settingsObject[setting->getName()].is()) { + if (!settingElement.isNull()) { + if (!settingElement.is()) { setReason(Issue::Type); return result; - } else if (!setting->validate(settingsObject[setting->getName()].as())) { + } else if (!setting->validate(settingElement.as())) { setReason(Issue::Validator); return result; } @@ -336,11 +414,11 @@ ConfigValidationResult Validation::_validateConfigSettings(const JsonObject obje } else if (iSetting->isLong()) { HomieSetting* setting = static_cast*>(iSetting); - if (settingsObject.containsKey(setting->getName())) { - if (!settingsObject[setting->getName()].is()) { + if (!settingElement.isNull()) { + if (!settingElement.is()) { setReason(Issue::Type); return result; - } else if (!setting->validate(settingsObject[setting->getName()].as())) { + } else if (!setting->validate(settingElement.as())) { setReason(Issue::Validator); return result; } @@ -351,11 +429,11 @@ ConfigValidationResult Validation::_validateConfigSettings(const JsonObject obje } else if (iSetting->isDouble()) { HomieSetting* setting = static_cast*>(iSetting); - if (settingsObject.containsKey(setting->getName())) { - if (!settingsObject[setting->getName()].is()) { + if (!settingElement.isNull()) { + if (!settingElement.is()) { setReason(Issue::Type); return result; - } else if (!setting->validate(settingsObject[setting->getName()].as())) { + } else if (!setting->validate(settingElement.as())) { setReason(Issue::Validator); return result; } @@ -366,11 +444,11 @@ ConfigValidationResult Validation::_validateConfigSettings(const JsonObject obje } else if (iSetting->isConstChar()) { HomieSetting* setting = static_cast*>(iSetting); - if (settingsObject.containsKey(setting->getName())) { - if (!settingsObject[setting->getName()].is()) { + if (!settingElement.isNull()) { + if (!settingElement.is()) { setReason(Issue::Type); return result; - } else if (!setting->validate(settingsObject[setting->getName()].as())) { + } else if (!setting->validate(settingElement.as())) { setReason(Issue::Validator); return result; }