Merge remote-tracking branch 'origin/dev' for 3.6.5

This commit is contained in:
proddy
2024-03-23 17:56:05 +01:00
444 changed files with 21644 additions and 19030 deletions

View File

@@ -17,17 +17,16 @@
#ifdef EMSESP_STANDALONE
#include <Arduino.h>
#include <stdio.h>
#include <stdarg.h>
#include <iostream>
#include <thread>
#include <atomic>
#include <string>
#include <Network.h>
#include "Arduino.h"
#include "Network.h"
NativeConsole Serial;

View File

@@ -25,16 +25,14 @@
#include <cstring>
#include <string>
#include <math.h>
#include <algorithm> // for count_if
#include <algorithm>
#include <Print.h>
#include <Printable.h>
#include <Stream.h>
#include <WString.h>
#include <iostream>
#include "WString.h"
typedef double double_t;
#define ICACHE_FLASH_ATTR
@@ -188,6 +186,4 @@ void yield(void);
void setup(void);
void loop(void);
#endif

View File

@@ -1,8 +1,10 @@
#ifndef ASYNC_JSON_H_
#define ASYNC_JSON_H_
#include <ArduinoJson.h>
#include <ESPAsyncWebServer.h>
#include "ESPAsyncWebServer.h"
#define DYNAMIC_JSON_DOCUMENT_SIZE 1024
@@ -42,71 +44,24 @@ class ChunkPrint : public Print {
class PrettyAsyncJsonResponse {
protected:
DynamicJsonDocument _jsonBuffer;
JsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
public:
PrettyAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
PrettyAsyncJsonResponse(bool isArray = false)
: _isValid{false} {
if (isArray)
_root = _jsonBuffer.createNestedArray();
_root = _jsonBuffer.to<JsonArray>();
else
_root = _jsonBuffer.createNestedObject();
_root = _jsonBuffer.add<JsonObject>();
}
~PrettyAsyncJsonResponse() {
}
JsonVariant & getRoot() {
return _root;
}
bool _sourceValid() const {
return _isValid;
}
size_t setLength() {
return 0;
}
void setContentType(const char * s) {
}
size_t getSize() {
return _jsonBuffer.size();
}
size_t _fillBuffer(uint8_t * data, size_t len) {
return len;
}
void setCode(uint16_t) {
}
};
class MsgpackAsyncJsonResponse {
protected:
DynamicJsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
public:
MsgpackAsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
if (isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
~MsgpackAsyncJsonResponse() {
}
JsonVariant & getRoot() {
JsonVariant getRoot() {
return _root;
}
@@ -135,25 +90,26 @@ class MsgpackAsyncJsonResponse {
class AsyncJsonResponse {
protected:
DynamicJsonDocument _jsonBuffer;
JsonDocument _jsonBuffer;
JsonVariant _root;
bool _isValid;
bool _isMsgPack;
public:
AsyncJsonResponse(bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE)
: _jsonBuffer(maxJsonBufferSize)
, _isValid{false} {
AsyncJsonResponse(bool isArray = false, bool isMsgPack = false)
: _isValid{false}
, _isMsgPack{isMsgPack} {
if (isArray)
_root = _jsonBuffer.createNestedArray();
_root = _jsonBuffer.to<JsonArray>();
else
_root = _jsonBuffer.createNestedObject();
_root = _jsonBuffer.add<JsonObject>();
}
~AsyncJsonResponse() {
}
JsonVariant & getRoot() {
JsonVariant getRoot() {
return _root;
}
@@ -175,9 +131,12 @@ class AsyncJsonResponse {
void setCode(uint16_t) {
}
void setContentType(const char * s) {
}
};
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant & json)> ArJsonRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction;
class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
private:
@@ -224,7 +183,7 @@ class AsyncCallbackJsonWebHandler : public AsyncWebHandler {
virtual void handleRequest(AsyncWebServerRequest * request) override final {
if (_onRequest) {
if (request->_tempObject != NULL) {
DynamicJsonDocument jsonBuffer(1024);
JsonDocument jsonBuffer;
DeserializationError error = deserializeJson(jsonBuffer, (uint8_t *)(request->_tempObject));
if (!error) {
JsonVariant json = jsonBuffer.as<JsonVariant>();

View File

@@ -2,6 +2,7 @@
#define ASYNCTCP_H_
#include "Arduino.h"
#include <functional>
class AsyncClient;

View File

@@ -1,21 +1,19 @@
#ifndef ESP8266React_h
#define ESP8266React_h
#include <Arduino.h>
#include <ArduinoJson.h>
#include <AsyncJson.h>
#include <espMqttClient.h>
#include <ESPAsyncWebServer.h>
#include <list>
#include <FS.h>
#include <SecurityManager.h>
#include <SecuritySettingsService.h>
#include <StatefulService.h>
#include <Network.h>
#include "Arduino.h"
#include "ArduinoJson.h"
#include "AsyncJson.h"
#include "ESPAsyncWebServer.h"
#include "FS.h"
#include "SecurityManager.h"
#include "SecuritySettingsService.h"
#include "StatefulService.h"
#include "Network.h"
#include <espMqttClient.h>
#define AP_SETTINGS_FILE "/config/apSettings.json"
#define MQTT_SETTINGS_FILE "/config/mqttSettings.json"
@@ -59,26 +57,29 @@ class DummySettings {
uint16_t publish_time_sensor = 10;
uint16_t publish_time_heartbeat = 60;
String hostname = "ems-esp";
String jwtSecret = "ems-esp";
String ssid = "ems-esp";
String password = "ems-esp";
String bssid = "";
String localIP = "";
String gatewayIP = "";
String subnetMask = "";
bool staticIPConfig = false;
String dnsIP1 = "";
String dnsIP2 = "";
bool enableIPv6 = false;
bool enableMDNS = true;
bool enableCORS = false;
String CORSOrigin = "*";
String hostname = "ems-esp";
String jwtSecret = "ems-esp";
String ssid = "ems-esp";
String password = "ems-esp";
String bssid = "";
String localIP = "";
String gatewayIP = "";
String subnetMask = "";
bool staticIPConfig = false;
String dnsIP1 = "";
String dnsIP2 = "";
bool enableIPv6 = false;
bool enableMDNS = true;
bool enableCORS = false;
String CORSOrigin = "*";
uint8_t tx_power = 0;
static void read(DummySettings & settings, JsonObject & root){};
uint8_t provisionMode = 0;
static void read(DummySettings & settings, JsonObject root){};
static void read(DummySettings & settings){};
static StateUpdateResult update(JsonObject & root, DummySettings & settings) {
static StateUpdateResult update(JsonObject root, DummySettings & settings) {
return StateUpdateResult::CHANGED;
}
};
@@ -95,6 +96,9 @@ class DummySettingsService : public StatefulService<DummySettings> {
#define SecuritySettings DummySettings
#define MqttSettings DummySettings
#define NTPSettings DummySettings
#define OTASettings DummySettings
#define APSettings DummySettings
class ESP8266React {
public:
@@ -103,7 +107,6 @@ class ESP8266React {
, _securitySettingsService(server, fs){};
void begin() {
// initialize mqtt
_mqttClient = new espMqttClient();
};
void loop(){};
@@ -116,6 +119,10 @@ class ESP8266React {
return _mqttClient;
}
bool apStatus() {
return false;
}
void setWill(const char * will_topic) {
}
void onMessage(espMqttClientTypes::OnMessageCallback callback) {
@@ -137,6 +144,14 @@ class ESP8266React {
return &_settings;
}
StatefulService<DummySettings> * getOTASettingsService() {
return &_settings;
}
StatefulService<DummySettings> * getAPSettingsService() {
return &_settings;
}
private:
DummySettingsService _settings;
SecuritySettingsService _securitySettingsService;
@@ -152,7 +167,7 @@ class EMSESPSettingsService {
class JsonUtils {
public:
static void writeIP(JsonObject & root, const String & key, const String & ip) {
static void writeIP(JsonObject root, const String & key, const String & ip) {
root[key] = ip;
}
};

View File

@@ -2,9 +2,9 @@
#define _ESPAsyncWebServer_H_
#include "Arduino.h"
#include "AsyncTCP.h"
#include <functional>
#include <AsyncTCP.h>
#include <ArduinoJson.h>
class AsyncWebServer;
@@ -213,6 +213,7 @@ class AsyncWebServerResponse {
typedef std::function<void(AsyncWebServerRequest * request)> ArRequestHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, const String & filename, size_t index, uint8_t * data, size_t len, bool final)> ArUploadHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, uint8_t * data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
typedef std::function<void(AsyncWebServerRequest * request, JsonVariant json)> ArJsonRequestHandlerFunction; // added by proddy
class AsyncWebServer {
protected:
@@ -232,6 +233,7 @@ class AsyncWebServer {
}
void on(const char * uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest){};
void on(const char * uri, ArJsonRequestHandlerFunction onRequest){}; // added by proddy
};

View File

@@ -21,9 +21,10 @@
#ifndef FS_H
#define FS_H
#include "Arduino.h"
#include <memory>
#include <string>
#include <Arduino.h>
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
@@ -53,7 +54,7 @@ class File : public Stream {
int peek() override;
void flush() override;
size_t read(uint8_t * buf, size_t size);
size_t readBytes(char * buffer, size_t length) {
size_t readBytes(char * buffer, size_t length) override {
return read((uint8_t *)buffer, length);
}

View File

@@ -1,38 +1,32 @@
#ifndef FSPersistence_h
#define FSPersistence_h
#include <StatefulService.h>
#include <FS.h>
#include "StatefulService.h"
#include "FS.h"
template <class T>
class FSPersistence {
public:
FSPersistence(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater,
StatefulService<T> * statefulService,
FS * fs,
const char * filePath,
size_t bufferSize = FS_BUFFER_SIZE)
FSPersistence(JsonStateReader<T> stateReader, JsonStateUpdater<T> stateUpdater, StatefulService<T> * statefulService, FS * fs, const char * filePath)
: _stateReader(stateReader)
, _stateUpdater(stateUpdater)
, _statefulService(statefulService)
, _fs(fs)
, _filePath(filePath)
, _bufferSize(bufferSize)
, _updateHandlerId(0) {
enableUpdateHandler();
}
void readFromFS() {
Serial.println();
Serial.print("Fake reading file ");
Serial.println(_filePath);
// Serial.println();
// Serial.print("Fake reading file ");
// Serial.println(_filePath);
applyDefaults();
}
bool writeToFS() {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
JsonObject jsonObject = jsonDocument.to<JsonObject>();
JsonDocument jsonDocument;
JsonObject jsonObject = jsonDocument.to<JsonObject>();
_statefulService->read(jsonObject, _stateReader);
return true;
}
@@ -46,7 +40,7 @@ class FSPersistence {
void enableUpdateHandler() {
if (!_updateHandlerId) {
_updateHandlerId = _statefulService->addUpdateHandler([&](const String & originId) { writeToFS(); });
_updateHandlerId = _statefulService->addUpdateHandler([this] { writeToFS(); });
}
}
@@ -56,13 +50,12 @@ class FSPersistence {
StatefulService<T> * _statefulService;
FS * _fs;
const char * _filePath;
size_t _bufferSize;
update_handler_id_t _updateHandlerId;
protected:
virtual void applyDefaults() {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(_bufferSize);
JsonObject jsonObject = jsonDocument.as<JsonObject>();
JsonDocument jsonDocument;
JsonObject jsonObject = jsonDocument.as<JsonObject>();
_statefulService->updateWithoutPropagation(jsonObject, _stateUpdater);
}
};

View File

@@ -1,8 +1,6 @@
#ifndef Features_h
#define Features_h
#define FT_ENABLED(feature) feature
// project feature off by default
#ifndef FT_PROJECT
#define FT_PROJECT 0

View File

@@ -3,11 +3,11 @@
#include <functional>
#include <AsyncJson.h>
#include <ESPAsyncWebServer.h>
#include "AsyncJson.h"
#include "ESPAsyncWebServer.h"
#include <SecurityManager.h>
#include <StatefulService.h>
#include "SecurityManager.h"
#include "StatefulService.h"
#define HTTP_ENDPOINT_ORIGIN_ID "http"
@@ -19,27 +19,19 @@ class HttpGetEndpoint {
AsyncWebServer * server,
const String & servicePath,
SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN)
: _stateReader(stateReader)
, _statefulService(statefulService)
, _bufferSize(bufferSize) {
, _statefulService(statefulService) {
}
HttpGetEndpoint(JsonStateReader<T> stateReader,
StatefulService<T> * statefulService,
AsyncWebServer * server,
const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
HttpGetEndpoint(JsonStateReader<T> stateReader, StatefulService<T> * statefulService, AsyncWebServer * server, const String & servicePath)
: _stateReader(stateReader)
, _statefulService(statefulService)
, _bufferSize(bufferSize) {
, _statefulService(statefulService) {
}
protected:
JsonStateReader<T> _stateReader;
StatefulService<T> * _statefulService;
size_t _bufferSize;
void fetchSettings(AsyncWebServerRequest * request) {
}
@@ -54,33 +46,28 @@ class HttpPostEndpoint {
AsyncWebServer * server,
const String & servicePath,
SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN)
: _stateReader(stateReader)
, _stateUpdater(stateUpdater)
, _statefulService(statefulService)
, _bufferSize(bufferSize) {
, _statefulService(statefulService) {
}
HttpPostEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater,
StatefulService<T> * statefulService,
AsyncWebServer * server,
const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
const String & servicePath)
: _stateReader(stateReader)
, _stateUpdater(stateUpdater)
, _statefulService(statefulService)
, _bufferSize(bufferSize) {
, _statefulService(statefulService) {
}
protected:
JsonStateReader<T> _stateReader;
JsonStateUpdater<T> _stateUpdater;
StatefulService<T> * _statefulService;
size_t _bufferSize;
void updateSettings(AsyncWebServerRequest * request, JsonVariant & json) {
void updateSettings(AsyncWebServerRequest * request, JsonVariant json) {
if (!json.is<JsonObject>()) {
return;
}
@@ -103,20 +90,18 @@ class HttpEndpoint : public HttpGetEndpoint<T>, public HttpPostEndpoint<T> {
AsyncWebServer * server,
const String & servicePath,
SecurityManager * securityManager,
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize)
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate, bufferSize) {
AuthenticationPredicate authenticationPredicate = AuthenticationPredicates::IS_ADMIN)
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, securityManager, authenticationPredicate)
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, securityManager, authenticationPredicate) {
}
HttpEndpoint(JsonStateReader<T> stateReader,
JsonStateUpdater<T> stateUpdater,
StatefulService<T> * statefulService,
AsyncWebServer * server,
const String & servicePath,
size_t bufferSize = DEFAULT_BUFFER_SIZE)
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath, bufferSize)
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath, bufferSize) {
const String & servicePath)
: HttpGetEndpoint<T>(stateReader, statefulService, server, servicePath)
, HttpPostEndpoint<T>(stateReader, stateUpdater, statefulService, server, servicePath) {
}
};

View File

@@ -17,9 +17,9 @@
*/
#ifdef ENV_NATIVE
#include <Arduino.h>
#include <FS.h>
#include <LittleFS.h>
#include "Arduino.h"
#include "FS.h"
#include "LittleFS.h"
fs::LittleFSFS LittleFS;

View File

@@ -1,7 +1,8 @@
#ifndef Network_h
#define Network_h
#include <Arduino.h>
#include "Arduino.h"
#include <functional>
#include <IPAddress.h>
@@ -11,6 +12,21 @@
#define WIFI_AP WIFI_MODE_AP
#define WIFI_AP_STA WIFI_MODE_APSTA
typedef enum {
WIFI_POWER_19_5dBm = 78, // 19.5dBm
WIFI_POWER_19dBm = 76, // 19dBm
WIFI_POWER_18_5dBm = 74, // 18.5dBm
WIFI_POWER_17dBm = 68, // 17dBm
WIFI_POWER_15dBm = 60, // 15dBm
WIFI_POWER_13dBm = 52, // 13dBm
WIFI_POWER_11dBm = 44, // 11dBm
WIFI_POWER_8_5dBm = 34, // 8.5dBm
WIFI_POWER_7dBm = 28, // 7dBm
WIFI_POWER_5dBm = 20, // 5dBm
WIFI_POWER_2dBm = 8, // 2dBm
WIFI_POWER_MINUS_1dBm = -4 // -1dBm
} wifi_power_t;
typedef enum {
ETH_CLOCK_GPIO0_IN = 0, /*!< RMII clock input to GPIO0 */
ETH_CLOCK_GPIO0_OUT = 1, /*!< RMII clock output from GPIO0 */

View File

@@ -28,7 +28,8 @@
#include <string>
#include <Printable.h>
#include <WString.h>
#include "WString.h"
int vsnprintf_P(char * str, size_t size, const char * format, va_list ap);

View File

@@ -1,18 +1,15 @@
#ifndef SecurityManager_h
#define SecurityManager_h
#include <Arduino.h>
#include <Features.h>
#include <ESPAsyncWebServer.h>
#include <AsyncJson.h>
#include "Arduino.h"
#include "Features.h"
#include "ESPAsyncWebServer.h"
#include "AsyncJson.h"
#include <list>
#ifndef FACTORY_JWT_SECRET
#define FACTORY_JWT_SECRET ESPUtils::defaultDeviceValue()
#endif
#define FACTORY_JWT_SECRET "ems-esp"
#define ACCESS_TOKEN_PARAMATER "access_token"
#define AUTHORIZATION_HEADER "Authorization"
#define AUTHORIZATION_HEADER_PREFIX "Bearer "
#define AUTHORIZATION_HEADER_PREFIX_LEN 7
@@ -69,11 +66,6 @@ class AuthenticationPredicates {
class SecurityManager {
public:
#if FT_ENABLED(FT_SECURITY)
virtual Authentication authenticate(const String & username, const String & password) = 0;
virtual String generateJWT(User * user) = 0;
#endif
virtual Authentication authenticateRequest(AsyncWebServerRequest * request) = 0;
virtual ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate) = 0;
virtual ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) = 0;

View File

@@ -1,116 +1,6 @@
#ifdef EMSESP_STANDALONE
#include <SecuritySettingsService.h>
#if FT_ENABLED(FT_SECURITY)
#include "../../src/emsesp_stub.h" // proddy added
SecuritySettingsService::SecuritySettingsService(AsyncWebServer * server, FS * fs)
: _httpEndpoint(SecuritySettings::read, SecuritySettings::update, this, server, SECURITY_SETTINGS_PATH, this)
, _fsPersistence(SecuritySettings::read, SecuritySettings::update, this, fs, SECURITY_SETTINGS_FILE)
, _jwtHandler(FACTORY_JWT_SECRET) {
addUpdateHandler([&](const String & originId) { configureJWTHandler(); }, false);
}
void SecuritySettingsService::begin() {
_fsPersistence.readFromFS();
configureJWTHandler();
}
Authentication SecuritySettingsService::authenticateRequest(AsyncWebServerRequest * request) {
AsyncWebHeader * authorizationHeader = request->getHeader(AUTHORIZATION_HEADER);
if (authorizationHeader) {
String value = authorizationHeader->value();
if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) {
value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN);
return authenticateJWT(value);
}
} else if (request->hasParam(ACCESS_TOKEN_PARAMATER)) {
AsyncWebParameter * tokenParamater = request->getParam(ACCESS_TOKEN_PARAMATER);
String value = tokenParamater->value();
return authenticateJWT(value);
}
return Authentication();
}
void SecuritySettingsService::configureJWTHandler() {
_jwtHandler.setSecret(_state.jwtSecret);
}
Authentication SecuritySettingsService::authenticateJWT(String & jwt) {
DynamicJsonDocument payloadDocument(MAX_JWT_SIZE);
_jwtHandler.parseJWT(jwt, payloadDocument);
if (payloadDocument.is<JsonObject>()) {
JsonObject parsedPayload = payloadDocument.as<JsonObject>();
String username = parsedPayload["username"];
for (User _user : _state.users) {
if (_user.username == username && validatePayload(parsedPayload, &_user)) {
return Authentication(_user);
}
}
}
return Authentication();
}
Authentication SecuritySettingsService::authenticate(const String & username, const String & password) {
for (User _user : _state.users) {
if (_user.username == username && _user.password == password) {
return Authentication(_user);
}
}
return Authentication();
}
inline void populateJWTPayload(JsonObject & payload, User * user) {
payload["username"] = user->username;
payload["admin"] = user->admin;
}
boolean SecuritySettingsService::validatePayload(JsonObject & parsedPayload, User * user) {
DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
JsonObject payload = jsonDocument.to<JsonObject>();
populateJWTPayload(payload, user);
return payload == parsedPayload;
}
String SecuritySettingsService::generateJWT(User * user) {
DynamicJsonDocument jsonDocument(MAX_JWT_SIZE);
JsonObject payload = jsonDocument.to<JsonObject>();
populateJWTPayload(payload, user);
return _jwtHandler.buildJWT(payload);
}
ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) {
return [this, predicate](AsyncWebServerRequest * request) {
Authentication authentication = authenticateRequest(request);
return predicate(authentication);
};
}
ArRequestHandlerFunction SecuritySettingsService::wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
return [this, onRequest, predicate](AsyncWebServerRequest * request) {
Authentication authentication = authenticateRequest(request);
if (!predicate(authentication)) {
request->send(401);
return;
}
onRequest(request);
};
}
ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequestHandlerFunction onRequest, AuthenticationPredicate predicate) {
return [this, onRequest, predicate](AsyncWebServerRequest * request, JsonVariant & json) {
Authentication authentication = authenticateRequest(request);
if (!predicate(authentication)) {
request->send(401);
return;
}
onRequest(request, json);
};
}
#else
#include "SecuritySettingsService.h"
User ADMIN_USER = User(FACTORY_ADMIN_USERNAME, FACTORY_ADMIN_PASSWORD, true);
@@ -121,7 +11,7 @@ SecuritySettingsService::~SecuritySettingsService() {
}
ArRequestFilterFunction SecuritySettingsService::filterRequest(AuthenticationPredicate predicate) {
return [this, predicate](AsyncWebServerRequest * request) { return true; };
return [predicate](AsyncWebServerRequest * request) { return true; };
}
// Return the admin user on all request - disabling security features
@@ -138,6 +28,4 @@ ArJsonRequestHandlerFunction SecuritySettingsService::wrapCallback(ArJsonRequest
return onRequest;
}
#endif
#endif

View File

@@ -1,10 +1,10 @@
#ifndef SecuritySettingsService_h
#define SecuritySettingsService_h
#include <Features.h>
#include <SecurityManager.h>
#include <HttpEndpoint.h>
#include <FSPersistence.h>
#include "Features.h"
#include "SecurityManager.h"
#include "HttpEndpoint.h"
#include "FSPersistence.h"
#ifndef FACTORY_ADMIN_USERNAME
#define FACTORY_ADMIN_USERNAME "admin"
@@ -25,71 +25,6 @@
#define SECURITY_SETTINGS_FILE "/config/securitySettings.json"
#define SECURITY_SETTINGS_PATH "/rest/securitySettings"
#if FT_ENABLED(FT_SECURITY)
class SecuritySettings {
public:
String jwtSecret;
std::list<User> users;
static void read(SecuritySettings & settings, JsonObject & root) {
// secret
root["jwt_secret"] = settings.jwtSecret;
// users
JsonArray users = root.createNestedArray("users");
for (User user : settings.users) {
JsonObject userRoot = users.createNestedObject();
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.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;
}
};
class SecuritySettingsService : public StatefulService<SecuritySettings>, public SecurityManager {
public:
SecuritySettingsService(AsyncWebServer * server, FS * fs);
void begin();
// Functions to implement SecurityManager
Authentication authenticate(const String & username, const String & password);
Authentication authenticateRequest(AsyncWebServerRequest * request);
String generateJWT(User * user);
ArRequestFilterFunction filterRequest(AuthenticationPredicate predicate);
ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate);
ArJsonRequestHandlerFunction wrapCallback(ArJsonRequestHandlerFunction callback, AuthenticationPredicate predicate);
private:
HttpEndpoint<SecuritySettings> _httpEndpoint;
FSPersistence<SecuritySettings> _fsPersistence;
ArduinoJsonJWT _jwtHandler;
void configureJWTHandler();
Authentication authenticateJWT(String & jwt);
boolean validatePayload(JsonObject & parsedPayload, User * user);
};
#else
class SecuritySettingsService : public SecurityManager {
public:
SecuritySettingsService(AsyncWebServer * server, FS * fs);
@@ -103,4 +38,3 @@ class SecuritySettingsService : public SecurityManager {
};
#endif
#endif

View File

@@ -1,3 +1,3 @@
#include <StatefulService.h>
#include "StatefulService.h"
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;

View File

@@ -1,20 +1,13 @@
#ifndef StatefulService_h
#define StatefulService_h
#include <Arduino.h>
#include "Arduino.h"
#include <ArduinoJson.h>
#include <list>
#include <functional>
#ifndef DEFAULT_BUFFER_SIZE
#define DEFAULT_BUFFER_SIZE 2048
#endif
#ifndef FS_BUFFER_SIZE
#define FS_BUFFER_SIZE 8192
#endif
enum class StateUpdateResult {
CHANGED = 0, // The update changed the state and propagation should take place if required
CHANGED_RESTART, // The update changed the state and the service should be restarted
@@ -23,13 +16,13 @@ enum class StateUpdateResult {
};
template <typename T>
using JsonStateUpdater = std::function<StateUpdateResult(JsonObject & root, T & settings)>;
using JsonStateUpdater = std::function<StateUpdateResult(JsonObject root, T & settings)>;
template <typename T>
using JsonStateReader = std::function<void(T & settings, JsonObject & root)>;
using JsonStateReader = std::function<void(T & settings, JsonObject root)>;
typedef size_t update_handler_id_t;
typedef std::function<void(const String & originId)> StateUpdateCallback;
typedef size_t update_handler_id_t;
typedef std::function<void()> StateUpdateCallback;
typedef struct StateUpdateHandlerInfo {
static update_handler_id_t currentUpdatedHandlerId;
@@ -76,12 +69,12 @@ class StatefulService {
}
}
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater, const String & originId) {
StateUpdateResult update(std::function<StateUpdateResult(T &)> stateUpdater) {
beginTransaction();
StateUpdateResult result = stateUpdater(_state);
endTransaction();
if (result == StateUpdateResult::CHANGED) {
callUpdateHandlers(originId);
callUpdateHandlers();
}
return result;
}
@@ -93,17 +86,17 @@ class StatefulService {
return result;
}
StateUpdateResult update(JsonObject & jsonObject, JsonStateUpdater<T> stateUpdater, const String & originId) {
StateUpdateResult update(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater) {
beginTransaction();
StateUpdateResult result = stateUpdater(jsonObject, _state);
endTransaction();
if (result == StateUpdateResult::CHANGED) {
callUpdateHandlers(originId);
callUpdateHandlers();
}
return result;
}
StateUpdateResult updateWithoutPropagation(JsonObject & jsonObject, JsonStateUpdater<T> stateUpdater) {
StateUpdateResult updateWithoutPropagation(JsonObject jsonObject, JsonStateUpdater<T> stateUpdater) {
beginTransaction();
StateUpdateResult result = stateUpdater(jsonObject, _state);
endTransaction();
@@ -116,15 +109,15 @@ class StatefulService {
endTransaction();
}
void read(JsonObject & jsonObject, JsonStateReader<T> stateReader) {
void read(JsonObject jsonObject, JsonStateReader<T> stateReader) {
beginTransaction();
stateReader(_state, jsonObject);
endTransaction();
}
void callUpdateHandlers(const String & originId) {
void callUpdateHandlers() {
for (const StateUpdateHandlerInfo_t & updateHandler : _updateHandlers) {
updateHandler._cb(originId);
updateHandler._cb();
}
}

View File

@@ -1,7 +1,7 @@
#ifdef EMSESP_STANDALONE
#include <Arduino.h>
#include "Arduino.h"
#include "WString.h"
/*

View File

@@ -1,6 +1,6 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2023 Paul Derbyshire
* Copyright 2020-2024 Paul Derbyshire
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@@ -1,6 +1,6 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2023 Paul Derbyshire
* Copyright 2020-2024 Paul Derbyshire
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@
#ifndef EMSESP_EMSUART_H
#define EMSESP_EMSUART_H
#include <Arduino.h>
#include "Arduino.h"
namespace emsesp {