From cf727d4ff92108c129b7f0e3f06be2a504060ec8 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Thu, 13 Oct 2022 19:44:16 +0200 Subject: [PATCH] Added API to change the access point password --- include/Configuration.h | 4 +- include/WebApi.h | 2 + include/WebApi_security.h | 16 +++++++ src/Configuration.cpp | 12 +++++ src/NetworkSettings.cpp | 2 +- src/WebApi.cpp | 2 + src/WebApi_security.cpp | 92 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 include/WebApi_security.h create mode 100644 src/WebApi_security.cpp diff --git a/include/Configuration.h b/include/Configuration.h index 14ed23bb..ee3754c6 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -5,7 +5,7 @@ #define CONFIG_FILENAME "/config.bin" #define CONFIG_FILENAME_JSON "/config.json" -#define CONFIG_VERSION 0x00011500 // 0.1.21 // make sure to clean all after change +#define CONFIG_VERSION 0x00011600 // 0.1.22 // make sure to clean all after change #define WIFI_MAX_SSID_STRLEN 31 #define WIFI_MAX_PASSWORD_STRLEN 64 @@ -81,6 +81,8 @@ struct CONFIG_T { char Mqtt_Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1]; bool Mqtt_Hass_Expire; + + char Security_Password[WIFI_MAX_PASSWORD_STRLEN + 1]; }; class ConfigurationClass { diff --git a/include/WebApi.h b/include/WebApi.h index 1d01b62d..cf7805a7 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -12,6 +12,7 @@ #include "WebApi_network.h" #include "WebApi_ntp.h" #include "WebApi_power.h" +#include "WebApi_security.h" #include "WebApi_sysstatus.h" #include "WebApi_webapp.h" #include "WebApi_ws_live.h" @@ -38,6 +39,7 @@ private: WebApiNetworkClass _webApiNetwork; WebApiNtpClass _webApiNtp; WebApiPowerClass _webApiPower; + WebApiSecurityClass _webApiSecurity; WebApiSysstatusClass _webApiSysstatus; WebApiWebappClass _webApiWebapp; WebApiWsLiveClass _webApiWsLive; diff --git a/include/WebApi_security.h b/include/WebApi_security.h new file mode 100644 index 00000000..d94a7eeb --- /dev/null +++ b/include/WebApi_security.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +class WebApiSecurityClass { +public: + void init(AsyncWebServer* server); + void loop(); + +private: + void onPasswordGet(AsyncWebServerRequest* request); + void onPasswordPost(AsyncWebServerRequest* request); + + AsyncWebServer* _server; +}; \ No newline at end of file diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 591ec006..d9dbcd11 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -58,6 +58,8 @@ void ConfigurationClass::init() config.Mqtt_Hass_Retain = MQTT_HASS_RETAIN; strlcpy(config.Mqtt_Hass_Topic, MQTT_HASS_TOPIC, sizeof(config.Mqtt_Hass_Topic)); config.Mqtt_Hass_IndividualPanels = MQTT_HASS_INDIVIDUALPANELS; + + strlcpy(config.Security_Password, ACCESS_POINT_PASSWORD, sizeof(config.Security_Password)); } bool ConfigurationClass::write() @@ -121,6 +123,9 @@ bool ConfigurationClass::write() dtu["poll_interval"] = config.Dtu_PollInterval; dtu["pa_level"] = config.Dtu_PaLevel; + JsonObject security = doc.createNestedObject("security"); + security["password"] = config.Security_Password; + JsonArray inverters = doc.createNestedArray("inverters"); for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { JsonObject inv = inverters.createNestedObject(); @@ -259,6 +264,9 @@ bool ConfigurationClass::readJson() config.Dtu_PollInterval = dtu["poll_interval"] | DTU_POLL_INTERVAL; config.Dtu_PaLevel = dtu["pa_level"] | DTU_PA_LEVEL; + JsonObject security = doc["security"]; + strlcpy(config.Security_Password, security["password"] | ACCESS_POINT_PASSWORD, sizeof(config.Security_Password)); + JsonArray inverters = doc["inverters"]; for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { JsonObject inv = inverters[i].as(); @@ -343,6 +351,10 @@ void ConfigurationClass::migrate() config.Mqtt_Hass_Expire = MQTT_HASS_EXPIRE; } + if (config.Cfg_Version < 0x00011600) { + strlcpy(config.Security_Password, ACCESS_POINT_PASSWORD, sizeof(config.Security_Password)); + } + config.Cfg_Version = CONFIG_VERSION; write(); } diff --git a/src/NetworkSettings.cpp b/src/NetworkSettings.cpp index 98e3a6a6..f4df6da3 100644 --- a/src/NetworkSettings.cpp +++ b/src/NetworkSettings.cpp @@ -115,7 +115,7 @@ void NetworkSettingsClass::setupMode() WiFi.mode(WIFI_AP_STA); String ssidString = getApName(); WiFi.softAPConfig(apIp, apIp, apNetmask); - WiFi.softAP((const char*)ssidString.c_str(), ACCESS_POINT_PASSWORD); + WiFi.softAP((const char*)ssidString.c_str(), Configuration.get().Security_Password); dnsServer->setErrorReplyCode(DNSReplyCode::NoError); dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); dnsServerStatus = true; diff --git a/src/WebApi.cpp b/src/WebApi.cpp index e6e3c2c6..be8203db 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -28,6 +28,7 @@ void WebApiClass::init() _webApiNetwork.init(&_server); _webApiNtp.init(&_server); _webApiPower.init(&_server); + _webApiSecurity.init(&_server); _webApiSysstatus.init(&_server); _webApiWebapp.init(&_server); _webApiWsLive.init(&_server); @@ -48,6 +49,7 @@ void WebApiClass::loop() _webApiNetwork.loop(); _webApiNtp.loop(); _webApiPower.loop(); + _webApiSecurity.loop(); _webApiSysstatus.loop(); _webApiWebapp.loop(); _webApiWsLive.loop(); diff --git a/src/WebApi_security.cpp b/src/WebApi_security.cpp new file mode 100644 index 00000000..2009be96 --- /dev/null +++ b/src/WebApi_security.cpp @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Thomas Basler and others + */ +#include "WebApi_security.h" +#include "ArduinoJson.h" +#include "AsyncJson.h" +#include "Configuration.h" +#include "helper.h" + +void WebApiSecurityClass::init(AsyncWebServer* server) +{ + using std::placeholders::_1; + + _server = server; + + _server->on("/api/security/password", HTTP_GET, std::bind(&WebApiSecurityClass::onPasswordGet, this, _1)); + _server->on("/api/security/password", HTTP_POST, std::bind(&WebApiSecurityClass::onPasswordPost, this, _1)); +} + +void WebApiSecurityClass::loop() +{ +} + +void WebApiSecurityClass::onPasswordGet(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + const CONFIG_T& config = Configuration.get(); + + root[F("password")] = config.Security_Password; + + response->setLength(); + request->send(response); +} + +void WebApiSecurityClass::onPasswordPost(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject retMsg = response->getRoot(); + retMsg[F("type")] = F("warning"); + + if (!request->hasParam("data", true)) { + retMsg[F("message")] = F("No values found!"); + response->setLength(); + request->send(response); + return; + } + + String json = request->getParam("data", true)->value(); + + if (json.length() > 1024) { + retMsg[F("message")] = F("Data too large!"); + response->setLength(); + request->send(response); + return; + } + + DynamicJsonDocument root(1024); + DeserializationError error = deserializeJson(root, json); + + if (error) { + retMsg[F("message")] = F("Failed to parse data!"); + response->setLength(); + request->send(response); + return; + } + + if (!root.containsKey("password")) { + retMsg[F("message")] = F("Values are missing!"); + response->setLength(); + request->send(response); + return; + } + + if (root[F("password")].as().length() < 8 || root[F("password")].as().length() > WIFI_MAX_PASSWORD_STRLEN) { + retMsg[F("message")] = F("Password must between 8 and " STR(WIFI_MAX_PASSWORD_STRLEN) " characters long!"); + response->setLength(); + request->send(response); + return; + } + + CONFIG_T& config = Configuration.get(); + strlcpy(config.Security_Password, root[F("password")].as().c_str(), sizeof(config.Security_Password)); + Configuration.write(); + + retMsg[F("type")] = F("success"); + retMsg[F("message")] = F("Settings saved!"); + + response->setLength(); + request->send(response); +} \ No newline at end of file