mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
refactoring
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
#include <APSettingsService.h>
|
#include "APSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
@@ -9,8 +9,8 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
|
|||||||
, _lastManaged(0)
|
, _lastManaged(0)
|
||||||
, _reconfigureAp(false)
|
, _reconfigureAp(false)
|
||||||
, _connected(0) {
|
, _connected(0) {
|
||||||
addUpdateHandler([&](const String & originId) { reconfigureAP(); }, false);
|
addUpdateHandler([this] { reconfigureAP(); }, false);
|
||||||
WiFi.onEvent(std::bind(&APSettingsService::WiFiEvent, this, _1));
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void APSettingsService::begin() {
|
void APSettingsService::begin() {
|
||||||
@@ -53,7 +53,7 @@ void APSettingsService::reconfigureAP() {
|
|||||||
|
|
||||||
void APSettingsService::loop() {
|
void APSettingsService::loop() {
|
||||||
unsigned long currentMillis = uuid::get_uptime();
|
unsigned long currentMillis = uuid::get_uptime();
|
||||||
unsigned long manageElapsed = (uint32_t)(currentMillis - _lastManaged);
|
unsigned long manageElapsed = static_cast<uint32_t>(currentMillis - _lastManaged);
|
||||||
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
if (manageElapsed >= MANAGE_NETWORK_DELAY) {
|
||||||
_lastManaged = currentMillis;
|
_lastManaged = currentMillis;
|
||||||
manageAP();
|
manageAP();
|
||||||
@@ -76,7 +76,7 @@ void APSettingsService::manageAP() {
|
|||||||
|
|
||||||
void APSettingsService::startAP() {
|
void APSettingsService::startAP() {
|
||||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_AP, WIFI_BW_HT20);
|
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
||||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||||
#if CONFIG_IDF_TARGET_ESP32C3
|
#if CONFIG_IDF_TARGET_ESP32C3
|
||||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||||
@@ -108,14 +108,16 @@ void APSettingsService::handleDNS() {
|
|||||||
APNetworkStatus APSettingsService::getAPNetworkStatus() {
|
APNetworkStatus APSettingsService::getAPNetworkStatus() {
|
||||||
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||||
bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA;
|
bool apActive = currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA;
|
||||||
|
|
||||||
if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) {
|
if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) {
|
||||||
return APNetworkStatus::LINGERING;
|
return APNetworkStatus::LINGERING;
|
||||||
}
|
}
|
||||||
|
|
||||||
return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE;
|
return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void APSettings::read(APSettings & settings, JsonObject root) {
|
void APSettings::read(const APSettings & settings, JsonObject root) {
|
||||||
root["provision_mode"] = settings.provisionMode;
|
root["provision_mode"] = settings.provisionMode;
|
||||||
root["ssid"] = settings.ssid;
|
root["ssid"] = settings.ssid;
|
||||||
root["password"] = settings.password;
|
root["password"] = settings.password;
|
||||||
@@ -129,7 +131,8 @@ void APSettings::read(APSettings & settings, JsonObject root) {
|
|||||||
|
|
||||||
StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||||
APSettings newSettings = {};
|
APSettings newSettings = {};
|
||||||
newSettings.provisionMode = root["provision_mode"] | FACTORY_AP_PROVISION_MODE;
|
newSettings.provisionMode = static_cast<uint8_t>(root["provision_mode"] | FACTORY_AP_PROVISION_MODE);
|
||||||
|
|
||||||
switch (settings.provisionMode) {
|
switch (settings.provisionMode) {
|
||||||
case AP_MODE_ALWAYS:
|
case AP_MODE_ALWAYS:
|
||||||
case AP_MODE_DISCONNECTED:
|
case AP_MODE_DISCONNECTED:
|
||||||
@@ -138,11 +141,12 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
|||||||
default:
|
default:
|
||||||
newSettings.provisionMode = AP_MODE_ALWAYS;
|
newSettings.provisionMode = AP_MODE_ALWAYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
newSettings.ssid = root["ssid"] | FACTORY_AP_SSID;
|
newSettings.ssid = root["ssid"] | FACTORY_AP_SSID;
|
||||||
newSettings.password = root["password"] | FACTORY_AP_PASSWORD;
|
newSettings.password = root["password"] | FACTORY_AP_PASSWORD;
|
||||||
newSettings.channel = root["channel"] | FACTORY_AP_CHANNEL;
|
newSettings.channel = static_cast<uint8_t>(root["channel"] | FACTORY_AP_CHANNEL);
|
||||||
newSettings.ssidHidden = root["ssid_hidden"] | FACTORY_AP_SSID_HIDDEN;
|
newSettings.ssidHidden = root["ssid_hidden"] | FACTORY_AP_SSID_HIDDEN;
|
||||||
newSettings.maxClients = root["max_clients"] | FACTORY_AP_MAX_CLIENTS;
|
newSettings.maxClients = static_cast<uint8_t>(root["max_clients"] | FACTORY_AP_MAX_CLIENTS);
|
||||||
|
|
||||||
JsonUtils::readIP(root, "local_ip", newSettings.localIP, FACTORY_AP_LOCAL_IP);
|
JsonUtils::readIP(root, "local_ip", newSettings.localIP, FACTORY_AP_LOCAL_IP);
|
||||||
JsonUtils::readIP(root, "gateway_ip", newSettings.gatewayIP, FACTORY_AP_GATEWAY_IP);
|
JsonUtils::readIP(root, "gateway_ip", newSettings.gatewayIP, FACTORY_AP_GATEWAY_IP);
|
||||||
@@ -151,6 +155,7 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
|||||||
if (newSettings == settings) {
|
if (newSettings == settings) {
|
||||||
return StateUpdateResult::UNCHANGED;
|
return StateUpdateResult::UNCHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
settings = newSettings;
|
settings = newSettings;
|
||||||
return StateUpdateResult::CHANGED;
|
return StateUpdateResult::CHANGED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#ifndef APSettingsConfig_h
|
#ifndef APSettingsConfig_h
|
||||||
#define APSettingsConfig_h
|
#define APSettingsConfig_h
|
||||||
|
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
#include <JsonUtils.h>
|
#include "JsonUtils.h"
|
||||||
|
|
||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
@@ -75,7 +75,7 @@ class APSettings {
|
|||||||
&& subnetMask == settings.subnetMask;
|
&& subnetMask == settings.subnetMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read(APSettings & settings, JsonObject root);
|
static void read(const APSettings & settings, JsonObject root);
|
||||||
static StateUpdateResult update(JsonObject root, APSettings & settings);
|
static StateUpdateResult update(JsonObject root, APSettings & settings);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
#include <APStatus.h>
|
#include "APStatus.h"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
||||||
: _apSettingsService(apSettingsService) {
|
: _apSettingsService(apSettingsService) {
|
||||||
server->on(AP_STATUS_SERVICE_PATH,
|
server->on(AP_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { apStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
void APStatus::apStatus(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
root["status"] = _apSettingsService->getAPNetworkStatus();
|
root["status"] = _apSettingsService->getAPNetworkStatus();
|
||||||
root["ip_address"] = WiFi.softAPIP().toString();
|
root["ip_address"] = WiFi.softAPIP().toString();
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
#include <APSettingsService.h>
|
#include "SecurityManager.h"
|
||||||
|
#include "APSettingsService.h"
|
||||||
|
|
||||||
#define AP_STATUS_SERVICE_PATH "/rest/apStatus"
|
#define AP_STATUS_SERVICE_PATH "/rest/apStatus"
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +1,27 @@
|
|||||||
#include "ArduinoJsonJWT.h"
|
#include "ArduinoJsonJWT.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
ArduinoJsonJWT::ArduinoJsonJWT(String secret)
|
ArduinoJsonJWT::ArduinoJsonJWT(String secret)
|
||||||
: _secret(secret) {
|
: _secret(std::move(secret)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArduinoJsonJWT::setSecret(String secret) {
|
void ArduinoJsonJWT::setSecret(String secret) {
|
||||||
_secret = secret;
|
_secret = std::move(secret);
|
||||||
}
|
}
|
||||||
|
|
||||||
String ArduinoJsonJWT::getSecret() {
|
String ArduinoJsonJWT::getSecret() {
|
||||||
return _secret;
|
return _secret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
|
||||||
*
|
|
||||||
* Both come with decent HMAC implementations supporting sha256, as well as others.
|
|
||||||
*
|
|
||||||
* No need to pull in additional crypto libraries - lets use what we already have.
|
|
||||||
*/
|
|
||||||
String ArduinoJsonJWT::sign(String & payload) {
|
|
||||||
unsigned char hmacResult[32];
|
|
||||||
{
|
|
||||||
mbedtls_md_context_t ctx;
|
|
||||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
|
||||||
mbedtls_md_init(&ctx);
|
|
||||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
|
||||||
mbedtls_md_hmac_starts(&ctx, (unsigned char *)_secret.c_str(), _secret.length());
|
|
||||||
mbedtls_md_hmac_update(&ctx, (unsigned char *)payload.c_str(), payload.length());
|
|
||||||
mbedtls_md_hmac_finish(&ctx, hmacResult);
|
|
||||||
mbedtls_md_free(&ctx);
|
|
||||||
}
|
|
||||||
return encode((char *)hmacResult, 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
String ArduinoJsonJWT::buildJWT(JsonObject payload) {
|
String ArduinoJsonJWT::buildJWT(JsonObject payload) {
|
||||||
// serialize, then encode payload
|
// serialize, then encode payload
|
||||||
String jwt;
|
String jwt;
|
||||||
serializeJson(payload, jwt);
|
serializeJson(payload, jwt);
|
||||||
jwt = encode(jwt.c_str(), jwt.length());
|
jwt = encode(jwt.c_str(), static_cast<int>(jwt.length()));
|
||||||
|
|
||||||
// add the header to payload
|
// add the header to payload
|
||||||
jwt = JWT_HEADER + '.' + jwt;
|
jwt = getJWTHeader() + '.' + jwt;
|
||||||
|
|
||||||
// add signature
|
// add signature
|
||||||
jwt += '.' + sign(jwt);
|
jwt += '.' + sign(jwt);
|
||||||
@@ -53,65 +33,88 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument & jsonDocument) {
|
|||||||
// clear json document before we begin, jsonDocument wil be null on failure
|
// clear json document before we begin, jsonDocument wil be null on failure
|
||||||
jsonDocument.clear();
|
jsonDocument.clear();
|
||||||
|
|
||||||
|
const String & jwt_header = getJWTHeader();
|
||||||
|
const unsigned int jwt_header_size = jwt_header.length();
|
||||||
|
|
||||||
// must have the correct header and delimiter
|
// must have the correct header and delimiter
|
||||||
if (!jwt.startsWith(JWT_HEADER) || jwt.indexOf('.') != JWT_HEADER_SIZE) {
|
if (!jwt.startsWith(jwt_header) || jwt.indexOf('.') != static_cast<int>(jwt_header_size)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check there is a signature delimieter
|
// check there is a signature delimieter
|
||||||
int signatureDelimiterIndex = jwt.lastIndexOf('.');
|
const int signatureDelimiterIndex = jwt.lastIndexOf('.');
|
||||||
if (signatureDelimiterIndex == JWT_HEADER_SIZE) {
|
if (signatureDelimiterIndex == static_cast<int>(jwt_header_size)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the signature is valid
|
// check the signature is valid
|
||||||
String signature = jwt.substring(signatureDelimiterIndex + 1);
|
const String signature = jwt.substring(static_cast<unsigned int>(signatureDelimiterIndex) + 1);
|
||||||
jwt = jwt.substring(0, signatureDelimiterIndex);
|
jwt = jwt.substring(0, static_cast<unsigned int>(signatureDelimiterIndex));
|
||||||
if (sign(jwt) != signature) {
|
if (sign(jwt) != signature) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode payload
|
// decode payload
|
||||||
jwt = jwt.substring(JWT_HEADER_SIZE + 1);
|
jwt = jwt.substring(jwt_header_size + 1);
|
||||||
jwt = decode(jwt);
|
jwt = decode(jwt);
|
||||||
|
|
||||||
// parse payload, clearing json document after failure
|
// parse payload, clearing json document after failure
|
||||||
DeserializationError error = deserializeJson(jsonDocument, jwt);
|
const DeserializationError error = deserializeJson(jsonDocument, jwt);
|
||||||
if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()) {
|
if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()) {
|
||||||
jsonDocument.clear();
|
jsonDocument.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ESP32 uses mbedtls, ESP2866 uses bearssl.
|
||||||
|
*
|
||||||
|
* Both come with decent HMAC implementations supporting sha256, as well as others.
|
||||||
|
*
|
||||||
|
* No need to pull in additional crypto libraries - lets use what we already have.
|
||||||
|
*/
|
||||||
|
String ArduinoJsonJWT::sign(String & payload) {
|
||||||
|
std::array<unsigned char, 32> hmacResult{};
|
||||||
|
{
|
||||||
|
mbedtls_md_context_t ctx;
|
||||||
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||||
|
mbedtls_md_init(&ctx);
|
||||||
|
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1);
|
||||||
|
mbedtls_md_hmac_starts(&ctx, reinterpret_cast<const unsigned char *>(_secret.c_str()), _secret.length());
|
||||||
|
mbedtls_md_hmac_update(&ctx, reinterpret_cast<const unsigned char *>(payload.c_str()), payload.length());
|
||||||
|
mbedtls_md_hmac_finish(&ctx, hmacResult.data());
|
||||||
|
mbedtls_md_free(&ctx);
|
||||||
|
}
|
||||||
|
return encode(reinterpret_cast<const char *>(hmacResult.data()), hmacResult.size());
|
||||||
|
}
|
||||||
|
|
||||||
String ArduinoJsonJWT::encode(const char * cstr, int inputLen) {
|
String ArduinoJsonJWT::encode(const char * cstr, int inputLen) {
|
||||||
// prepare encoder
|
// prepare encoder
|
||||||
base64_encodestate _state;
|
base64_encodestate _state;
|
||||||
base64_init_encodestate(&_state);
|
base64_init_encodestate(&_state);
|
||||||
size_t encodedLength = base64_encode_expected_len(inputLen) + 1;
|
|
||||||
// prepare buffer of correct length, returning an empty string on failure
|
// prepare buffer of correct length
|
||||||
char * buffer = (char *)malloc(encodedLength * sizeof(char));
|
const auto bufferLength = static_cast<std::size_t>(base64_encode_expected_len(inputLen)) + 1;
|
||||||
if (buffer == nullptr) {
|
auto * buffer = new char[bufferLength];
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode to buffer
|
// encode to buffer
|
||||||
int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state);
|
int len = base64_encode_block(cstr, inputLen, &buffer[0], &_state);
|
||||||
len += base64_encode_blockend(&buffer[len], &_state);
|
len += base64_encode_blockend(&buffer[len], &_state);
|
||||||
buffer[len] = 0;
|
buffer[len] = '\0';
|
||||||
|
|
||||||
// convert to arduino string, freeing buffer
|
// convert to arduino string, freeing buffer
|
||||||
String value = String(buffer);
|
auto result = String(buffer);
|
||||||
free(buffer);
|
delete[] buffer;
|
||||||
buffer = nullptr;
|
buffer = nullptr;
|
||||||
|
|
||||||
// remove padding and convert to URL safe form
|
// remove padding and convert to URL safe form
|
||||||
while (value.length() > 0 && value.charAt(value.length() - 1) == '=') {
|
while (result.length() > 0 && result.charAt(result.length() - 1) == '=') {
|
||||||
value.remove(value.length() - 1);
|
result.remove(result.length() - 1);
|
||||||
}
|
}
|
||||||
value.replace('+', '-');
|
result.replace('+', '-');
|
||||||
value.replace('/', '_');
|
result.replace('/', '_');
|
||||||
|
|
||||||
// return as string
|
// return as string
|
||||||
return value;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ArduinoJsonJWT::decode(String value) {
|
String ArduinoJsonJWT::decode(String value) {
|
||||||
@@ -120,12 +123,18 @@ String ArduinoJsonJWT::decode(String value) {
|
|||||||
value.replace('_', '/');
|
value.replace('_', '/');
|
||||||
|
|
||||||
// prepare buffer of correct length
|
// prepare buffer of correct length
|
||||||
char buffer[base64_decode_expected_len(value.length()) + 1];
|
const auto bufferLength = static_cast<std::size_t>(base64_decode_expected_len(value.length()) + 1);
|
||||||
|
auto * buffer = new char[bufferLength];
|
||||||
|
|
||||||
// decode
|
// decode
|
||||||
int len = base64_decode_chars(value.c_str(), value.length(), &buffer[0]);
|
const int len = base64_decode_chars(value.c_str(), static_cast<int>(value.length()), &buffer[0]);
|
||||||
buffer[len] = 0;
|
buffer[len] = '\0';
|
||||||
|
|
||||||
|
// convert to arduino string, freeing buffer
|
||||||
|
auto result = String(buffer);
|
||||||
|
delete[] buffer;
|
||||||
|
buffer = nullptr;
|
||||||
|
|
||||||
// return as string
|
// return as string
|
||||||
return String(buffer);
|
return result;
|
||||||
}
|
}
|
||||||
@@ -3,30 +3,33 @@
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
#include <libb64/cdecode.h>
|
#include <libb64/cdecode.h>
|
||||||
#include <libb64/cencode.h>
|
#include <libb64/cencode.h>
|
||||||
#include <mbedtls/md.h>
|
#include <mbedtls/md.h>
|
||||||
|
|
||||||
class ArduinoJsonJWT {
|
class ArduinoJsonJWT {
|
||||||
private:
|
|
||||||
String _secret;
|
|
||||||
|
|
||||||
const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
|
|
||||||
const int JWT_HEADER_SIZE = JWT_HEADER.length();
|
|
||||||
|
|
||||||
String sign(String & value);
|
|
||||||
|
|
||||||
static String encode(const char * cstr, int len);
|
|
||||||
static String decode(String value);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ArduinoJsonJWT(String secret);
|
explicit ArduinoJsonJWT(String secret);
|
||||||
|
|
||||||
void setSecret(String secret);
|
void setSecret(String secret);
|
||||||
String getSecret();
|
String getSecret();
|
||||||
|
|
||||||
String buildJWT(JsonObject payload);
|
String buildJWT(JsonObject payload);
|
||||||
void parseJWT(String jwt, JsonDocument & jsonDocument);
|
void parseJWT(String jwt, JsonDocument & jsonDocument);
|
||||||
|
|
||||||
|
private:
|
||||||
|
String _secret;
|
||||||
|
|
||||||
|
String sign(String & value);
|
||||||
|
|
||||||
|
static String encode(const char * cstr, int len);
|
||||||
|
static String decode(String value);
|
||||||
|
|
||||||
|
static const String & getJWTHeader() {
|
||||||
|
static const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
|
||||||
|
return JWT_HEADER;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#include <AuthenticationService.h>
|
#include "AuthenticationService.h"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
AuthenticationService::AuthenticationService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager)
|
: _securityManager(securityManager)
|
||||||
, _signInHandler(SIGN_IN_PATH, std::bind(&AuthenticationService::signIn, this, _1, _2)) {
|
, _signInHandler(SIGN_IN_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { signIn(request, json); }) {
|
||||||
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, _1));
|
server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { verifyAuthorization(request); });
|
||||||
_signInHandler.setMethod(HTTP_POST);
|
_signInHandler.setMethod(HTTP_POST);
|
||||||
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
_signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE);
|
||||||
server->addHandler(&_signInHandler);
|
server->addHandler(&_signInHandler);
|
||||||
@@ -29,10 +27,10 @@ void AuthenticationService::signIn(AsyncWebServerRequest * request, JsonVariant
|
|||||||
String password = json["password"];
|
String password = json["password"];
|
||||||
Authentication authentication = _securityManager->authenticate(username, password);
|
Authentication authentication = _securityManager->authenticate(username, password);
|
||||||
if (authentication.authenticated) {
|
if (authentication.authenticated) {
|
||||||
User * user = authentication.user;
|
User * user = authentication.user;
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject jsonObject = response->getRoot();
|
JsonObject jsonObject = response->getRoot();
|
||||||
jsonObject["access_token"] = _securityManager->generateJWT(user);
|
jsonObject["access_token"] = _securityManager->generateJWT(user);
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#ifndef AuthenticationService_H_
|
#ifndef AuthenticationService_H_
|
||||||
#define AuthenticationService_H_
|
#define AuthenticationService_H_
|
||||||
|
|
||||||
#include <Features.h>
|
#include "Features.h"
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
|
||||||
#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization"
|
#define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization"
|
||||||
#define SIGN_IN_PATH "/rest/signIn"
|
#define SIGN_IN_PATH "/rest/signIn"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include <ESP8266React.h>
|
#include "ESP8266React.h"
|
||||||
|
|
||||||
#include <WWWData.h>
|
#include "WWWData.h"
|
||||||
|
|
||||||
ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
||||||
: _securitySettingsService(server, fs)
|
: _securitySettingsService(server, fs)
|
||||||
@@ -27,7 +27,7 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
|||||||
static char last_modified[50];
|
static char last_modified[50];
|
||||||
sprintf(last_modified, "%s %s CET", __DATE__, __TIME__);
|
sprintf(last_modified, "%s %s CET", __DATE__, __TIME__);
|
||||||
|
|
||||||
WWWData::registerRoutes([server, this](const String & uri, const String & contentType, const uint8_t * content, size_t len, const String & hash) {
|
WWWData::registerRoutes([server](const String & uri, const String & contentType, const uint8_t * content, size_t len, const String & hash) {
|
||||||
ArRequestHandlerFunction requestHandler = [contentType, content, len, hash](AsyncWebServerRequest * request) {
|
ArRequestHandlerFunction requestHandler = [contentType, content, len, hash](AsyncWebServerRequest * request) {
|
||||||
// Check if the client already has the same version and respond with a 304 (Not modified)
|
// Check if the client already has the same version and respond with a 304 (Not modified)
|
||||||
if (request->header("If-Modified-Since").indexOf(last_modified) > 0) {
|
if (request->header("If-Modified-Since").indexOf(last_modified) > 0) {
|
||||||
@@ -66,12 +66,13 @@ ESP8266React::ESP8266React(AsyncWebServer * server, FS * fs)
|
|||||||
void ESP8266React::begin() {
|
void ESP8266React::begin() {
|
||||||
_networkSettingsService.begin();
|
_networkSettingsService.begin();
|
||||||
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
_networkSettingsService.read([&](NetworkSettings & networkSettings) {
|
||||||
|
DefaultHeaders & defaultHeaders = DefaultHeaders::Instance();
|
||||||
if (networkSettings.enableCORS) {
|
if (networkSettings.enableCORS) {
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
|
defaultHeaders.addHeader("Access-Control-Allow-Origin", networkSettings.CORSOrigin);
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
defaultHeaders.addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization");
|
||||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true");
|
defaultHeaders.addHeader("Access-Control-Allow-Credentials", "true");
|
||||||
}
|
}
|
||||||
DefaultHeaders::Instance().addHeader("Server", networkSettings.hostname);
|
defaultHeaders.addHeader("Server", networkSettings.hostname);
|
||||||
});
|
});
|
||||||
_apSettingsService.begin();
|
_apSettingsService.begin();
|
||||||
_ntpSettingsService.begin();
|
_ntpSettingsService.begin();
|
||||||
|
|||||||
@@ -1,28 +1,27 @@
|
|||||||
#ifndef ESP8266React_h
|
#ifndef ESP8266React_h
|
||||||
#define ESP8266React_h
|
#define ESP8266React_h
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include "APSettingsService.h"
|
||||||
|
#include "APStatus.h"
|
||||||
|
#include "AuthenticationService.h"
|
||||||
|
#include "FactoryResetService.h"
|
||||||
|
#include "MqttSettingsService.h"
|
||||||
|
#include "MqttStatus.h"
|
||||||
|
#include "NTPSettingsService.h"
|
||||||
|
#include "NTPStatus.h"
|
||||||
|
#include "OTASettingsService.h"
|
||||||
|
#include "UploadFileService.h"
|
||||||
|
#include "RestartService.h"
|
||||||
|
#include "SecuritySettingsService.h"
|
||||||
|
#include "SystemStatus.h"
|
||||||
|
#include "WiFiScanner.h"
|
||||||
|
#include "NetworkSettingsService.h"
|
||||||
|
#include "NetworkStatus.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include <APSettingsService.h>
|
|
||||||
#include <APStatus.h>
|
|
||||||
#include <AuthenticationService.h>
|
|
||||||
#include <FactoryResetService.h>
|
|
||||||
#include <MqttSettingsService.h>
|
|
||||||
#include <MqttStatus.h>
|
|
||||||
#include <NTPSettingsService.h>
|
|
||||||
#include <NTPStatus.h>
|
|
||||||
#include <OTASettingsService.h>
|
|
||||||
#include <UploadFileService.h>
|
|
||||||
#include <RestartService.h>
|
|
||||||
#include <SecuritySettingsService.h>
|
|
||||||
#include <SystemStatus.h>
|
|
||||||
#include <WiFiScanner.h>
|
|
||||||
#include <NetworkSettingsService.h>
|
|
||||||
#include <NetworkStatus.h>
|
|
||||||
|
|
||||||
class ESP8266React {
|
class ESP8266React {
|
||||||
public:
|
public:
|
||||||
ESP8266React(AsyncWebServer * server, FS * fs);
|
ESP8266React(AsyncWebServer * server, FS * fs);
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
class ESPUtils {
|
class ESPUtils {
|
||||||
public:
|
public:
|
||||||
static String defaultDeviceValue(String prefix = "") {
|
static String defaultDeviceValue(const String & prefix = "") {
|
||||||
return prefix + String((uint32_t)ESP.getEfuseMac(), HEX);
|
return prefix + String(static_cast<uint32_t>(ESP.getEfuseMac()), HEX);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef FSPersistence_h
|
#ifndef FSPersistence_h
|
||||||
#define FSPersistence_h
|
#define FSPersistence_h
|
||||||
|
|
||||||
#include <StatefulService.h>
|
#include "StatefulService.h"
|
||||||
#include <FS.h>
|
#include "FS.h"
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class FSPersistence {
|
class FSPersistence {
|
||||||
@@ -47,8 +47,8 @@ class FSPersistence {
|
|||||||
// make directories if required, for new IDF4.2 & LittleFS
|
// make directories if required, for new IDF4.2 & LittleFS
|
||||||
String path(_filePath);
|
String path(_filePath);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while ((index = path.indexOf('/', index + 1)) != -1) {
|
while ((index = path.indexOf('/', static_cast<unsigned int>(index) + 1)) != -1) {
|
||||||
String segment = path.substring(0, index);
|
String segment = path.substring(0, static_cast<unsigned int>(index));
|
||||||
if (!_fs->exists(segment)) {
|
if (!_fs->exists(segment)) {
|
||||||
_fs->mkdir(segment);
|
_fs->mkdir(segment);
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ class FSPersistence {
|
|||||||
|
|
||||||
void enableUpdateHandler() {
|
void enableUpdateHandler() {
|
||||||
if (!_updateHandlerId) {
|
if (!_updateHandlerId) {
|
||||||
_updateHandlerId = _statefulService->addUpdateHandler([&] { writeToFS(); });
|
_updateHandlerId = _statefulService->addUpdateHandler([this] { writeToFS(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
#include <FactoryResetService.h>
|
#include "FactoryResetService.h"
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
FactoryResetService::FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
FactoryResetService::FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: fs(fs) {
|
: fs(fs) {
|
||||||
server->on(FACTORY_RESET_SERVICE_PATH,
|
server->on(FACTORY_RESET_SERVICE_PATH,
|
||||||
HTTP_POST,
|
HTTP_POST,
|
||||||
securityManager->wrapRequest(std::bind(&FactoryResetService::handleRequest, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { handleRequest(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FactoryResetService::handleRequest(AsyncWebServerRequest * request) {
|
void FactoryResetService::handleRequest(AsyncWebServerRequest * request) {
|
||||||
request->onDisconnect(std::bind(&FactoryResetService::factoryReset, this));
|
request->onDisconnect([this]() { factoryReset(); });
|
||||||
request->send(200);
|
request->send(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,7 +19,7 @@ void FactoryResetService::factoryReset() {
|
|||||||
// TODO To replaced with fs.rmdir(FS_CONFIG_DIRECTORY) now we're using IDF 4.2
|
// TODO To replaced with fs.rmdir(FS_CONFIG_DIRECTORY) now we're using IDF 4.2
|
||||||
File root = fs->open(FS_CONFIG_DIRECTORY);
|
File root = fs->open(FS_CONFIG_DIRECTORY);
|
||||||
File file;
|
File file;
|
||||||
while (file = root.openNextFile()) {
|
while ((file = root.openNextFile())) {
|
||||||
String path = file.path();
|
String path = file.path();
|
||||||
file.close();
|
file.close();
|
||||||
fs->remove(path);
|
fs->remove(path);
|
||||||
|
|||||||
@@ -3,22 +3,22 @@
|
|||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
#include <RestartService.h>
|
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
|
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
#include "RestartService.h"
|
||||||
|
|
||||||
#define FS_CONFIG_DIRECTORY "/config"
|
#define FS_CONFIG_DIRECTORY "/config"
|
||||||
#define FACTORY_RESET_SERVICE_PATH "/rest/factoryReset"
|
#define FACTORY_RESET_SERVICE_PATH "/rest/factoryReset"
|
||||||
|
|
||||||
class FactoryResetService {
|
class FactoryResetService {
|
||||||
FS * fs;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
FactoryResetService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||||
|
|
||||||
void factoryReset();
|
void factoryReset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FS * fs;
|
||||||
void handleRequest(AsyncWebServerRequest * request);
|
void handleRequest(AsyncWebServerRequest * request);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,13 @@
|
|||||||
#define HttpEndpoint_h
|
#define HttpEndpoint_h
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
#include <SecurityManager.h>
|
#include "SecurityManager.h"
|
||||||
#include <StatefulService.h>
|
#include "StatefulService.h"
|
||||||
|
|
||||||
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
#define HTTP_ENDPOINT_ORIGIN_ID "http"
|
||||||
|
#define HTTPS_ENDPOINT_ORIGIN_ID "https"
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class HttpEndpoint {
|
class HttpEndpoint {
|
||||||
@@ -19,8 +17,7 @@ class HttpEndpoint {
|
|||||||
JsonStateUpdater<T> _stateUpdater;
|
JsonStateUpdater<T> _stateUpdater;
|
||||||
StatefulService<T> * _statefulService;
|
StatefulService<T> * _statefulService;
|
||||||
|
|
||||||
AsyncCallbackWebHandler * GEThandler;
|
AsyncCallbackJsonWebHandler * handler;
|
||||||
AsyncCallbackJsonWebHandler * POSThandler;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HttpEndpoint(JsonStateReader<T> stateReader,
|
HttpEndpoint(JsonStateReader<T> stateReader,
|
||||||
@@ -33,12 +30,12 @@ class HttpEndpoint {
|
|||||||
: _stateReader(stateReader)
|
: _stateReader(stateReader)
|
||||||
, _stateUpdater(stateUpdater)
|
, _stateUpdater(stateUpdater)
|
||||||
, _statefulService(statefulService) {
|
, _statefulService(statefulService) {
|
||||||
// Create the GET and POST endpoints
|
// Create hander for both GET and POST endpoints
|
||||||
POSThandler = new AsyncCallbackJsonWebHandler(servicePath,
|
handler = new AsyncCallbackJsonWebHandler(servicePath,
|
||||||
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
|
||||||
JsonVariant json) { handleRequest(request, json); },
|
JsonVariant json) { handleRequest(request, json); },
|
||||||
authenticationPredicate));
|
authenticationPredicate));
|
||||||
server->addHandler(POSThandler);
|
server->addHandler(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -66,8 +63,8 @@ class HttpEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject jsonObject = response->getRoot().to<JsonObject>();
|
JsonObject jsonObject = response->getRoot().to<JsonObject>();
|
||||||
_statefulService->read(jsonObject, _stateReader);
|
_statefulService->read(jsonObject, _stateReader);
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@@ -3,16 +3,20 @@
|
|||||||
|
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
|
|
||||||
const IPAddress IP_NOT_SET = IPAddress(INADDR_NONE);
|
|
||||||
|
|
||||||
class IPUtils {
|
class IPUtils {
|
||||||
public:
|
public:
|
||||||
static bool isSet(const IPAddress & ip) {
|
static bool isSet(const IPAddress & ip) {
|
||||||
return ip != IP_NOT_SET;
|
return ip != getNotSetIP();
|
||||||
}
|
}
|
||||||
static bool isNotSet(const IPAddress & ip) {
|
static bool isNotSet(const IPAddress & ip) {
|
||||||
return ip == IP_NOT_SET;
|
return ip == getNotSetIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const IPAddress & getNotSetIP() {
|
||||||
|
static const IPAddress IP_NOT_SET = IPAddress(INADDR_NONE);
|
||||||
|
return IP_NOT_SET;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
#define JsonUtils_h
|
#define JsonUtils_h
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <IPAddress.h>
|
|
||||||
#include <IPUtils.h>
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include <IPAddress.h>
|
||||||
|
|
||||||
|
#include "IPUtils.h"
|
||||||
|
|
||||||
class JsonUtils {
|
class JsonUtils {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
#include <MqttSettingsService.h>
|
#include "MqttSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
* Retains a copy of the cstr provided in the pointer provided using dynamic allocation.
|
||||||
*
|
*
|
||||||
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
* Frees the pointer before allocation and leaves it as nullptr if cstr == nullptr.
|
||||||
*/
|
*/
|
||||||
static char * retainCstr(const char * cstr, char ** ptr) {
|
static char * retainCstr(const char * cstr, char ** ptr) {
|
||||||
|
if (ptr == nullptr || *ptr == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// free up previously retained value if exists
|
// free up previously retained value if exists
|
||||||
free(*ptr);
|
delete[] *ptr;
|
||||||
*ptr = nullptr;
|
*ptr = nullptr;
|
||||||
|
|
||||||
// dynamically allocate and copy cstr (if non null)
|
// dynamically allocate and copy cstr (if non null)
|
||||||
if (cstr != nullptr) {
|
if (cstr != nullptr) {
|
||||||
*ptr = (char *)malloc(strlen(cstr) + 1);
|
*ptr = new char[strlen(cstr) + 1];
|
||||||
strcpy(*ptr, cstr);
|
strcpy(*ptr, cstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,15 +32,22 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
|
|||||||
, _retainedClientId(nullptr)
|
, _retainedClientId(nullptr)
|
||||||
, _retainedUsername(nullptr)
|
, _retainedUsername(nullptr)
|
||||||
, _retainedPassword(nullptr)
|
, _retainedPassword(nullptr)
|
||||||
|
, _retainedRootCA(nullptr)
|
||||||
, _reconfigureMqtt(false)
|
, _reconfigureMqtt(false)
|
||||||
, _disconnectedAt(0)
|
, _disconnectedAt(0)
|
||||||
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
|
||||||
, _mqttClient(nullptr) {
|
, _mqttClient(nullptr) {
|
||||||
WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2));
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||||
addUpdateHandler([&] { onConfigUpdated(); }, false);
|
addUpdateHandler([this]() { onConfigUpdated(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttSettingsService::~MqttSettingsService() {
|
MqttSettingsService::~MqttSettingsService() {
|
||||||
|
delete _mqttClient;
|
||||||
|
retainCstr(nullptr, &_retainedHost);
|
||||||
|
retainCstr(nullptr, &_retainedClientId);
|
||||||
|
retainCstr(nullptr, &_retainedUsername);
|
||||||
|
retainCstr(nullptr, &_retainedPassword);
|
||||||
|
retainCstr(nullptr, &_retainedRootCA);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::begin() {
|
void MqttSettingsService::begin() {
|
||||||
@@ -55,32 +63,41 @@ void MqttSettingsService::startClient() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete _mqttClient;
|
delete _mqttClient;
|
||||||
|
_mqttClient = nullptr;
|
||||||
}
|
}
|
||||||
#if CONFIG_IDF_TARGET_ESP32S3
|
#if CONFIG_IDF_TARGET_ESP32S3
|
||||||
if (_state.enableTLS) {
|
if (_state.enableTLS) {
|
||||||
isSecure = true;
|
isSecure = true;
|
||||||
_mqttClient = static_cast<MqttClient *>(new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO));
|
_mqttClient = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
|
||||||
if (_state.rootCA == "insecure") {
|
if (_state.rootCA == "insecure") {
|
||||||
static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
|
static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
|
||||||
} else {
|
} else {
|
||||||
String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n";
|
String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n";
|
||||||
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(retainCstr(certificate.c_str(), &_retainedRootCA));
|
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(retainCstr(certificate.c_str(), &_retainedRootCA));
|
||||||
}
|
}
|
||||||
static_cast<espMqttClientSecure *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
static_cast<espMqttClientSecure *>(_mqttClient)->onConnect([this](bool sessionPresent) { onMqttConnect(sessionPresent); });
|
||||||
static_cast<espMqttClientSecure *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
static_cast<espMqttClientSecure *>(_mqttClient)->onDisconnect([this](espMqttClientTypes::DisconnectReason reason) { onMqttDisconnect(reason); });
|
||||||
static_cast<espMqttClientSecure *>(_mqttClient)->onMessage(std::bind(&MqttSettingsService::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
static_cast<espMqttClientSecure *>(_mqttClient)
|
||||||
|
->onMessage(
|
||||||
|
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
||||||
|
onMqttMessage(properties, topic, payload, len, index, total);
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
isSecure = false;
|
isSecure = false;
|
||||||
_mqttClient = static_cast<MqttClient *>(new espMqttClient(espMqttClientTypes::UseInternalTask::NO));
|
_mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
|
||||||
static_cast<espMqttClient *>(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1));
|
static_cast<espMqttClient *>(_mqttClient)->onConnect([this](bool sessionPresent) { onMqttConnect(sessionPresent); });
|
||||||
static_cast<espMqttClient *>(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1));
|
static_cast<espMqttClient *>(_mqttClient)->onDisconnect([this](espMqttClientTypes::DisconnectReason reason) { onMqttDisconnect(reason); });
|
||||||
static_cast<espMqttClient *>(_mqttClient)->onMessage(std::bind(&MqttSettingsService::onMqttMessage, this, _1, _2, _3, _4, _5, _6));
|
static_cast<espMqttClient *>(_mqttClient)
|
||||||
|
->onMessage(
|
||||||
|
[this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) {
|
||||||
|
onMqttMessage(properties, topic, payload, len, index, total);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::loop() {
|
void MqttSettingsService::loop() {
|
||||||
if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
|
||||||
// reconfigure MQTT client
|
// reconfigure MQTT client
|
||||||
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
|
||||||
_reconfigureMqtt = false;
|
_reconfigureMqtt = false;
|
||||||
@@ -116,6 +133,9 @@ void MqttSettingsService::onMqttMessage(const espMqttClientTypes::MessagePropert
|
|||||||
size_t len,
|
size_t len,
|
||||||
size_t index,
|
size_t index,
|
||||||
size_t total) {
|
size_t total) {
|
||||||
|
(void)properties;
|
||||||
|
(void)index;
|
||||||
|
(void)total;
|
||||||
emsesp::EMSESP::mqtt_.on_message(topic, payload, len);
|
emsesp::EMSESP::mqtt_.on_message(topic, payload, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +148,7 @@ MqttClient * MqttSettingsService::getMqttClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
void MqttSettingsService::onMqttConnect(bool sessionPresent) {
|
||||||
|
(void)sessionPresent;
|
||||||
// _disconnectedAt = 0;
|
// _disconnectedAt = 0;
|
||||||
emsesp::EMSESP::mqtt_.on_connect();
|
emsesp::EMSESP::mqtt_.on_connect();
|
||||||
// emsesp::EMSESP::logger().info("Connected to MQTT, %s", (sessionPresent) ? ("with persistent session") : ("without persistent session"));
|
// emsesp::EMSESP::logger().info("Connected to MQTT, %s", (sessionPresent) ? ("with persistent session") : ("without persistent session"));
|
||||||
@@ -149,7 +170,7 @@ void MqttSettingsService::onConfigUpdated() {
|
|||||||
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
@@ -264,32 +285,32 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
|
|||||||
#endif
|
#endif
|
||||||
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED;
|
||||||
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
newSettings.host = root["host"] | FACTORY_MQTT_HOST;
|
||||||
newSettings.port = root["port"] | FACTORY_MQTT_PORT;
|
newSettings.port = static_cast<uint16_t>(root["port"] | FACTORY_MQTT_PORT);
|
||||||
newSettings.base = root["base"] | FACTORY_MQTT_BASE;
|
newSettings.base = root["base"] | FACTORY_MQTT_BASE;
|
||||||
newSettings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
newSettings.username = root["username"] | FACTORY_MQTT_USERNAME;
|
||||||
newSettings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
newSettings.password = root["password"] | FACTORY_MQTT_PASSWORD;
|
||||||
newSettings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
newSettings.clientId = root["client_id"] | FACTORY_MQTT_CLIENT_ID;
|
||||||
newSettings.keepAlive = root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE;
|
newSettings.keepAlive = static_cast<uint16_t>(root["keep_alive"] | FACTORY_MQTT_KEEP_ALIVE);
|
||||||
newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
newSettings.cleanSession = root["clean_session"] | FACTORY_MQTT_CLEAN_SESSION;
|
||||||
newSettings.mqtt_qos = root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS;
|
newSettings.mqtt_qos = static_cast<uint8_t>(root["mqtt_qos"] | EMSESP_DEFAULT_MQTT_QOS);
|
||||||
newSettings.mqtt_retain = root["mqtt_retain"] | EMSESP_DEFAULT_MQTT_RETAIN;
|
newSettings.mqtt_retain = root["mqtt_retain"] | EMSESP_DEFAULT_MQTT_RETAIN;
|
||||||
|
|
||||||
newSettings.publish_time_boiler = root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_boiler = static_cast<uint16_t>(root["publish_time_boiler"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_thermostat = root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_thermostat = static_cast<uint16_t>(root["publish_time_thermostat"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_solar = root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_solar = static_cast<uint16_t>(root["publish_time_solar"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_mixer = root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_mixer = static_cast<uint16_t>(root["publish_time_mixer"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_other = root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_other = static_cast<uint16_t>(root["publish_time_other"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_sensor = root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME;
|
newSettings.publish_time_sensor = static_cast<uint16_t>(root["publish_time_sensor"] | EMSESP_DEFAULT_PUBLISH_TIME);
|
||||||
newSettings.publish_time_heartbeat = root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT;
|
newSettings.publish_time_heartbeat = static_cast<uint16_t>(root["publish_time_heartbeat"] | EMSESP_DEFAULT_PUBLISH_HEARTBEAT);
|
||||||
|
|
||||||
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
newSettings.ha_enabled = root["ha_enabled"] | EMSESP_DEFAULT_HA_ENABLED;
|
||||||
newSettings.nested_format = root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT;
|
newSettings.nested_format = static_cast<uint8_t>(root["nested_format"] | EMSESP_DEFAULT_NESTED_FORMAT);
|
||||||
newSettings.discovery_prefix = root["discovery_prefix"] | EMSESP_DEFAULT_DISCOVERY_PREFIX;
|
newSettings.discovery_prefix = root["discovery_prefix"] | EMSESP_DEFAULT_DISCOVERY_PREFIX;
|
||||||
newSettings.discovery_type = root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE;
|
newSettings.discovery_type = static_cast<uint8_t>(root["discovery_type"] | EMSESP_DEFAULT_DISCOVERY_TYPE);
|
||||||
newSettings.publish_single = root["publish_single"] | EMSESP_DEFAULT_PUBLISH_SINGLE;
|
newSettings.publish_single = root["publish_single"] | EMSESP_DEFAULT_PUBLISH_SINGLE;
|
||||||
newSettings.publish_single2cmd = root["publish_single2cmd"] | EMSESP_DEFAULT_PUBLISH_SINGLE2CMD;
|
newSettings.publish_single2cmd = root["publish_single2cmd"] | EMSESP_DEFAULT_PUBLISH_SINGLE2CMD;
|
||||||
newSettings.send_response = root["send_response"] | EMSESP_DEFAULT_SEND_RESPONSE;
|
newSettings.send_response = root["send_response"] | EMSESP_DEFAULT_SEND_RESPONSE;
|
||||||
newSettings.entity_format = root["entity_format"] | EMSESP_DEFAULT_ENTITY_FORMAT;
|
newSettings.entity_format = static_cast<uint8_t>(root["entity_format"] | EMSESP_DEFAULT_ENTITY_FORMAT);
|
||||||
|
|
||||||
if (newSettings.enabled != settings.enabled) {
|
if (newSettings.enabled != settings.enabled) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
#ifndef MqttSettingsService_h
|
#ifndef MqttSettingsService_h
|
||||||
#define MqttSettingsService_h
|
#define MqttSettingsService_h
|
||||||
|
|
||||||
#include <StatefulService.h>
|
#include "StatefulService.h"
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
|
#include "ESPUtils.h"
|
||||||
|
|
||||||
#include <espMqttClient.h>
|
#include <espMqttClient.h>
|
||||||
#include <ESPUtils.h>
|
|
||||||
|
|
||||||
#include <uuid/common.h>
|
#include <uuid/common.h>
|
||||||
|
|
||||||
@@ -141,11 +142,12 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
|
|||||||
// the MQTT client instance
|
// the MQTT client instance
|
||||||
MqttClient * _mqttClient;
|
MqttClient * _mqttClient;
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(WiFiEvent_t event);
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||||
void
|
void
|
||||||
onMqttMessage(const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total);
|
onMqttMessage(const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total);
|
||||||
|
|
||||||
bool configureMqtt();
|
bool configureMqtt();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
#include <MqttStatus.h>
|
#include "MqttStatus.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
MqttStatus::MqttStatus(AsyncWebServer * server, MqttSettingsService * mqttSettingsService, SecurityManager * securityManager)
|
||||||
: _mqttSettingsService(mqttSettingsService) {
|
: _mqttSettingsService(mqttSettingsService) {
|
||||||
server->on(MQTT_STATUS_SERVICE_PATH,
|
server->on(MQTT_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&MqttStatus::mqttStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { mqttStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
void MqttStatus::mqttStatus(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
root["enabled"] = _mqttSettingsService->isEnabled();
|
root["enabled"] = _mqttSettingsService->isEnabled();
|
||||||
root["connected"] = _mqttSettingsService->isConnected();
|
root["connected"] = _mqttSettingsService->isConnected();
|
||||||
|
|||||||
@@ -2,10 +2,11 @@
|
|||||||
#define MqttStatus_h
|
#define MqttStatus_h
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <MqttSettingsService.h>
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
#include "MqttSettingsService.h"
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#define MQTT_STATUS_SERVICE_PATH "/rest/mqttStatus"
|
#define MQTT_STATUS_SERVICE_PATH "/rest/mqttStatus"
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
#include <NTPSettingsService.h>
|
#include "NTPSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(NTPSettings::read, NTPSettings::update, this, server, NTP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
, _fsPersistence(NTPSettings::read, NTPSettings::update, this, fs, NTP_SETTINGS_FILE)
|
||||||
, _timeHandler(TIME_PATH, securityManager->wrapCallback(std::bind(&NTPSettingsService::configureTime, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
, _timeHandler(TIME_PATH,
|
||||||
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { configureTime(request, json); },
|
||||||
|
AuthenticationPredicates::IS_ADMIN))
|
||||||
|
, _connected(false) {
|
||||||
_timeHandler.setMethod(HTTP_POST);
|
_timeHandler.setMethod(HTTP_POST);
|
||||||
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
|
_timeHandler.setMaxContentLength(MAX_TIME_SIZE);
|
||||||
server->addHandler(&_timeHandler);
|
server->addHandler(&_timeHandler);
|
||||||
|
|
||||||
WiFi.onEvent(std::bind(&NTPSettingsService::WiFiEvent, this, _1));
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||||
|
addUpdateHandler([this] { configureNTP(); }, false);
|
||||||
addUpdateHandler([&] { configureNTP(); }, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTPSettingsService::begin() {
|
void NTPSettingsService::begin() {
|
||||||
@@ -27,9 +27,9 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
if (connected_) {
|
if (_connected) {
|
||||||
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
|
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
|
||||||
connected_ = false;
|
_connected = false;
|
||||||
configureNTP();
|
configureNTP();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -37,7 +37,7 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
|
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
|
||||||
connected_ = true;
|
_connected = true;
|
||||||
configureNTP();
|
configureNTP();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ void NTPSettingsService::WiFiEvent(WiFiEvent_t event) {
|
|||||||
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
|
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
|
||||||
void NTPSettingsService::configureNTP() {
|
void NTPSettingsService::configureNTP() {
|
||||||
emsesp::EMSESP::system_.ntp_connected(false);
|
emsesp::EMSESP::system_.ntp_connected(false);
|
||||||
if (connected_ && _state.enabled) {
|
if (_connected && _state.enabled) {
|
||||||
emsesp::EMSESP::logger().info("Starting NTP service");
|
emsesp::EMSESP::logger().info("Starting NTP service");
|
||||||
esp_sntp_set_sync_interval(3600000); // one hour
|
esp_sntp_set_sync_interval(3600000); // one hour
|
||||||
esp_sntp_set_time_sync_notification_cb(ntp_received);
|
esp_sntp_set_time_sync_notification_cb(ntp_received);
|
||||||
@@ -63,13 +63,13 @@ void NTPSettingsService::configureNTP() {
|
|||||||
|
|
||||||
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {
|
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {
|
||||||
if (json.is<JsonObject>()) {
|
if (json.is<JsonObject>()) {
|
||||||
struct tm tm = {0};
|
struct tm tm = {};
|
||||||
String timeLocal = json["local_time"];
|
String timeLocal = json["local_time"];
|
||||||
char * s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
|
char * s = strptime(timeLocal.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
|
||||||
if (s != nullptr) {
|
if (s != nullptr) {
|
||||||
tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving
|
tm.tm_isdst = -1; // not set by strptime, tells mktime to determine daylightsaving
|
||||||
time_t time = mktime(&tm);
|
time_t time = mktime(&tm);
|
||||||
struct timeval now = {.tv_sec = time};
|
struct timeval now = {.tv_sec = time, .tv_usec = {}};
|
||||||
settimeofday(&now, nullptr);
|
settimeofday(&now, nullptr);
|
||||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@@ -82,6 +82,7 @@ void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVari
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NTPSettingsService::ntp_received(struct timeval * tv) {
|
void NTPSettingsService::ntp_received(struct timeval * tv) {
|
||||||
|
(void)tv;
|
||||||
// emsesp::EMSESP::logger().info("NTP sync to %d sec", tv->tv_sec);
|
// emsesp::EMSESP::logger().info("NTP sync to %d sec", tv->tv_sec);
|
||||||
emsesp::EMSESP::system_.ntp_connected(true);
|
emsesp::EMSESP::system_.ntp_connected(true);
|
||||||
}
|
}
|
||||||
@@ -99,4 +100,4 @@ StateUpdateResult NTPSettings::update(JsonObject root, NTPSettings & settings) {
|
|||||||
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
settings.tzLabel = root["tz_label"] | FACTORY_NTP_TIME_ZONE_LABEL;
|
||||||
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
settings.tzFormat = root["tz_format"] | FACTORY_NTP_TIME_ZONE_FORMAT;
|
||||||
return StateUpdateResult::CHANGED;
|
return StateUpdateResult::CHANGED;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef NTPSettingsService_h
|
#ifndef NTPSettingsService_h
|
||||||
#define NTPSettingsService_h
|
#define NTPSettingsService_h
|
||||||
|
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <ctime>
|
||||||
#include <esp_sntp.h>
|
#include <esp_sntp.h>
|
||||||
|
|
||||||
#ifndef FACTORY_NTP_ENABLED
|
#ifndef FACTORY_NTP_ENABLED
|
||||||
@@ -51,8 +51,8 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
|
|||||||
HttpEndpoint<NTPSettings> _httpEndpoint;
|
HttpEndpoint<NTPSettings> _httpEndpoint;
|
||||||
FSPersistence<NTPSettings> _fsPersistence;
|
FSPersistence<NTPSettings> _fsPersistence;
|
||||||
AsyncCallbackJsonWebHandler _timeHandler;
|
AsyncCallbackJsonWebHandler _timeHandler;
|
||||||
|
bool _connected;
|
||||||
|
|
||||||
bool connected_ = false;
|
|
||||||
void WiFiEvent(WiFiEvent_t event);
|
void WiFiEvent(WiFiEvent_t event);
|
||||||
void configureNTP();
|
void configureNTP();
|
||||||
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
void configureTime(AsyncWebServerRequest * request, JsonVariant json);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#include <NTPStatus.h>
|
#include "NTPStatus.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
#include <array>
|
||||||
|
|
||||||
NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(NTP_STATUS_SERVICE_PATH,
|
server->on(NTP_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { ntpStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -15,9 +16,9 @@ NTPStatus::NTPStatus(AsyncWebServer * server, SecurityManager * securityManager)
|
|||||||
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
|
* Uses a 25 byte buffer, large enough to fit an ISO time string with offset.
|
||||||
*/
|
*/
|
||||||
String formatTime(tm * time, const char * format) {
|
String formatTime(tm * time, const char * format) {
|
||||||
char time_string[25];
|
std::array<char, 25> time_string{};
|
||||||
strftime(time_string, 25, format, time);
|
strftime(time_string.data(), time_string.size(), format, time);
|
||||||
return String(time_string);
|
return {time_string.data()};
|
||||||
}
|
}
|
||||||
|
|
||||||
String toUTCTimeString(tm * time) {
|
String toUTCTimeString(tm * time) {
|
||||||
@@ -29,14 +30,23 @@ String toLocalTimeString(tm * time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NTPStatus::ntpStatus(AsyncWebServerRequest * request) {
|
void NTPStatus::ntpStatus(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
// grab the current instant in unix seconds
|
// grab the current instant in unix seconds
|
||||||
time_t now = time(nullptr);
|
time_t now = time(nullptr);
|
||||||
|
|
||||||
// only provide enabled/disabled status for now
|
// only provide enabled/disabled status for now
|
||||||
root["status"] = esp_sntp_enabled() ? emsesp::EMSESP::system_.ntp_connected() ? 2 : 1 : 0;
|
root["status"] = []() {
|
||||||
|
if (esp_sntp_enabled()) {
|
||||||
|
if (emsesp::EMSESP::system_.ntp_connected()) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}();
|
||||||
|
|
||||||
// the current time in UTC
|
// the current time in UTC
|
||||||
root["utc_time"] = toUTCTimeString(gmtime(&now));
|
root["utc_time"] = toUTCTimeString(gmtime(&now));
|
||||||
@@ -49,4 +59,4 @@ void NTPStatus::ntpStatus(AsyncWebServerRequest * request) {
|
|||||||
|
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
#ifndef NTPStatus_h
|
#ifndef NTPStatus_h
|
||||||
#define NTPStatus_h
|
#define NTPStatus_h
|
||||||
|
|
||||||
#include <time.h>
|
#include <ctime>
|
||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <esp_sntp.h>
|
#include <esp_sntp.h>
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#include <uuid/common.h>
|
#include <uuid/common.h>
|
||||||
|
|
||||||
#define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus"
|
#define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus"
|
||||||
|
|||||||
@@ -1,16 +1,25 @@
|
|||||||
#include <NetworkSettingsService.h>
|
#include "NetworkSettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
||||||
, _lastConnectionAttempt(0) {
|
, _lastConnectionAttempt(0)
|
||||||
addUpdateHandler([&] { reconfigureWiFiConnection(); }, false);
|
, _stopping(false) {
|
||||||
// wifi event callbacks
|
addUpdateHandler([this]() { reconfigureWiFiConnection(); }, false);
|
||||||
WiFi.onEvent(std::bind(&NetworkSettingsService::WiFiEvent, this, _1, _2));
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); });
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
||||||
|
uint tmp[6];
|
||||||
|
if (bssid.isEmpty() || sscanf(bssid.c_str(), "%X:%X:%X:%X:%X:%X", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]) != 6) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < 6; i++) {
|
||||||
|
mac[i] = static_cast<uint8_t>(tmp[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkSettingsService::begin() {
|
void NetworkSettingsService::begin() {
|
||||||
@@ -47,7 +56,7 @@ void NetworkSettingsService::reconfigureWiFiConnection() {
|
|||||||
|
|
||||||
void NetworkSettingsService::loop() {
|
void NetworkSettingsService::loop() {
|
||||||
unsigned long currentMillis = millis();
|
unsigned long currentMillis = millis();
|
||||||
if (!_lastConnectionAttempt || (uint32_t)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
if (!_lastConnectionAttempt || static_cast<uint32_t>(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
||||||
_lastConnectionAttempt = currentMillis;
|
_lastConnectionAttempt = currentMillis;
|
||||||
manageSTA();
|
manageSTA();
|
||||||
}
|
}
|
||||||
@@ -68,22 +77,18 @@ void NetworkSettingsService::manageSTA() {
|
|||||||
|
|
||||||
// www.esp32.com/viewtopic.php?t=12055
|
// www.esp32.com/viewtopic.php?t=12055
|
||||||
if (_state.bandwidth20) {
|
if (_state.bandwidth20) {
|
||||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT20);
|
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT20);
|
||||||
} else {
|
} else {
|
||||||
esp_wifi_set_bandwidth((wifi_interface_t)ESP_IF_WIFI_STA, WIFI_BW_HT40);
|
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT40);
|
||||||
}
|
}
|
||||||
if (_state.nosleep) {
|
if (_state.nosleep) {
|
||||||
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
// attempt to connect to the network
|
// attempt to connect to the network
|
||||||
uint mac[6];
|
uint8_t bssid[6];
|
||||||
if (!_state.bssid.isEmpty() && sscanf(_state.bssid.c_str(), "%X:%X:%X:%X:%X:%X", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) == 6) {
|
if (formatBssid(_state.bssid, bssid)) {
|
||||||
uint8_t mac1[6];
|
WiFi.begin(_state.ssid.c_str(), _state.password.c_str(), 0, bssid);
|
||||||
for (uint8_t i = 0; i < 6; i++) {
|
|
||||||
mac1[i] = (uint8_t)mac[i];
|
|
||||||
}
|
|
||||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str(), 0, mac1);
|
|
||||||
} else {
|
} else {
|
||||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str());
|
WiFi.begin(_state.ssid.c_str(), _state.password.c_str());
|
||||||
}
|
}
|
||||||
@@ -96,7 +101,7 @@ void NetworkSettingsService::manageSTA() {
|
|||||||
#else
|
#else
|
||||||
if (_state.tx_power != 0) {
|
if (_state.tx_power != 0) {
|
||||||
// if not set to Auto (0) set the Tx power now
|
// if not set to Auto (0) set the Tx power now
|
||||||
if (!WiFi.setTxPower((wifi_power_t)_state.tx_power)) {
|
if (!WiFi.setTxPower(static_cast<wifi_power_t>(_state.tx_power))) {
|
||||||
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
|
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +178,7 @@ void NetworkSettingsService::setWiFiPowerOnRSSI() {
|
|||||||
emsesp::EMSESP::logger().debug("Recommended set WiFi Tx Power (set_power %d, new power %d, rssi %d, threshold %d", set_power, p, rssi, threshold);
|
emsesp::EMSESP::logger().debug("Recommended set WiFi Tx Power (set_power %d, new power %d, rssi %d, threshold %d", set_power, p, rssi, threshold);
|
||||||
#else
|
#else
|
||||||
char result[10];
|
char result[10];
|
||||||
emsesp::EMSESP::logger().info("Setting WiFi Tx Power to %s dBm", emsesp::Helpers::render_value(result, (double)(p / 4), 1));
|
emsesp::EMSESP::logger().info("Setting WiFi Tx Power to %s dBm", emsesp::Helpers::render_value(result, ((double)(p) / 4), 1));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!WiFi.setTxPower(p)) {
|
if (!WiFi.setTxPower(p)) {
|
||||||
@@ -310,7 +315,7 @@ void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
|||||||
emsesp::EMSESP::logger().info("WiFi connected with IP=%s, hostname=%s, TxPower=%s dBm",
|
emsesp::EMSESP::logger().info("WiFi connected with IP=%s, hostname=%s, TxPower=%s dBm",
|
||||||
WiFi.localIP().toString().c_str(),
|
WiFi.localIP().toString().c_str(),
|
||||||
WiFi.getHostname(),
|
WiFi.getHostname(),
|
||||||
emsesp::Helpers::render_value(result, (double)(WiFi.getTxPower() / 4), 1));
|
emsesp::Helpers::render_value(result, ((double)(WiFi.getTxPower()) / 4), 1));
|
||||||
|
|
||||||
mDNS_start();
|
mDNS_start();
|
||||||
break;
|
break;
|
||||||
@@ -389,7 +394,6 @@ void NetworkSettings::read(NetworkSettings & settings, JsonObject root) {
|
|||||||
root["static_ip_config"] = settings.staticIPConfig;
|
root["static_ip_config"] = settings.staticIPConfig;
|
||||||
root["enableIPv6"] = settings.enableIPv6;
|
root["enableIPv6"] = settings.enableIPv6;
|
||||||
root["bandwidth20"] = settings.bandwidth20;
|
root["bandwidth20"] = settings.bandwidth20;
|
||||||
root["tx_power"] = settings.tx_power;
|
|
||||||
root["nosleep"] = settings.nosleep;
|
root["nosleep"] = settings.nosleep;
|
||||||
root["enableMDNS"] = settings.enableMDNS;
|
root["enableMDNS"] = settings.enableMDNS;
|
||||||
root["enableCORS"] = settings.enableCORS;
|
root["enableCORS"] = settings.enableCORS;
|
||||||
@@ -417,7 +421,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
|
|||||||
settings.staticIPConfig = root["static_ip_config"] | false;
|
settings.staticIPConfig = root["static_ip_config"] | false;
|
||||||
settings.enableIPv6 = root["enableIPv6"] | false;
|
settings.enableIPv6 = root["enableIPv6"] | false;
|
||||||
settings.bandwidth20 = root["bandwidth20"] | false;
|
settings.bandwidth20 = root["bandwidth20"] | false;
|
||||||
settings.tx_power = root["tx_power"] | 0;
|
settings.tx_power = static_cast<uint8_t>(root["tx_power"] | 0);
|
||||||
settings.nosleep = root["nosleep"] | false;
|
settings.nosleep = root["nosleep"] | false;
|
||||||
settings.enableMDNS = root["enableMDNS"] | true;
|
settings.enableMDNS = root["enableMDNS"] | true;
|
||||||
settings.enableCORS = root["enableCORS"] | false;
|
settings.enableCORS = root["enableCORS"] | false;
|
||||||
@@ -445,7 +449,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
|
|||||||
|
|
||||||
// see if we need to inform the user of a restart
|
// see if we need to inform the user of a restart
|
||||||
if (tx_power != settings.tx_power || enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin
|
if (tx_power != settings.tx_power || enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin
|
||||||
|| (ssid != settings.ssid && settings.ssid == "")) {
|
|| (ssid != settings.ssid && settings.ssid.isEmpty())) {
|
||||||
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef NetworkSettingsService_h
|
#ifndef NetworkSettingsService_h
|
||||||
#define NetworkSettingsService_h
|
#define NetworkSettingsService_h
|
||||||
|
|
||||||
#include <StatefulService.h>
|
#include "StatefulService.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <JsonUtils.h>
|
#include "JsonUtils.h"
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
#include <esp_wifi.h>
|
#include <esp_wifi.h>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
#define NETWORK_SETTINGS_FILE "/config/networkSettings.json"
|
#define NETWORK_SETTINGS_FILE "/config/networkSettings.json"
|
||||||
#define NETWORK_SETTINGS_SERVICE_PATH "/rest/networkSettings"
|
#define NETWORK_SETTINGS_SERVICE_PATH "/rest/networkSettings"
|
||||||
#define WIFI_RECONNECTION_DELAY 1000 * 3
|
#define WIFI_RECONNECTION_DELAY (1000 * 3)
|
||||||
|
|
||||||
#ifndef FACTORY_WIFI_SSID
|
#ifndef FACTORY_WIFI_SSID
|
||||||
#define FACTORY_WIFI_SSID ""
|
#define FACTORY_WIFI_SSID ""
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
#include <NetworkStatus.h>
|
#include "NetworkStatus.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
NetworkStatus::NetworkStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
NetworkStatus::NetworkStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(NETWORK_STATUS_SERVICE_PATH,
|
server->on(NETWORK_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&NetworkStatus::networkStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { networkStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
bool ethernet_connected = emsesp::EMSESP::system_.ethernet_connected();
|
bool ethernet_connected = emsesp::EMSESP::system_.ethernet_connected();
|
||||||
wl_status_t wifi_status = WiFi.status();
|
wl_status_t wifi_status = WiFi.status();
|
||||||
@@ -22,7 +20,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
|||||||
root["status"] = 10; // custom code #10 - ETHERNET_STATUS_CONNECTED
|
root["status"] = 10; // custom code #10 - ETHERNET_STATUS_CONNECTED
|
||||||
root["hostname"] = ETH.getHostname();
|
root["hostname"] = ETH.getHostname();
|
||||||
} else {
|
} else {
|
||||||
root["status"] = (uint8_t)wifi_status;
|
root["status"] = static_cast<uint8_t>(wifi_status);
|
||||||
root["hostname"] = WiFi.getHostname();
|
root["hostname"] = WiFi.getHostname();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <IPAddress.h>
|
#include <IPAddress.h>
|
||||||
#include <IPUtils.h>
|
|
||||||
|
|
||||||
#include <SecurityManager.h>
|
#include "IPUtils.h"
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#define MAX_NETWORK_STATUS_SIZE 1024
|
#define MAX_NETWORK_STATUS_SIZE 1024
|
||||||
#define NETWORK_STATUS_SERVICE_PATH "/rest/networkStatus"
|
#define NETWORK_STATUS_SERVICE_PATH "/rest/networkStatus"
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#include <OTASettingsService.h>
|
#include "OTASettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
OTASettingsService::OTASettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
OTASettingsService::OTASettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(OTASettings::read, OTASettings::update, this, server, OTA_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE)
|
, _fsPersistence(OTASettings::read, OTASettings::update, this, fs, OTA_SETTINGS_FILE)
|
||||||
, _arduinoOTA(nullptr) {
|
, _arduinoOTA(nullptr) {
|
||||||
WiFi.onEvent(std::bind(&OTASettingsService::WiFiEvent, this, _1, _2));
|
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
|
||||||
addUpdateHandler([&] { configureArduinoOTA(); }, false);
|
addUpdateHandler([this] { configureArduinoOTA(); }, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OTASettingsService::begin() {
|
void OTASettingsService::begin() {
|
||||||
@@ -32,7 +30,7 @@ void OTASettingsService::configureArduinoOTA() {
|
|||||||
|
|
||||||
if (_state.enabled) {
|
if (_state.enabled) {
|
||||||
_arduinoOTA = new ArduinoOTAClass;
|
_arduinoOTA = new ArduinoOTAClass;
|
||||||
_arduinoOTA->setPort(_state.port);
|
_arduinoOTA->setPort(static_cast<uint16_t>(_state.port));
|
||||||
_arduinoOTA->setPassword(_state.password.c_str());
|
_arduinoOTA->setPassword(_state.password.c_str());
|
||||||
|
|
||||||
_arduinoOTA->onStart([] { emsesp::EMSESP::system_.upload_status(true); });
|
_arduinoOTA->onStart([] { emsesp::EMSESP::system_.upload_status(true); });
|
||||||
@@ -64,7 +62,7 @@ void OTASettingsService::configureArduinoOTA() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OTASettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
void OTASettingsService::WiFiEvent(WiFiEvent_t event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef OTASettingsService_h
|
#ifndef OTASettingsService_h
|
||||||
#define OTASettingsService_h
|
#define OTASettingsService_h
|
||||||
|
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
|
|
||||||
#include <ArduinoOTA.h>
|
#include <ArduinoOTA.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
@@ -45,7 +45,7 @@ class OTASettingsService : public StatefulService<OTASettings> {
|
|||||||
ArduinoOTAClass * _arduinoOTA;
|
ArduinoOTAClass * _arduinoOTA;
|
||||||
|
|
||||||
void configureArduinoOTA();
|
void configureArduinoOTA();
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(WiFiEvent_t event);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,15 +1,22 @@
|
|||||||
#include <RestartService.h>
|
#include "RestartService.h"
|
||||||
|
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
RestartService::RestartService(AsyncWebServer * server, SecurityManager * securityManager) {
|
RestartService::RestartService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(RESTART_SERVICE_PATH, HTTP_POST, securityManager->wrapRequest(std::bind(&RestartService::restart, this, _1), AuthenticationPredicates::IS_ADMIN));
|
server->on(RESTART_SERVICE_PATH,
|
||||||
|
HTTP_POST,
|
||||||
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { restart(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
server->on(PARTITION_SERVICE_PATH,
|
server->on(PARTITION_SERVICE_PATH,
|
||||||
HTTP_POST,
|
HTTP_POST,
|
||||||
securityManager->wrapRequest(std::bind(&RestartService::partition, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { partition(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestartService::restartNow() {
|
||||||
|
WiFi.disconnect(true);
|
||||||
|
delay(500);
|
||||||
|
ESP.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestartService::restart(AsyncWebServerRequest * request) {
|
void RestartService::restart(AsyncWebServerRequest * request) {
|
||||||
@@ -19,7 +26,7 @@ void RestartService::restart(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RestartService::partition(AsyncWebServerRequest * request) {
|
void RestartService::partition(AsyncWebServerRequest * request) {
|
||||||
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
const esp_partition_t * factory_partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, nullptr);
|
||||||
if (factory_partition) {
|
if (factory_partition) {
|
||||||
esp_ota_set_boot_partition(factory_partition);
|
esp_ota_set_boot_partition(factory_partition);
|
||||||
emsesp::EMSESP::system_.store_nvs_values();
|
emsesp::EMSESP::system_.store_nvs_values();
|
||||||
@@ -27,7 +34,7 @@ void RestartService::partition(AsyncWebServerRequest * request) {
|
|||||||
request->send(200);
|
request->send(200);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const esp_partition_t * ota_partition = esp_ota_get_next_update_partition(NULL);
|
const esp_partition_t * ota_partition = esp_ota_get_next_update_partition(nullptr);
|
||||||
if (!ota_partition) {
|
if (!ota_partition) {
|
||||||
request->send(400); // bad request
|
request->send(400); // bad request
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#define RESTART_SERVICE_PATH "/rest/restart"
|
#define RESTART_SERVICE_PATH "/rest/restart"
|
||||||
#define PARTITION_SERVICE_PATH "/rest/partition"
|
#define PARTITION_SERVICE_PATH "/rest/partition"
|
||||||
@@ -14,11 +14,7 @@ class RestartService {
|
|||||||
public:
|
public:
|
||||||
RestartService(AsyncWebServer * server, SecurityManager * securityManager);
|
RestartService(AsyncWebServer * server, SecurityManager * securityManager);
|
||||||
|
|
||||||
static void restartNow() {
|
static void restartNow();
|
||||||
WiFi.disconnect(true);
|
|
||||||
delay(500);
|
|
||||||
ESP.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void restart(AsyncWebServerRequest * request);
|
void restart(AsyncWebServerRequest * request);
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#ifndef SecurityManager_h
|
#ifndef SecurityManager_h
|
||||||
#define SecurityManager_h
|
#define SecurityManager_h
|
||||||
|
|
||||||
#include <Features.h>
|
#include "Features.h"
|
||||||
#include <ArduinoJsonJWT.h>
|
#include "ArduinoJsonJWT.h"
|
||||||
|
#include "ESPUtils.h"
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <ESPUtils.h>
|
|
||||||
#include <AsyncJson.h>
|
#include <AsyncJson.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
@@ -26,28 +27,27 @@ class User {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
User(String username, String password, bool admin)
|
User(String username, String password, bool admin)
|
||||||
: username(username)
|
: username(std::move(username))
|
||||||
, password(password)
|
, password(std::move(password))
|
||||||
, admin(admin) {
|
, admin(admin) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Authentication {
|
class Authentication {
|
||||||
public:
|
public:
|
||||||
User * user;
|
User * user = nullptr;
|
||||||
boolean authenticated;
|
boolean authenticated = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Authentication(User & user)
|
explicit Authentication(const User & user)
|
||||||
: user(new User(user))
|
: user(new User(user))
|
||||||
, authenticated(true) {
|
, authenticated(true) {
|
||||||
}
|
}
|
||||||
Authentication()
|
|
||||||
: user(nullptr)
|
Authentication() = default;
|
||||||
, authenticated(false) {
|
|
||||||
}
|
|
||||||
~Authentication() {
|
~Authentication() {
|
||||||
delete (user);
|
delete user;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,13 +55,14 @@ typedef std::function<boolean(Authentication & authentication)> AuthenticationPr
|
|||||||
|
|
||||||
class AuthenticationPredicates {
|
class AuthenticationPredicates {
|
||||||
public:
|
public:
|
||||||
static bool NONE_REQUIRED(Authentication & authentication) {
|
static bool NONE_REQUIRED(const Authentication & authentication) {
|
||||||
|
(void)authentication;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
static bool IS_AUTHENTICATED(Authentication & authentication) {
|
static bool IS_AUTHENTICATED(const Authentication & authentication) {
|
||||||
return authentication.authenticated;
|
return authentication.authenticated;
|
||||||
};
|
};
|
||||||
static bool IS_ADMIN(Authentication & authentication) {
|
static bool IS_ADMIN(const Authentication & authentication) {
|
||||||
return authentication.authenticated && authentication.user->admin;
|
return authentication.authenticated && authentication.user->admin;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -76,7 +77,7 @@ class SecurityManager {
|
|||||||
/*
|
/*
|
||||||
* Generate a JWT for the user provided
|
* Generate a JWT for the user provided
|
||||||
*/
|
*/
|
||||||
virtual String generateJWT(User * user) = 0;
|
virtual String generateJWT(const User * user) = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the request header for the Authorization token
|
* Check the request header for the Authorization token
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
#include <SecuritySettingsService.h>
|
#include "SecuritySettingsService.h"
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
|
||||||
|
|
||||||
SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
|
SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
|
||||||
: _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this)
|
: _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this)
|
||||||
, _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE)
|
, _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE)
|
||||||
, _jwtHandler(FACTORY_JWT_SECRET) {
|
, _jwtHandler(FACTORY_JWT_SECRET) {
|
||||||
addUpdateHandler([&] { configureJWTHandler(); }, false);
|
addUpdateHandler([this] { configureJWTHandler(); }, false);
|
||||||
server->on(GENERATE_TOKEN_PATH,
|
server->on(GENERATE_TOKEN_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
wrapRequest(std::bind(&SecuritySettingsService::generateToken, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN));
|
SecuritySettingsService::wrapRequest([this](AsyncWebServerRequest * request) { generateToken(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecuritySettingsService::begin() {
|
void SecuritySettingsService::begin() {
|
||||||
@@ -30,7 +28,7 @@ Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerReques
|
|||||||
String value = tokenParamater->value();
|
String value = tokenParamater->value();
|
||||||
return authenticateJWT(value);
|
return authenticateJWT(value);
|
||||||
}
|
}
|
||||||
return Authentication();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecuritySettingsService::configureJWTHandler() {
|
void SecuritySettingsService::configureJWTHandler() {
|
||||||
@@ -43,37 +41,37 @@ Authentication SecuritySettingsService::authenticateJWT(String & jwt) {
|
|||||||
if (payloadDocument.is<JsonObject>()) {
|
if (payloadDocument.is<JsonObject>()) {
|
||||||
JsonObject parsedPayload = payloadDocument.as<JsonObject>();
|
JsonObject parsedPayload = payloadDocument.as<JsonObject>();
|
||||||
String username = parsedPayload["username"];
|
String username = parsedPayload["username"];
|
||||||
for (User _user : _state.users) {
|
for (const User & _user : _state.users) {
|
||||||
if (_user.username == username && validatePayload(parsedPayload, &_user)) {
|
if (_user.username == username && validatePayload(parsedPayload, &_user)) {
|
||||||
return Authentication(_user);
|
return Authentication(_user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Authentication();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Authentication SecuritySettingsService::authenticate(const String & username, const String & password) {
|
Authentication SecuritySettingsService::authenticate(const String & username, const String & password) {
|
||||||
for (User _user : _state.users) {
|
for (const User & _user : _state.users) {
|
||||||
if (_user.username == username && _user.password == password) {
|
if (_user.username == username && _user.password == password) {
|
||||||
return Authentication(_user);
|
return Authentication(_user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Authentication();
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void populateJWTPayload(JsonObject payload, User * user) {
|
inline void populateJWTPayload(JsonObject payload, const User * user) {
|
||||||
payload["username"] = user->username;
|
payload["username"] = user->username;
|
||||||
payload["admin"] = user->admin;
|
payload["admin"] = user->admin;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean SecuritySettingsService::validatePayload(JsonObject parsedPayload, User * user) {
|
boolean SecuritySettingsService::validatePayload(JsonObject parsedPayload, const User * user) {
|
||||||
JsonDocument jsonDocument;
|
JsonDocument jsonDocument;
|
||||||
JsonObject payload = jsonDocument.to<JsonObject>();
|
JsonObject payload = jsonDocument.to<JsonObject>();
|
||||||
populateJWTPayload(payload, user);
|
populateJWTPayload(payload, user);
|
||||||
return payload == parsedPayload;
|
return payload == parsedPayload;
|
||||||
}
|
}
|
||||||
|
|
||||||
String SecuritySettingsService::generateJWT(User * user) {
|
String SecuritySettingsService::generateJWT(const User * user) {
|
||||||
JsonDocument jsonDocument;
|
JsonDocument jsonDocument;
|
||||||
JsonObject payload = jsonDocument.to<JsonObject>();
|
JsonObject payload = jsonDocument.to<JsonObject>();
|
||||||
populateJWTPayload(payload, user);
|
populateJWTPayload(payload, user);
|
||||||
@@ -111,11 +109,11 @@ ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequest
|
|||||||
|
|
||||||
void SecuritySettingsService::generateToken(AsyncWebServerRequest * request) {
|
void SecuritySettingsService::generateToken(AsyncWebServerRequest * request) {
|
||||||
AsyncWebParameter * usernameParam = request->getParam("username");
|
AsyncWebParameter * usernameParam = request->getParam("username");
|
||||||
for (User _user : _state.users) {
|
for (const User & _user : _state.users) {
|
||||||
if (_user.username == usernameParam->value()) {
|
if (_user.username == usernameParam->value()) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
root["token"] = generateJWT(&_user);
|
root["token"] = generateJWT(&_user);
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@@ -123,34 +121,3 @@ void SecuritySettingsService::generateToken(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
request->send(401);
|
request->send(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SecuritySettings::read(SecuritySettings & settings, JsonObject root) {
|
|
||||||
// secret
|
|
||||||
root["jwt_secret"] = settings.jwtSecret;
|
|
||||||
|
|
||||||
// users
|
|
||||||
JsonArray users = root["users"].to<JsonArray>();
|
|
||||||
for (User user : settings.users) {
|
|
||||||
JsonObject userRoot = users.add<JsonObject>();
|
|
||||||
userRoot["username"] = user.username;
|
|
||||||
userRoot["password"] = user.password;
|
|
||||||
userRoot["admin"] = user.admin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StateUpdateResult SecuritySettings::update(JsonObject root, SecuritySettings & settings) {
|
|
||||||
// secret
|
|
||||||
settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET;
|
|
||||||
|
|
||||||
// users
|
|
||||||
settings.users.clear();
|
|
||||||
if (root["users"].is<JsonArray>()) {
|
|
||||||
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
|
||||||
settings.users.push_back(User(user["username"], user["password"], user["admin"]));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
settings.users.push_back(User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true));
|
|
||||||
settings.users.push_back(User(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false));
|
|
||||||
}
|
|
||||||
return StateUpdateResult::CHANGED;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#ifndef SecuritySettingsService_h
|
#ifndef SecuritySettingsService_h
|
||||||
#define SecuritySettingsService_h
|
#define SecuritySettingsService_h
|
||||||
|
|
||||||
#include <Features.h>
|
#include "Features.h"
|
||||||
#include <SecurityManager.h>
|
#include "SecurityManager.h"
|
||||||
#include <HttpEndpoint.h>
|
#include "HttpEndpoint.h"
|
||||||
#include <FSPersistence.h>
|
#include "FSPersistence.h"
|
||||||
|
|
||||||
#ifndef FACTORY_ADMIN_USERNAME
|
#ifndef FACTORY_ADMIN_USERNAME
|
||||||
#define FACTORY_ADMIN_USERNAME "admin"
|
#define FACTORY_ADMIN_USERNAME "admin"
|
||||||
@@ -33,23 +33,51 @@ class SecuritySettings {
|
|||||||
String jwtSecret;
|
String jwtSecret;
|
||||||
std::vector<User> users;
|
std::vector<User> users;
|
||||||
|
|
||||||
static void read(SecuritySettings & settings, JsonObject root);
|
static void read(SecuritySettings & settings, JsonObject root) {
|
||||||
static StateUpdateResult update(JsonObject root, SecuritySettings & settings);
|
// secret
|
||||||
|
root["jwt_secret"] = settings.jwtSecret;
|
||||||
|
|
||||||
|
// users
|
||||||
|
JsonArray users = root["users"].to<JsonArray>();
|
||||||
|
for (const User & user : settings.users) {
|
||||||
|
JsonObject userRoot = users.add<JsonObject>();
|
||||||
|
userRoot["username"] = user.username;
|
||||||
|
userRoot["password"] = user.password;
|
||||||
|
userRoot["admin"] = user.admin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static StateUpdateResult update(JsonObject root, SecuritySettings & settings) {
|
||||||
|
// secret
|
||||||
|
settings.jwtSecret = root["jwt_secret"] | FACTORY_JWT_SECRET;
|
||||||
|
|
||||||
|
// users
|
||||||
|
settings.users.clear();
|
||||||
|
if (root["users"].is<JsonArray>()) {
|
||||||
|
for (JsonVariant user : root["users"].as<JsonArray>()) {
|
||||||
|
settings.users.emplace_back(user["username"], user["password"], user["admin"]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
settings.users.emplace_back(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true);
|
||||||
|
settings.users.emplace_back(FACTORY_GUEST_USERNAME, FACTORY_GUEST_PASSWORD, false);
|
||||||
|
}
|
||||||
|
return StateUpdateResult::CHANGED;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SecuritySettingsService : public StatefulService<SecuritySettings>, public SecurityManager {
|
class SecuritySettingsService final : public StatefulService<SecuritySettings>, public SecurityManager {
|
||||||
public:
|
public:
|
||||||
SecuritySettingsService(AsyncWebServer * server, FS * fs);
|
SecuritySettingsService(AsyncWebServer * server, FS * fs);
|
||||||
|
|
||||||
void begin();
|
void begin();
|
||||||
|
|
||||||
// Functions to implement SecurityManager
|
// Functions to implement SecurityManager
|
||||||
Authentication authenticate(const String & username, const String & password);
|
Authentication authenticate(const String & username, const String & password) override;
|
||||||
Authentication authenticateRequest(AsyncWebServerRequest * request);
|
Authentication authenticateRequest(AsyncWebServerRequest * request) override;
|
||||||
String generateJWT(User * user);
|
String generateJWT(const User * user) override;
|
||||||
ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate);
|
ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) override;
|
||||||
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate);
|
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) override;
|
||||||
ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate);
|
ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpEndpoint<SecuritySettings> _httpEndpoint;
|
HttpEndpoint<SecuritySettings> _httpEndpoint;
|
||||||
@@ -68,7 +96,7 @@ class SecuritySettingsService : public StatefulService<SecuritySettings>, public
|
|||||||
/*
|
/*
|
||||||
* Verify the payload is correct
|
* Verify the payload is correct
|
||||||
*/
|
*/
|
||||||
boolean validatePayload(JsonObject parsedPayload, User * user);
|
boolean validatePayload(JsonObject parsedPayload, const User * user);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#include <StatefulService.h>
|
#include "StatefulService.h"
|
||||||
|
|
||||||
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;
|
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
#include <SystemStatus.h>
|
#include "SystemStatus.h"
|
||||||
|
|
||||||
#include <esp_ota_ops.h>
|
#include <esp_ota_ops.h>
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(SYSTEM_STATUS_SERVICE_PATH,
|
server->on(SYSTEM_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { systemStatus(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||||
emsesp::EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap
|
emsesp::EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap
|
||||||
|
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_DEBUG
|
||||||
root["emsesp_version"] = std::string(EMSESP_APP_VERSION) + " (DEBUG)";
|
root["emsesp_version"] = std::string(EMSESP_APP_VERSION) + " (DEBUG)";
|
||||||
@@ -49,11 +48,11 @@ void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
|||||||
root["psram_size"] = emsesp::EMSESP::system_.PSram();
|
root["psram_size"] = emsesp::EMSESP::system_.PSram();
|
||||||
root["free_psram"] = ESP.getFreePsram() / 1024;
|
root["free_psram"] = ESP.getFreePsram() / 1024;
|
||||||
}
|
}
|
||||||
const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, NULL);
|
const esp_partition_t * partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_APP_FACTORY, nullptr);
|
||||||
if (partition != NULL) { // factory partition found
|
if (partition != NULL) { // factory partition found
|
||||||
root["has_loader"] = true;
|
root["has_loader"] = true;
|
||||||
} else { // check for not empty, smaller OTA partition
|
} else { // check for not empty, smaller OTA partition
|
||||||
partition = esp_ota_get_next_update_partition(NULL);
|
partition = esp_ota_get_next_update_partition(nullptr);
|
||||||
if (partition) {
|
if (partition) {
|
||||||
uint64_t buffer;
|
uint64_t buffer;
|
||||||
esp_partition_read(partition, 0, &buffer, 8);
|
esp_partition_read(partition, 0, &buffer, 8);
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <FS.h>
|
#include <FS.h>
|
||||||
#include <LittleFS.h>
|
#include <LittleFS.h>
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
#include <UploadFileService.h>
|
#include "UploadFileService.h"
|
||||||
#include <esp_ota_ops.h>
|
|
||||||
#include <esp_app_format.h>
|
|
||||||
|
|
||||||
#include "../../src/emsesp_stub.hpp"
|
#include "../../src/emsesp_stub.hpp"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
#include <esp_app_format.h>
|
||||||
|
|
||||||
static bool is_firmware = false;
|
static String getFilenameExtension(const String & filename) {
|
||||||
static char md5[33] = "\0";
|
const auto pos = filename.lastIndexOf('.');
|
||||||
|
if (pos != -1) {
|
||||||
|
return filename.substring(static_cast<unsigned int>(pos) + 1);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * securityManager)
|
UploadFileService::UploadFileService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager) {
|
: _securityManager(securityManager)
|
||||||
server->on(UPLOAD_FILE_PATH,
|
, _is_firmware(false)
|
||||||
HTTP_POST,
|
, _md5() {
|
||||||
std::bind(&UploadFileService::uploadComplete, this, _1),
|
server->on(
|
||||||
std::bind(&UploadFileService::handleUpload, this, _1, _2, _3, _4, _5, _6));
|
UPLOAD_FILE_PATH,
|
||||||
|
HTTP_POST,
|
||||||
|
[this](AsyncWebServerRequest * request) { uploadComplete(request); },
|
||||||
|
[this](AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||||
|
handleUpload(request, filename, index, data, len, final);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void UploadFileService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
void UploadFileService::handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final) {
|
||||||
@@ -28,29 +35,27 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
|||||||
// at init
|
// at init
|
||||||
if (!index) {
|
if (!index) {
|
||||||
// check details of the file, to see if its a valid bin or json file
|
// check details of the file, to see if its a valid bin or json file
|
||||||
std::string fname(filename.c_str());
|
const String extension = getFilenameExtension(filename);
|
||||||
auto position = fname.find_last_of(".");
|
const std::size_t filesize = request->contentLength();
|
||||||
std::string extension = fname.substr(position + 1);
|
|
||||||
size_t fsize = request->contentLength();
|
|
||||||
|
|
||||||
is_firmware = false;
|
_is_firmware = false;
|
||||||
if ((extension == "bin") && (fsize > 1000000)) {
|
if ((extension == "bin") && (filesize > 1000000)) {
|
||||||
is_firmware = true;
|
_is_firmware = true;
|
||||||
} else if (extension == "json") {
|
} else if (extension == "json") {
|
||||||
md5[0] = '\0'; // clear md5
|
_md5[0] = '\0'; // clear md5
|
||||||
} else if (extension == "md5") {
|
} else if (extension == "md5") {
|
||||||
if (len == 32) {
|
if (len == _md5.size() - 1) {
|
||||||
memcpy(md5, data, 32);
|
std::memcpy(_md5.data(), data, _md5.size() - 1);
|
||||||
md5[32] = '\0';
|
_md5.back() = '\0';
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
md5[0] = '\0';
|
_md5.front() = '\0';
|
||||||
handleError(request, 406); // Not Acceptable - unsupported file type
|
handleError(request, 406); // Not Acceptable - unsupported file type
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_firmware) {
|
if (_is_firmware) {
|
||||||
// Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5
|
// Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5
|
||||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||||
if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) {
|
if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) {
|
||||||
@@ -74,12 +79,12 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// it's firmware - initialize the ArduinoOTA updater
|
// it's firmware - initialize the ArduinoOTA updater
|
||||||
if (Update.begin(fsize - sizeof(esp_image_header_t))) {
|
if (Update.begin(filesize - sizeof(esp_image_header_t))) {
|
||||||
if (strlen(md5) == 32) {
|
if (strlen(_md5.data()) == _md5.size() - 1) {
|
||||||
Update.setMD5(md5);
|
Update.setMD5(_md5.data());
|
||||||
md5[0] = '\0';
|
_md5.front() = '\0';
|
||||||
}
|
}
|
||||||
request->onDisconnect(UploadFileService::handleEarlyDisconnect); // success, let's make sure we end the update if the client hangs up
|
request->onDisconnect([this]() { handleEarlyDisconnect(); }); // success, let's make sure we end the update if the client hangs up
|
||||||
} else {
|
} else {
|
||||||
handleError(request, 507); // failed to begin, send an error response Insufficient Storage
|
handleError(request, 507); // failed to begin, send an error response Insufficient Storage
|
||||||
return;
|
return;
|
||||||
@@ -90,23 +95,17 @@ void UploadFileService::handleUpload(AsyncWebServerRequest * request, const Stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_firmware) {
|
if (!_is_firmware) {
|
||||||
if (len) {
|
if (len && len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
||||||
if (len != request->_tempFile.write(data, len)) { // stream the incoming chunk to the opened file
|
handleError(request, 507); // 507-Insufficient Storage
|
||||||
handleError(request, 507); // 507-Insufficient Storage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!request->_tempObject) { // if we haven't delt with an error, continue with the firmware update
|
||||||
// if we haven't delt with an error, continue with the firmware update
|
if (Update.write(data, len) != len) {
|
||||||
if (!request->_tempObject) {
|
handleError(request, 500);
|
||||||
if (Update.write(data, len) != len) {
|
return;
|
||||||
handleError(request, 500);
|
}
|
||||||
}
|
if (final && !Update.end(true)) {
|
||||||
if (final) {
|
handleError(request, 500);
|
||||||
if (!Update.end(true)) {
|
|
||||||
handleError(request, 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,7 +123,7 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
|||||||
|
|
||||||
// check if it was a firmware upgrade
|
// check if it was a firmware upgrade
|
||||||
// if no error, send the success response as a JSON
|
// if no error, send the success response as a JSON
|
||||||
if (is_firmware && !request->_tempObject) {
|
if (_is_firmware && !request->_tempObject) {
|
||||||
emsesp::EMSESP::system_.store_nvs_values();
|
emsesp::EMSESP::system_.store_nvs_values();
|
||||||
request->onDisconnect(RestartService::restartNow);
|
request->onDisconnect(RestartService::restartNow);
|
||||||
AsyncWebServerResponse * response = request->beginResponse(200);
|
AsyncWebServerResponse * response = request->beginResponse(200);
|
||||||
@@ -132,10 +131,10 @@ void UploadFileService::uploadComplete(AsyncWebServerRequest * request) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(md5) == 32) {
|
if (strlen(_md5.data()) == _md5.size() - 1) {
|
||||||
auto * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
root["md5"] = md5;
|
root["md5"] = _md5.data();
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
@@ -163,6 +162,6 @@ void UploadFileService::handleError(AsyncWebServerRequest * request, int code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UploadFileService::handleEarlyDisconnect() {
|
void UploadFileService::handleEarlyDisconnect() {
|
||||||
is_firmware = false;
|
_is_firmware = false;
|
||||||
Update.abort();
|
Update.abort();
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
#ifndef UploadFileService_h
|
#ifndef UploadFileService_h
|
||||||
#define UploadFileService_h
|
#define UploadFileService_h
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include "RestartService.h"
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
#include <Update.h>
|
#include <Update.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include <LittleFS.h>
|
#include <array>
|
||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
|
||||||
#include <SecurityManager.h>
|
|
||||||
#include <RestartService.h>
|
|
||||||
|
|
||||||
#define UPLOAD_FILE_PATH "/rest/uploadFile"
|
#define UPLOAD_FILE_PATH "/rest/uploadFile"
|
||||||
#define TEMP_FILENAME_PATH "/tmp_upload"
|
#define TEMP_FILENAME_PATH "/tmp_upload"
|
||||||
@@ -20,11 +20,14 @@ class UploadFileService {
|
|||||||
UploadFileService(AsyncWebServer * server, SecurityManager * securityManager);
|
UploadFileService(AsyncWebServer * server, SecurityManager * securityManager);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SecurityManager * _securityManager;
|
SecurityManager * _securityManager;
|
||||||
void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final);
|
bool _is_firmware;
|
||||||
void uploadComplete(AsyncWebServerRequest * request);
|
std::array<char, 33> _md5;
|
||||||
void handleError(AsyncWebServerRequest * request, int code);
|
|
||||||
static void handleEarlyDisconnect();
|
void handleUpload(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final);
|
||||||
|
void uploadComplete(AsyncWebServerRequest * request);
|
||||||
|
void handleError(AsyncWebServerRequest * request, int code);
|
||||||
|
void handleEarlyDisconnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
#include <WiFiScanner.h>
|
#include "WiFiScanner.h"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
|
WiFiScanner::WiFiScanner(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(SCAN_NETWORKS_SERVICE_PATH,
|
server->on(SCAN_NETWORKS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scanNetworks(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
server->on(LIST_NETWORKS_SERVICE_PATH,
|
server->on(LIST_NETWORKS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { listNetworks(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
};
|
};
|
||||||
|
|
||||||
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
||||||
@@ -21,18 +19,18 @@ void WiFiScanner::scanNetworks(AsyncWebServerRequest * request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
|
void WiFiScanner::listNetworks(AsyncWebServerRequest * request) {
|
||||||
int numNetworks = WiFi.scanComplete();
|
const int numNetworks = WiFi.scanComplete();
|
||||||
if (numNetworks > -1) {
|
if (numNetworks > -1) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false);
|
auto * response = new AsyncJsonResponse(false);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
JsonArray networks = root["networks"].to<JsonArray>();
|
JsonArray networks = root["networks"].to<JsonArray>();
|
||||||
for (int i = 0; i < numNetworks; i++) {
|
for (uint8_t i = 0; i < numNetworks; i++) {
|
||||||
JsonObject network = networks.add<JsonObject>();
|
JsonObject network = networks.add<JsonObject>();
|
||||||
network["rssi"] = WiFi.RSSI(i);
|
network["rssi"] = WiFi.RSSI(i);
|
||||||
network["ssid"] = WiFi.SSID(i);
|
network["ssid"] = WiFi.SSID(i);
|
||||||
network["bssid"] = WiFi.BSSIDstr(i);
|
network["bssid"] = WiFi.BSSIDstr(i);
|
||||||
network["channel"] = WiFi.channel(i);
|
network["channel"] = WiFi.channel(i);
|
||||||
network["encryption_type"] = (uint8_t)WiFi.encryptionType(i);
|
network["encryption_type"] = static_cast<uint8_t>(WiFi.encryptionType(i));
|
||||||
}
|
}
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SecurityManager.h>
|
|
||||||
|
#include "SecurityManager.h"
|
||||||
|
|
||||||
#define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks"
|
#define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks"
|
||||||
#define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks"
|
#define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks"
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class StatefulService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater, ) {
|
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater) {
|
||||||
beginTransaction();
|
beginTransaction();
|
||||||
StateUpdateResult result = stateUpdater(_state);
|
StateUpdateResult result = stateUpdater(_state);
|
||||||
endTransaction();
|
endTransaction();
|
||||||
@@ -85,7 +85,7 @@ class StatefulService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
StateUpdateResult update(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater, ) {
|
StateUpdateResult update(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater) {
|
||||||
beginTransaction();
|
beginTransaction();
|
||||||
StateUpdateResult result = stateUpdater(jsonObject, _state);
|
StateUpdateResult result = stateUpdater(jsonObject, _state);
|
||||||
endTransaction();
|
endTransaction();
|
||||||
|
|||||||
@@ -38,8 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
|
|
||||||
#include <ESP8266React.h>
|
#include "ESP8266React.h"
|
||||||
|
|
||||||
#include "web/WebStatusService.h"
|
#include "web/WebStatusService.h"
|
||||||
#include "web/WebDataService.h"
|
#include "web/WebDataService.h"
|
||||||
#include "web/WebSettingsService.h"
|
#include "web/WebSettingsService.h"
|
||||||
|
|||||||
@@ -24,8 +24,7 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "default_settings.h"
|
#include "default_settings.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "ESP8266React.h"
|
||||||
#include <ESP8266React.h>
|
|
||||||
|
|
||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
|
|
||||||
|
|||||||
@@ -21,16 +21,15 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
#include <uuid/log.h>
|
||||||
|
|
||||||
// UART drivers
|
// UART drivers
|
||||||
#if defined(ESP32)
|
#if defined(ESP32)
|
||||||
#include "uart/emsuart_esp32.h"
|
#include "uart/emsuart_esp32.h"
|
||||||
#elif defined(EMSESP_STANDALONE)
|
#elif defined(EMSESP_STANDALONE)
|
||||||
#include <emsuart_standalone.h>
|
#include "emsuart_standalone.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <uuid/log.h>
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
|
#define MAX_RX_TELEGRAMS 10 // size of Rx queue
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "3.6.5-dev.13"
|
#define EMSESP_APP_VERSION "3.6.5-dev.14"
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
uint32_t WebAPIService::api_count_ = 0;
|
uint32_t WebAPIService::api_count_ = 0;
|
||||||
@@ -27,17 +25,26 @@ uint16_t WebAPIService::api_fails_ = 0;
|
|||||||
|
|
||||||
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _securityManager(securityManager)
|
: _securityManager(securityManager)
|
||||||
, _apiHandler("/api", std::bind(&WebAPIService::webAPIService_post, this, _1, _2)) { // for POSTS, must use 'Content-Type: application/json' in header
|
, _apiHandler(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService_post(request, json); }) { // for POSTs
|
||||||
server->on("/api", HTTP_GET, std::bind(&WebAPIService::webAPIService_get, this, _1)); // for GETS
|
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { webAPIService_get(request); }); // for GETs
|
||||||
server->addHandler(&_apiHandler);
|
server->addHandler(&_apiHandler);
|
||||||
|
|
||||||
// for settings
|
// for settings
|
||||||
server->on(GET_SETTINGS_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSettings, this, _1), AuthenticationPredicates::IS_ADMIN));
|
server->on(GET_SETTINGS_PATH,
|
||||||
|
HTTP_GET,
|
||||||
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
server->on(GET_CUSTOMIZATIONS_PATH,
|
server->on(GET_CUSTOMIZATIONS_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebAPIService::getCustomizations, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getCustomizations(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
server->on(GET_SCHEDULE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSchedule, this, _1), AuthenticationPredicates::IS_ADMIN));
|
|
||||||
server->on(GET_ENTITIES_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getEntities, this, _1), AuthenticationPredicates::IS_ADMIN));
|
server->on(GET_SCHEDULE_PATH,
|
||||||
|
HTTP_GET,
|
||||||
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSchedule(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
|
server->on(GET_ENTITIES_PATH,
|
||||||
|
HTTP_GET,
|
||||||
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTTP GET
|
// HTTP GET
|
||||||
|
|||||||
@@ -20,8 +20,6 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebCustomEntity::read,
|
: _httpEndpoint(WebCustomEntity::read,
|
||||||
WebCustomEntity::update,
|
WebCustomEntity::update,
|
||||||
|
|||||||
@@ -20,27 +20,24 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
bool WebCustomization::_start = true;
|
bool WebCustomization::_start = true;
|
||||||
|
|
||||||
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
|
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
|
||||||
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
|
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
|
||||||
securityManager->wrapCallback(std::bind(&WebCustomizationService::customization_entities, this, _1, _2),
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
|
||||||
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
AuthenticationPredicates::IS_AUTHENTICATED)) {
|
||||||
server->on(DEVICE_ENTITIES_PATH,
|
server->on(DEVICE_ENTITIES_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::device_entities, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
|
|
||||||
server->on(DEVICES_SERVICE_PATH,
|
server->on(DEVICES_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
|
server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
|
||||||
HTTP_POST,
|
HTTP_POST,
|
||||||
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
_masked_entities_handler.setMethod(HTTP_POST);
|
_masked_entities_handler.setMethod(HTTP_POST);
|
||||||
_masked_entities_handler.setMaxContentLength(2048);
|
_masked_entities_handler.setMaxContentLength(2048);
|
||||||
|
|||||||
@@ -20,33 +20,36 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
|
: _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
|
||||||
securityManager->wrapCallback(std::bind(&WebDataService::write_device_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_device_value(request, json); },
|
||||||
|
AuthenticationPredicates::IS_ADMIN))
|
||||||
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
|
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
|
||||||
securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2),
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
|
||||||
|
JsonVariant json) { write_temperature_sensor(request, json); },
|
||||||
AuthenticationPredicates::IS_ADMIN))
|
AuthenticationPredicates::IS_ADMIN))
|
||||||
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
|
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
|
||||||
securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
|
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_analog_sensor(request, json); },
|
||||||
|
AuthenticationPredicates::IS_ADMIN)) {
|
||||||
// GET's
|
// GET's
|
||||||
server->on(DEVICE_DATA_SERVICE_PATH,
|
server->on(DEVICE_DATA_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebDataService::device_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
|
|
||||||
server->on(CORE_DATA_SERVICE_PATH,
|
server->on(CORE_DATA_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { core_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
server->on(SENSOR_DATA_SERVICE_PATH,
|
server->on(SENSOR_DATA_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebDataService::sensor_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { sensor_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
|
||||||
// POST's
|
// POST's
|
||||||
server->on(SCAN_DEVICES_SERVICE_PATH,
|
server->on(SCAN_DEVICES_SERVICE_PATH,
|
||||||
HTTP_POST,
|
HTTP_POST,
|
||||||
securityManager->wrapRequest(std::bind(&WebDataService::scan_devices, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scan_devices(request); }, AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
|
|
||||||
_write_value_handler.setMethod(HTTP_POST);
|
_write_value_handler.setMethod(HTTP_POST);
|
||||||
_write_value_handler.setMaxContentLength(256);
|
_write_value_handler.setMaxContentLength(256);
|
||||||
|
|||||||
@@ -18,19 +18,18 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
using namespace std::placeholders;
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
|
||||||
: events_(EVENT_SOURCE_LOG_PATH)
|
: events_(EVENT_SOURCE_LOG_PATH)
|
||||||
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2)) {
|
, setValues_(LOG_SETTINGS_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { setValues(request, json); }) {
|
||||||
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
|
||||||
|
|
||||||
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1)); // get settings
|
// get settings
|
||||||
|
server->on(LOG_SETTINGS_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { getValues(request); });
|
||||||
|
|
||||||
// for bring back the whole log - is a command, hence a POST
|
// for bring back the whole log - is a command, hence a POST
|
||||||
server->on(FETCH_LOG_PATH, HTTP_POST, std::bind(&WebLogService::fetchLog, this, _1));
|
server->on(FETCH_LOG_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { fetchLog(request); });
|
||||||
|
|
||||||
server->addHandler(&setValues_);
|
server->addHandler(&setValues_);
|
||||||
server->addHandler(&events_);
|
server->addHandler(&events_);
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebScheduler::read, WebScheduler::update, this, server, EMSESP_SCHEDULER_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED)
|
: _httpEndpoint(WebScheduler::read, WebScheduler::update, this, server, EMSESP_SCHEDULER_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED)
|
||||||
, _fsPersistence(WebScheduler::read, WebScheduler::update, this, fs, EMSESP_SCHEDULER_FILE) {
|
, _fsPersistence(WebScheduler::read, WebScheduler::update, this, fs, EMSESP_SCHEDULER_FILE) {
|
||||||
|
|||||||
@@ -22,17 +22,13 @@ namespace emsesp {
|
|||||||
|
|
||||||
uint8_t WebSettings::flags_ = 0;
|
uint8_t WebSettings::flags_ = 0;
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||||
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
|
||||||
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
|
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
|
||||||
// GET
|
|
||||||
server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH,
|
server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebSettingsService::board_profile, this, _1), AuthenticationPredicates::IS_ADMIN));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { board_profile(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
|
addUpdateHandler([this] { onUpdate(); }, false);
|
||||||
addUpdateHandler([&] { onUpdate(); }, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebSettings::read(WebSettings & settings, JsonObject root) {
|
void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||||
|
|||||||
@@ -18,14 +18,12 @@
|
|||||||
|
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
|
|
||||||
using namespace std::placeholders; // for `_1` etc
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
|
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||||
server->on(EMSESP_STATUS_SERVICE_PATH,
|
server->on(EMSESP_STATUS_SERVICE_PATH,
|
||||||
HTTP_GET,
|
HTTP_GET,
|
||||||
securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { webStatusService(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
||||||
|
|||||||
Reference in New Issue
Block a user