diff --git a/code/espurna/board.cpp b/code/espurna/board.cpp index f291c776..d1e8fbe1 100644 --- a/code/espurna/board.cpp +++ b/code/espurna/board.cpp @@ -25,7 +25,7 @@ const String& getChipId() { const String& getIdentifier() { static String value; if (!value.length()) { - value += APP_NAME; + value += getAppName(); value += '-'; value += getChipId(); } @@ -388,9 +388,9 @@ void boardSetup() { return; } - DEBUG_MSG_P(PSTR("[MAIN] " APP_NAME " %s built %s\n"), getVersion(), buildTime().c_str()); - DEBUG_MSG_P(PSTR("[MAIN] " APP_AUTHOR "\n")); - DEBUG_MSG_P(PSTR("[MAIN] " APP_WEBSITE "\n\n")); + DEBUG_MSG_P(PSTR("[MAIN] %s %s built %s\n"), getAppName(), getVersion(), buildTime().c_str()); + DEBUG_MSG_P(PSTR("[MAIN] %s\n"), getAppAuthor()); + DEBUG_MSG_P(PSTR("[MAIN] %s\n"), getAppWebsite()); DEBUG_MSG_P(PSTR("[MAIN] CPU chip ID: %s\n"), getFullChipId().c_str()); DEBUG_MSG_P(PSTR("[MAIN] SDK: %s\n"), ESP.getSdkVersion()); DEBUG_MSG_P(PSTR("[MAIN] Arduino Core: %s\n"), getCoreVersion().c_str()); diff --git a/code/espurna/mdns.cpp b/code/espurna/mdns.cpp index 45719c43..32646306 100644 --- a/code/espurna/mdns.cpp +++ b/code/espurna/mdns.cpp @@ -61,7 +61,7 @@ void mdnsServerSetup() { #if OTA_ARDUINOOTA_SUPPORT { - MDNS.addServiceTxt("arduino", "tcp", "app_name", APP_NAME); + MDNS.addServiceTxt("arduino", "tcp", "app_name", getAppName()); MDNS.addServiceTxt("arduino", "tcp", "app_version", getVersion()); MDNS.addServiceTxt("arduino", "tcp", "build_date", buildTime()); MDNS.addServiceTxt("arduino", "tcp", "mac", WiFi.macAddress()); diff --git a/code/espurna/mqtt.cpp b/code/espurna/mqtt.cpp index 522b9a79..0af36e7d 100644 --- a/code/espurna/mqtt.cpp +++ b/code/espurna/mqtt.cpp @@ -617,7 +617,7 @@ bool _mqttHeartbeat(heartbeat::Mask mask) { mqttSend(MQTT_TOPIC_INTERVAL, String(_mqtt_heartbeat_interval.count()).c_str()); if (mask & heartbeat::Report::App) - mqttSend(MQTT_TOPIC_APP, APP_NAME); + mqttSend(MQTT_TOPIC_APP, getAppName()); if (mask & heartbeat::Report::Version) mqttSend(MQTT_TOPIC_VERSION, getVersion()); diff --git a/code/espurna/nofuss.cpp b/code/espurna/nofuss.cpp index fcfbf638..4230ed25 100644 --- a/code/espurna/nofuss.cpp +++ b/code/espurna/nofuss.cpp @@ -43,7 +43,6 @@ void _nofussWebSocketOnConnected(JsonObject& root) { #endif void _nofussConfigure() { - String nofussServer = getSetting("nofussServer", NOFUSS_SERVER); if (!nofussServer.length()) { setSetting("nofussEnabled", 0); @@ -54,25 +53,24 @@ void _nofussConfigure() { _nofussInterval = getSetting("nofussInterval", NOFUSS_INTERVAL); _nofussLastCheck = 0; - if (!_nofussEnabled) { - - DEBUG_MSG_P(PSTR("[NOFUSS] Disabled\n")); - - } else { + if (_nofussEnabled) { + char device[256]; + sprintf_P(device, PSTR("%s_%s"), getAppName(), getDevice()); + auto timestamp = String(__UNIX_TIMESTAMP__); NoFUSSClient.setServer(nofussServer); - NoFUSSClient.setDevice(APP_NAME "_" DEVICE); - NoFUSSClient.setVersion(APP_VERSION); - NoFUSSClient.setBuild(String(__UNIX_TIMESTAMP__)); - - DEBUG_MSG_P(PSTR("[NOFUSS] Server : %s\n"), nofussServer.c_str()); - DEBUG_MSG_P(PSTR("[NOFUSS] Device: %s\n"), APP_NAME "_" DEVICE); - DEBUG_MSG_P(PSTR("[NOFUSS] Version: %s\n"), APP_VERSION); - DEBUG_MSG_P(PSTR("[NOFUSS] Build: %s\n"), String(__UNIX_TIMESTAMP__).c_str()); - DEBUG_MSG_P(PSTR("[NOFUSS] Enabled\n")); + NoFUSSClient.setDevice(device); + NoFUSSClient.setVersion(getVersion()); + NoFUSSClient.setBuild(timestamp); + DEBUG_MSG_P(PSTR("[NOFUSS] Server: %s\n"), nofussServer.c_str()); + DEBUG_MSG_P(PSTR("[NOFUSS] Device: %s\n"), device) + DEBUG_MSG_P(PSTR("[NOFUSS] Version: %s\n"), getVersion()); + DEBUG_MSG_P(PSTR("[NOFUSS] Build: %s\n"), timestamp.c_str()); + return; } + DEBUG_MSG_P(PSTR("[NOFUSS] Disabled\n")); } // ----------------------------------------------------------------------------- diff --git a/code/espurna/settings.cpp b/code/espurna/settings.cpp index 8af979d3..618bf2f6 100644 --- a/code/espurna/settings.cpp +++ b/code/espurna/settings.cpp @@ -373,7 +373,7 @@ bool settingsRestoreJson(JsonObject& data) { // Note: we try to match what /config generates, expect {"app":"ESPURNA",...} const char* app = data["app"]; - if (!app || strcmp(app, APP_NAME) != 0) { + if (!app || strcmp(app, getAppName()) != 0) { DEBUG_MSG_P(PSTR("[SETTING] Wrong or missing 'app' key\n")); return false; } diff --git a/code/espurna/ssdp.cpp b/code/espurna/ssdp.cpp index d365f0a4..c765f1d0 100644 --- a/code/espurna/ssdp.cpp +++ b/code/espurna/ssdp.cpp @@ -56,9 +56,9 @@ void ssdpSetup() { SSDP_DEVICE_TYPE, // device type getSetting("hostname").c_str(), // friendlyName chipId, // serialNumber - APP_NAME, // modelName - APP_VERSION, // modelNumber - APP_WEBSITE, // modelURL + getAppName(), // modelName + getVersion(), // modelNumber + getAppWebsite(), // modelURL getBoardName().c_str(), // manufacturer "", // manufacturerURL chipId // UUID @@ -73,9 +73,9 @@ void ssdpSetup() { SSDP.setDeviceType(SSDP_DEVICE_TYPE); //https://github.com/esp8266/Arduino/issues/2283 SSDP.setSerialNumber(String(ESP.getChipId())); - SSDP.setModelName(APP_NAME); - SSDP.setModelNumber(APP_VERSION); - SSDP.setModelURL(APP_WEBSITE); + SSDP.setModelName(getAppName()); + SSDP.setModelNumber(getVersion()); + SSDP.setModelURL(getAppWebsite()); SSDP.setManufacturer(getBoardName()); SSDP.setManufacturerURL(""); SSDP.setURL("/"); diff --git a/code/espurna/terminal.cpp b/code/espurna/terminal.cpp index 45741efe..7d048df8 100644 --- a/code/espurna/terminal.cpp +++ b/code/espurna/terminal.cpp @@ -430,7 +430,7 @@ void _terminalInitCommands() { ctx.output.print(F("\n\n!!! device is in safe mode !!!\n\n")); } - ctx.output.printf_P(PSTR(APP_NAME " %s built %s\n"), getVersion(), buildTime().c_str()); + ctx.output.printf_P(PSTR("%s %s built %s\n"), getAppName(), getVersion(), buildTime().c_str()); ctx.output.printf_P(PSTR("mcu: esp8266 chipid: %s\n"), getFullChipId().c_str()); ctx.output.printf_P(PSTR("sdk: %s core: %s\n"), ESP.getSdkVersion(), getCoreVersion().c_str()); diff --git a/code/espurna/utils.cpp b/code/espurna/utils.cpp index abe050bf..aac72dde 100644 --- a/code/espurna/utils.cpp +++ b/code/espurna/utils.cpp @@ -90,6 +90,21 @@ const char* getVersion() { return version; } +const char* getAppName() { + static const char app[] = APP_NAME; + return app; +} + +const char* getAppAuthor() { + static const char author[] = APP_AUTHOR; + return author; +} + +const char* getAppWebsite() { + static const char website[] = APP_WEBSITE; + return website; +} + const char* getDevice() { static const char device[] = DEVICE; return device; diff --git a/code/espurna/utils.h b/code/espurna/utils.h index 346c0295..1bc75502 100644 --- a/code/espurna/utils.h +++ b/code/espurna/utils.h @@ -23,6 +23,9 @@ const String& getCoreRevision(); const char* getFlashChipMode(); const char* getVersion(); +const char* getAppName(); +const char* getAppAuthor(); +const char* getAppWebsite(); const char* getDevice(); const char* getManufacturer(); diff --git a/code/espurna/web.cpp b/code/espurna/web.cpp index b8169f61..8a8c1ff4 100644 --- a/code/espurna/web.cpp +++ b/code/espurna/web.cpp @@ -15,6 +15,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include "system.h" +#include "settings.h" #include "utils.h" #include "ntp.h" @@ -219,10 +220,15 @@ constexpr unsigned long WebConfigBufferMax { 4096ul }; // HOOKS // ----------------------------------------------------------------------------- +void _webRequestAuth(AsyncWebServerRequest* request) { + request->requestAuthentication(getSetting("hostname", getIdentifier()).c_str(), true); +} + void _onReset(AsyncWebServerRequest *request) { webLog(request); if (!webAuthenticate(request)) { - return request->requestAuthentication(getSetting("hostname").c_str()); + _webRequestAuth(request); + return; } deferredReset(100, CustomResetReason::Web); @@ -238,7 +244,7 @@ void _onDiscover(AsyncWebServerRequest *request) { StaticJsonBuffer jsonBuffer; JsonObject &root = jsonBuffer.createObject(); - root["app"] = APP_NAME; + root["app"] = getAppName(); root["version"] = getVersion(); root["device"] = device; root["hostname"] = hostname.c_str(); @@ -251,44 +257,80 @@ void _onDiscover(AsyncWebServerRequest *request) { } void _onGetConfig(AsyncWebServerRequest *request) { - - webLog(request); if (!webAuthenticate(request)) { - return request->requestAuthentication(getSetting("hostname").c_str()); + _webRequestAuth(request); + return; } - AsyncResponseStream *response = request->beginResponseStream("application/json"); + auto out = std::make_shared(); + out->reserve(TCP_MSS); - char buffer[100]; - snprintf_P(buffer, sizeof(buffer), PSTR("attachment; filename=\"%s-backup.json\""), (char *) getSetting("hostname").c_str()); - response->addHeader("Content-Disposition", buffer); - response->addHeader("X-XSS-Protection", "1; mode=block"); - response->addHeader("X-Content-Type-Options", "nosniff"); - response->addHeader("X-Frame-Options", "deny"); - response->printf("{\n\"app\": \"" APP_NAME "\""); - response->printf(",\n\"version\": \"%s\"", getVersion()); - response->printf(",\n\"backup\": \"1\""); - #if NTP_SUPPORT - response->printf(",\n\"timestamp\": \"%s\"", ntpDateTime().c_str()); - #endif - - // Write the keys line by line (not sorted) - auto keys = settingsKeys(); - for (auto& key : keys) { - String value = getSetting(key); - response->printf(",\n\"%s\": \"%s\"", key.c_str(), value.c_str()); + char buffer[256]; + int prefix_len = snprintf_P(buffer, sizeof(buffer), + PSTR("{\n\"app\": \"%s\",\n\"version\": \"%s\",\n\"backup\": \"1\""), + getAppName(), getVersion()); + if (prefix_len <= 0) { + request->send(500); + return; } - response->printf("\n}"); + out->concat(buffer, prefix_len); - request->send(response); + settings::kv_store.foreach([&](settings::kvs_type::KeyValueResult&& kv) { + auto key = kv.key.read(); + auto value = kv.value.read(); + int len = snprintf_P(buffer, sizeof(buffer), PSTR("\"%s\": \"%s\""), key.c_str(), value.c_str()); + if (len > 0) { + *out += ",\n"; + out->concat(buffer, len); + } + }); + *out += "\n}"; + + auto hostname = getSetting("hostname", getIdentifier()); + auto timestamp = String(millis()); +#if NTP_SUPPORT + if (ntpSynced()) { + timestamp = ntpDateTime(); + } +#endif + + AsyncWebServerResponse* response = request->beginChunkedResponse("application/json", + [out](uint8_t* buffer, size_t maxLen, size_t index) -> size_t { + auto len = out->length(); + if (index == len) { + return 0; + } + + auto* ptr = out->c_str() + index; + size_t have = std::min(len - index, maxLen); + if (have) { + std::copy(ptr, ptr + have, buffer); + } + + return have; + }); + + int written = snprintf_P(buffer, sizeof(buffer), + PSTR("attachment; filename=\"%s %s backup.json\""), hostname.c_str(), timestamp.c_str()); + if (written > 0) { + response->addHeader("Content-Disposition", buffer); + response->addHeader("X-XSS-Protection", "1; mode=block"); + response->addHeader("X-Content-Type-Options", "nosniff"); + response->addHeader("X-Frame-Options", "deny"); + request->send(response); + return; + } + + request->send(500); } void _onPostConfig(AsyncWebServerRequest *request) { webLog(request); if (!webAuthenticate(request)) { - return request->requestAuthentication(getSetting("hostname").c_str()); + _webRequestAuth(request); + return; } request->send(_webConfigSuccess ? 200 : 400); } @@ -296,7 +338,8 @@ void _onPostConfig(AsyncWebServerRequest *request) { void _onPostConfigFile(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { if (!webAuthenticate(request)) { - return request->requestAuthentication(getSetting("hostname").c_str()); + _webRequestAuth(request); + return; } // No buffer @@ -342,7 +385,8 @@ void _onHome(AsyncWebServerRequest *request) { webLog(request); if (!webAuthenticate(request)) { - return request->requestAuthentication(getSetting("hostname").c_str()); + _webRequestAuth(request); + return; } if (request->header("If-Modified-Since").equals(_last_modified)) { diff --git a/code/espurna/ws.cpp b/code/espurna/ws.cpp index c5cda020..c9169964 100644 --- a/code/espurna/ws.cpp +++ b/code/espurna/ws.cpp @@ -486,7 +486,7 @@ bool _wsOnKeyCheck(const char * key, JsonVariant& value) { void _wsOnConnected(JsonObject& root) { root["webMode"] = WEB_MODE_NORMAL; - root["app_name"] = APP_NAME; + root["app_name"] = getAppName(); root["app_version"] = getVersion(); root["app_build"] = buildTime(); root["device"] = getDevice();