mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-09 01:09:51 +03:00
Merge remote-tracking branch 'origin/dev' for 3.6.5
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ASYNCTCP_H_
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
class AsyncClient;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#include <StatefulService.h>
|
||||
#include "StatefulService.h"
|
||||
|
||||
update_handler_id_t StateUpdateHandlerInfo::currentUpdatedHandlerId = 0;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
#ifdef EMSESP_STANDALONE
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "Arduino.h"
|
||||
#include "WString.h"
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user