Merge pull request #68 from rjwats/clang-format
reformat with .clang-format based on google's spec with some minor ch…
This commit is contained in:
		
							
								
								
									
										15
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| Language: Cpp | ||||
| BasedOnStyle: Google | ||||
| ColumnLimit: 120 | ||||
| AllowShortBlocksOnASingleLine: false | ||||
| AllowShortFunctionsOnASingleLine: false | ||||
| AllowShortIfStatementsOnASingleLine: false | ||||
| AllowShortLoopsOnASingleLine: false | ||||
| BinPackArguments: false | ||||
| BinPackParameters: false | ||||
| BreakConstructorInitializers: AfterColon | ||||
| AllowAllParametersOfDeclarationOnNextLine: false | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: true | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| KeepEmptyLinesAtTheStartOfBlocks: false | ||||
| DerivePointerAlignment: false | ||||
| @@ -1,8 +1,11 @@ | ||||
| #include <APSettingsService.h> | ||||
|  | ||||
| APSettingsService::APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, AP_SETTINGS_SERVICE_PATH, AP_SETTINGS_FILE) {} | ||||
| APSettingsService::APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : | ||||
|     AdminSettingsService(server, fs, securityManager, AP_SETTINGS_SERVICE_PATH, AP_SETTINGS_FILE) { | ||||
| } | ||||
|  | ||||
| APSettingsService::~APSettingsService() {} | ||||
| APSettingsService::~APSettingsService() { | ||||
| } | ||||
|  | ||||
| void APSettingsService::begin() { | ||||
|   SettingsService::begin(); | ||||
| @@ -12,9 +15,9 @@ void APSettingsService::begin() { | ||||
| void APSettingsService::loop() { | ||||
|   unsigned long currentMillis = millis(); | ||||
|   unsigned long manageElapsed = (unsigned long)(currentMillis - _lastManaged); | ||||
|   if (manageElapsed >= MANAGE_NETWORK_DELAY){ | ||||
|   if (manageElapsed >= MANAGE_NETWORK_DELAY) { | ||||
|     _lastManaged = currentMillis; | ||||
|      manageAP(); | ||||
|     manageAP(); | ||||
|   } | ||||
|   handleDNS(); | ||||
| } | ||||
|   | ||||
| @@ -20,39 +20,34 @@ | ||||
| #define AP_SETTINGS_SERVICE_PATH "/rest/apSettings" | ||||
|  | ||||
| class APSettingsService : public AdminSettingsService { | ||||
|  public: | ||||
|   APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|   ~APSettingsService(); | ||||
|  | ||||
|   public: | ||||
|   void begin(); | ||||
|   void loop(); | ||||
|  | ||||
|     APSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|     ~APSettingsService(); | ||||
|  protected: | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
|   void onConfigUpdated(); | ||||
|  | ||||
|     void begin(); | ||||
|     void loop(); | ||||
|  private: | ||||
|   // access point settings | ||||
|   uint8_t _provisionMode; | ||||
|   String _ssid; | ||||
|   String _password; | ||||
|  | ||||
|   protected: | ||||
|   // for the mangement delay loop | ||||
|   unsigned long _lastManaged; | ||||
|  | ||||
|     void readFromJsonObject(JsonObject& root); | ||||
|     void writeToJsonObject(JsonObject& root); | ||||
|     void onConfigUpdated(); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     // access point settings | ||||
|     uint8_t _provisionMode; | ||||
|     String _ssid; | ||||
|     String _password; | ||||
|  | ||||
|     // for the mangement delay loop | ||||
|     unsigned long _lastManaged; | ||||
|  | ||||
|     // for the captive portal | ||||
|     DNSServer *_dnsServer; | ||||
|  | ||||
|     void manageAP(); | ||||
|     void startAP(); | ||||
|     void stopAP() ; | ||||
|     void handleDNS(); | ||||
|   // for the captive portal | ||||
|   DNSServer* _dnsServer; | ||||
|  | ||||
|   void manageAP(); | ||||
|   void startAP(); | ||||
|   void stopAP(); | ||||
|   void handleDNS(); | ||||
| }; | ||||
|  | ||||
| #endif // end APSettingsConfig_h | ||||
| #endif  // end APSettingsConfig_h | ||||
| @@ -1,17 +1,18 @@ | ||||
| #include <APStatus.h> | ||||
|  | ||||
| APStatus::APStatus(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|  server->on(AP_STATUS_SERVICE_PATH, HTTP_GET,  | ||||
|     securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) | ||||
|   ); | ||||
|   server->on(AP_STATUS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&APStatus::apStatus, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_AUTHENTICATED)); | ||||
| } | ||||
|  | ||||
| void APStatus::apStatus(AsyncWebServerRequest *request) { | ||||
|   AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_AP_STATUS_SIZE); | ||||
| void APStatus::apStatus(AsyncWebServerRequest* request) { | ||||
|   AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AP_STATUS_SIZE); | ||||
|   JsonObject root = response->getRoot(); | ||||
|  | ||||
|   WiFiMode_t currentWiFiMode = WiFi.getMode(); | ||||
|   root["active"] =  (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA); | ||||
|   root["active"] = (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA); | ||||
|   root["ip_address"] = WiFi.softAPIP().toString(); | ||||
|   root["mac_address"] = WiFi.softAPmacAddress(); | ||||
|   root["station_num"] = WiFi.softAPgetStationNum(); | ||||
|   | ||||
| @@ -2,16 +2,16 @@ | ||||
| #define APStatus_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <IPAddress.h> | ||||
| #include <SecurityManager.h> | ||||
|  | ||||
| @@ -19,15 +19,11 @@ | ||||
| #define AP_STATUS_SERVICE_PATH "/rest/apStatus" | ||||
|  | ||||
| class APStatus { | ||||
|  public: | ||||
|   APStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     APStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|    | ||||
|     void apStatus(AsyncWebServerRequest *request); | ||||
|  | ||||
|  private: | ||||
|   void apStatus(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end APStatus_h | ||||
| #endif  // end APStatus_h | ||||
|   | ||||
| @@ -4,42 +4,46 @@ | ||||
| #include <SettingsService.h> | ||||
|  | ||||
| class AdminSettingsService : public SettingsService { | ||||
|  public: | ||||
|   AdminSettingsService(AsyncWebServer* server, | ||||
|                        FS* fs, | ||||
|                        SecurityManager* securityManager, | ||||
|                        char const* servicePath, | ||||
|                        char const* filePath) : | ||||
|       SettingsService(server, fs, servicePath, filePath), | ||||
|       _securityManager(securityManager) { | ||||
|   } | ||||
|  | ||||
|   public:   | ||||
|     AdminSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager, char const* servicePath, char const* filePath): | ||||
|       SettingsService(server, fs, servicePath, filePath), _securityManager(securityManager) {} | ||||
|  protected: | ||||
|   // will validate the requests with the security manager | ||||
|   SecurityManager* _securityManager; | ||||
|  | ||||
|   protected: | ||||
|     // will validate the requests with the security manager | ||||
|     SecurityManager* _securityManager; | ||||
|  | ||||
|     void fetchConfig(AsyncWebServerRequest *request) { | ||||
|       // verify the request against the predicate | ||||
|       Authentication authentication = _securityManager->authenticateRequest(request); | ||||
|       if (!getAuthenticationPredicate()(authentication)) { | ||||
|         request->send(401); | ||||
|         return; | ||||
|       } | ||||
|       // delegate to underlying implemetation | ||||
|       SettingsService::fetchConfig(request); | ||||
|   void fetchConfig(AsyncWebServerRequest* request) { | ||||
|     // verify the request against the predicate | ||||
|     Authentication authentication = _securityManager->authenticateRequest(request); | ||||
|     if (!getAuthenticationPredicate()(authentication)) { | ||||
|       request->send(401); | ||||
|       return; | ||||
|     } | ||||
|     // delegate to underlying implemetation | ||||
|     SettingsService::fetchConfig(request); | ||||
|   } | ||||
|  | ||||
|     void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) { | ||||
|       // verify the request against the predicate | ||||
|       Authentication authentication = _securityManager->authenticateRequest(request); | ||||
|       if (!getAuthenticationPredicate()(authentication)) { | ||||
|         request->send(401); | ||||
|         return; | ||||
|       } | ||||
|       // delegate to underlying implemetation | ||||
|       SettingsService::updateConfig(request, jsonDocument); | ||||
|     } | ||||
|  | ||||
|     // override this to replace the default authentication predicate, IS_ADMIN | ||||
|     AuthenticationPredicate getAuthenticationPredicate() { | ||||
|       return AuthenticationPredicates::IS_ADMIN; | ||||
|   void updateConfig(AsyncWebServerRequest* request, JsonDocument& jsonDocument) { | ||||
|     // verify the request against the predicate | ||||
|     Authentication authentication = _securityManager->authenticateRequest(request); | ||||
|     if (!getAuthenticationPredicate()(authentication)) { | ||||
|       request->send(401); | ||||
|       return; | ||||
|     } | ||||
|     // delegate to underlying implemetation | ||||
|     SettingsService::updateConfig(request, jsonDocument); | ||||
|   } | ||||
|  | ||||
|   // override this to replace the default authentication predicate, IS_ADMIN | ||||
|   AuthenticationPredicate getAuthenticationPredicate() { | ||||
|     return AuthenticationPredicates::IS_ADMIN; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end AdminSettingsService | ||||
| #endif  // end AdminSettingsService | ||||
|   | ||||
| @@ -1,12 +1,13 @@ | ||||
| #include "ArduinoJsonJWT.h" | ||||
|  | ||||
| ArduinoJsonJWT::ArduinoJsonJWT(String secret) : _secret(secret) { } | ||||
| ArduinoJsonJWT::ArduinoJsonJWT(String secret) : _secret(secret) { | ||||
| } | ||||
|  | ||||
| void ArduinoJsonJWT::setSecret(String secret){ | ||||
| void ArduinoJsonJWT::setSecret(String secret) { | ||||
|   _secret = secret; | ||||
| } | ||||
|  | ||||
| String ArduinoJsonJWT::getSecret(){ | ||||
| String ArduinoJsonJWT::getSecret() { | ||||
|   return _secret; | ||||
| } | ||||
|  | ||||
| @@ -17,31 +18,31 @@ String ArduinoJsonJWT::getSecret(){ | ||||
|  * | ||||
|  * No need to pull in additional crypto libraries - lets use what we already have. | ||||
|  */ | ||||
| String ArduinoJsonJWT::sign(String &payload) { | ||||
| String ArduinoJsonJWT::sign(String& payload) { | ||||
|   unsigned char hmacResult[32]; | ||||
|   { | ||||
|   #if defined(ESP_PLATFORM) | ||||
| #if defined(ESP_PLATFORM) | ||||
|     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_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); | ||||
|   #else | ||||
| #else | ||||
|     br_hmac_key_context keyCtx; | ||||
|     br_hmac_key_init(&keyCtx, &br_sha256_vtable, _secret.c_str(), _secret.length()); | ||||
|     br_hmac_context hmacCtx; | ||||
|     br_hmac_init(&hmacCtx, &keyCtx, 0); | ||||
|     br_hmac_update(&hmacCtx, payload.c_str(), payload.length()); | ||||
|     br_hmac_out(&hmacCtx, hmacResult); | ||||
|   #endif | ||||
| #endif | ||||
|   } | ||||
|   return encode((char *) hmacResult, 32); | ||||
|   return encode((char*)hmacResult, 32); | ||||
| } | ||||
|  | ||||
| String ArduinoJsonJWT::buildJWT(JsonObject &payload) { | ||||
| String ArduinoJsonJWT::buildJWT(JsonObject& payload) { | ||||
|   // serialize, then encode payload | ||||
|   String jwt; | ||||
|   serializeJson(payload, jwt); | ||||
| @@ -51,12 +52,12 @@ String ArduinoJsonJWT::buildJWT(JsonObject &payload) { | ||||
|   jwt = JWT_HEADER + '.' + jwt; | ||||
|  | ||||
|   // add signature | ||||
|   jwt  += '.' + sign(jwt); | ||||
|   jwt += '.' + sign(jwt); | ||||
|  | ||||
|   return jwt; | ||||
| } | ||||
|  | ||||
| void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) { | ||||
| void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument& jsonDocument) { | ||||
|   // clear json document before we begin, jsonDocument wil be null on failure | ||||
|   jsonDocument.clear(); | ||||
|  | ||||
| @@ -74,7 +75,7 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) { | ||||
|   // check the signature is valid | ||||
|   String signature = jwt.substring(signatureDelimiterIndex + 1); | ||||
|   jwt = jwt.substring(0, signatureDelimiterIndex); | ||||
|   if (sign(jwt) != signature){ | ||||
|   if (sign(jwt) != signature) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
| @@ -84,12 +85,12 @@ void ArduinoJsonJWT::parseJWT(String jwt, JsonDocument &jsonDocument) { | ||||
|  | ||||
|   // parse payload, clearing json document after failure | ||||
|   DeserializationError error = deserializeJson(jsonDocument, jwt); | ||||
|   if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()){ | ||||
|   if (error != DeserializationError::Ok || !jsonDocument.is<JsonObject>()) { | ||||
|     jsonDocument.clear(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| String ArduinoJsonJWT::encode(const char *cstr, int inputLen) { | ||||
| String ArduinoJsonJWT::encode(const char* cstr, int inputLen) { | ||||
|   // prepare encoder | ||||
|   base64_encodestate _state; | ||||
| #if defined(ESP8266) | ||||
| @@ -100,7 +101,7 @@ String ArduinoJsonJWT::encode(const char *cstr, int inputLen) { | ||||
|   size_t encodedLength = base64_encode_expected_len(inputLen) + 1; | ||||
| #endif | ||||
|   // prepare buffer of correct length, returning an empty string on failure | ||||
|   char* buffer = (char*) malloc(encodedLength * sizeof(char));   | ||||
|   char* buffer = (char*)malloc(encodedLength * sizeof(char)); | ||||
|   if (buffer == nullptr) { | ||||
|     return ""; | ||||
|   } | ||||
| @@ -113,10 +114,10 @@ String ArduinoJsonJWT::encode(const char *cstr, int inputLen) { | ||||
|   // convert to arduino string, freeing buffer | ||||
|   String value = String(buffer); | ||||
|   free(buffer); | ||||
|   buffer=nullptr; | ||||
|   buffer = nullptr; | ||||
|  | ||||
|   // remove padding and convert to URL safe form | ||||
|   while (value.length() > 0 && value.charAt(value.length() - 1) == '='){ | ||||
|   while (value.length() > 0 && value.charAt(value.length() - 1) == '=') { | ||||
|     value.remove(value.length() - 1); | ||||
|   } | ||||
|   value.replace('+', '-'); | ||||
| @@ -129,7 +130,7 @@ String ArduinoJsonJWT::encode(const char *cstr, int inputLen) { | ||||
| String ArduinoJsonJWT::decode(String value) { | ||||
|   // convert to standard base64 | ||||
|   value.replace('-', '+'); | ||||
|   value.replace( '_', '/'); | ||||
|   value.replace('_', '/'); | ||||
|  | ||||
|   // prepare buffer of correct length | ||||
|   char buffer[base64_decode_expected_len(value.length()) + 1]; | ||||
|   | ||||
| @@ -6,33 +6,31 @@ | ||||
| #include <libb64/cdecode.h> | ||||
| #include <libb64/cencode.h> | ||||
| #if defined(ESP_PLATFORM) | ||||
|   #include <mbedtls/md.h> | ||||
| #include <mbedtls/md.h> | ||||
| #else | ||||
|   #include <bearssl/bearssl_hmac.h> | ||||
| #include <bearssl/bearssl_hmac.h> | ||||
| #endif | ||||
|  | ||||
| class ArduinoJsonJWT { | ||||
|  | ||||
| private: | ||||
|  private: | ||||
|   String _secret; | ||||
|  | ||||
|   const String JWT_HEADER = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"; | ||||
|   const int JWT_HEADER_SIZE = JWT_HEADER.length(); | ||||
|  | ||||
|   String sign(String &value); | ||||
|   String sign(String& value); | ||||
|  | ||||
|   static String encode(const char *cstr, int len); | ||||
|   static String encode(const char* cstr, int len); | ||||
|   static String decode(String value); | ||||
|  | ||||
| public: | ||||
|  public: | ||||
|   ArduinoJsonJWT(String secret); | ||||
|  | ||||
|   void setSecret(String secret); | ||||
|   String getSecret(); | ||||
|  | ||||
|   String buildJWT(JsonObject &payload); | ||||
|   void parseJWT(String jwt, JsonDocument &jsonDocument); | ||||
|   String buildJWT(JsonObject& payload); | ||||
|   void parseJWT(String jwt, JsonDocument& jsonDocument); | ||||
| }; | ||||
|  | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,31 +1,33 @@ | ||||
| #ifndef _AsyncJsonCallbackResponse_H_ | ||||
| #define _AsyncJsonCallbackResponse_H_ | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
|  | ||||
| /* | ||||
| * Listens for a response being destroyed and calls a callback during said distruction. | ||||
| * used so we can take action after the response has been rendered to the client. | ||||
| * | ||||
| * Avoids having to fork ESPAsyncWebServer with a callback feature, but not nice! | ||||
| */ | ||||
|  * Listens for a response being destroyed and calls a callback during said distruction. | ||||
|  * used so we can take action after the response has been rendered to the client. | ||||
|  * | ||||
|  * Avoids having to fork ESPAsyncWebServer with a callback feature, but not nice! | ||||
|  */ | ||||
|  | ||||
| typedef std::function<void()> AsyncJsonCallback; | ||||
|  | ||||
| class AsyncJsonCallbackResponse : public AsyncJsonResponse | ||||
| { | ||||
| class AsyncJsonCallbackResponse : public AsyncJsonResponse { | ||||
|  private: | ||||
|   AsyncJsonCallback _callback; | ||||
|  | ||||
| private: | ||||
|     AsyncJsonCallback _callback; | ||||
|  public: | ||||
|   AsyncJsonCallbackResponse(AsyncJsonCallback callback, | ||||
|                             bool isArray = false, | ||||
|                             size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) : | ||||
|       AsyncJsonResponse(isArray, maxJsonBufferSize), | ||||
|       _callback{callback} { | ||||
|   } | ||||
|  | ||||
| public: | ||||
|     AsyncJsonCallbackResponse(AsyncJsonCallback callback, bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE) | ||||
|         : AsyncJsonResponse(isArray, maxJsonBufferSize), _callback{callback} {} | ||||
|     ~AsyncJsonCallbackResponse() | ||||
|     { | ||||
|         _callback(); | ||||
|     } | ||||
|   ~AsyncJsonCallbackResponse() { | ||||
|     _callback(); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end _AsyncJsonCallbackResponse_H_ | ||||
| #endif  // end _AsyncJsonCallbackResponse_H_ | ||||
|   | ||||
| @@ -1,120 +1,131 @@ | ||||
| #ifndef Async_Json_Request_Web_Handler_H_ | ||||
| #define Async_Json_Request_Web_Handler_H_ | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
|  | ||||
| #define ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE 1024 | ||||
| #define ASYNC_JSON_REQUEST_MIMETYPE "application/json" | ||||
|  | ||||
| /* | ||||
| * Handy little utility for dealing with small JSON request body payloads. | ||||
| * | ||||
| * Need to be careful using this as we are somewhat limited by RAM. | ||||
| * | ||||
| * Really only of use where there is a determinate payload size. | ||||
| */ | ||||
|  * Handy little utility for dealing with small JSON request body payloads. | ||||
|  * | ||||
|  * Need to be careful using this as we are somewhat limited by RAM. | ||||
|  * | ||||
|  * Really only of use where there is a determinate payload size. | ||||
|  */ | ||||
|  | ||||
| typedef std::function<void(AsyncWebServerRequest *request, JsonDocument &jsonDocument)> JsonRequestCallback; | ||||
| typedef std::function<void(AsyncWebServerRequest* request, JsonDocument& jsonDocument)> JsonRequestCallback; | ||||
|  | ||||
| class AsyncJsonWebHandler: public AsyncWebHandler { | ||||
| class AsyncJsonWebHandler : public AsyncWebHandler { | ||||
|  private: | ||||
|   WebRequestMethodComposite _method; | ||||
|   JsonRequestCallback _onRequest; | ||||
|   size_t _maxContentLength; | ||||
|  | ||||
|   private: | ||||
|     WebRequestMethodComposite _method; | ||||
|     JsonRequestCallback _onRequest; | ||||
|     size_t _maxContentLength; | ||||
|  protected: | ||||
|   String _uri; | ||||
|  | ||||
|   protected: | ||||
|     String _uri; | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     AsyncJsonWebHandler() :       | ||||
|       _method(HTTP_POST|HTTP_PUT|HTTP_PATCH), | ||||
|  public: | ||||
|   AsyncJsonWebHandler() : | ||||
|       _method(HTTP_POST | HTTP_PUT | HTTP_PATCH), | ||||
|       _onRequest(nullptr), | ||||
|       _maxContentLength(ASYNC_JSON_REQUEST_DEFAULT_MAX_SIZE), | ||||
|       _uri() {} | ||||
|       _uri() { | ||||
|   } | ||||
|  | ||||
|     ~AsyncJsonWebHandler() {} | ||||
|   ~AsyncJsonWebHandler() { | ||||
|   } | ||||
|  | ||||
|     void setUri(const String& uri) { _uri = uri; } | ||||
|     void setMethod(WebRequestMethodComposite method) { _method = method; } | ||||
|     void setMaxContentLength(size_t maxContentLength) { _maxContentLength = maxContentLength; } | ||||
|     void onRequest(JsonRequestCallback fn) { _onRequest = fn; } | ||||
|   void setUri(const String& uri) { | ||||
|     _uri = uri; | ||||
|   } | ||||
|   void setMethod(WebRequestMethodComposite method) { | ||||
|     _method = method; | ||||
|   } | ||||
|   void setMaxContentLength(size_t maxContentLength) { | ||||
|     _maxContentLength = maxContentLength; | ||||
|   } | ||||
|   void onRequest(JsonRequestCallback fn) { | ||||
|     _onRequest = fn; | ||||
|   } | ||||
|  | ||||
|     virtual bool canHandle(AsyncWebServerRequest *request) override final { | ||||
|       if(!_onRequest) | ||||
|         return false; | ||||
|   virtual bool canHandle(AsyncWebServerRequest* request) override final { | ||||
|     if (!_onRequest) | ||||
|       return false; | ||||
|  | ||||
|       if(!(_method & request->method())) | ||||
|         return false; | ||||
|     if (!(_method & request->method())) | ||||
|       return false; | ||||
|  | ||||
|       if(_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri+"/"))) | ||||
|         return false; | ||||
|     if (_uri.length() && (_uri != request->url() && !request->url().startsWith(_uri + "/"))) | ||||
|       return false; | ||||
|  | ||||
|       if (!request->contentType().equalsIgnoreCase(ASYNC_JSON_REQUEST_MIMETYPE)) | ||||
|         return false; | ||||
|     if (!request->contentType().equalsIgnoreCase(ASYNC_JSON_REQUEST_MIMETYPE)) | ||||
|       return false; | ||||
|  | ||||
|       request->addInterestingHeader("ANY"); | ||||
|       return true; | ||||
|     } | ||||
|     request->addInterestingHeader("ANY"); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|     virtual void handleRequest(AsyncWebServerRequest *request) override final { | ||||
|       // no request configured | ||||
|       if(!_onRequest) { | ||||
|         Serial.print("No request callback was configured for endpoint: "); | ||||
|         Serial.println(_uri);            | ||||
|         request->send(500); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       // we have been handed too much data, return a 413 (payload too large) | ||||
|       if (request->contentLength() > _maxContentLength) { | ||||
|         request->send(413); | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       // parse JSON and if possible handle the request | ||||
|       if (request->_tempObject) { | ||||
|         DynamicJsonDocument jsonDocument(_maxContentLength); | ||||
|         DeserializationError error = deserializeJson(jsonDocument, (uint8_t *) request->_tempObject); | ||||
|         if (error == DeserializationError::Ok) { | ||||
|           _onRequest(request, jsonDocument); | ||||
|         }else{ | ||||
|           request->send(400); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       // fallthrough, we have a null pointer, return 500. | ||||
|       // this can be due to running out of memory or never receiving body data. | ||||
|   virtual void handleRequest(AsyncWebServerRequest* request) override final { | ||||
|     // no request configured | ||||
|     if (!_onRequest) { | ||||
|       Serial.print("No request callback was configured for endpoint: "); | ||||
|       Serial.println(_uri); | ||||
|       request->send(500); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     virtual void handleBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) override final { | ||||
|       if (_onRequest) { | ||||
|         // don't allocate if data is too large | ||||
|         if (total > _maxContentLength){ | ||||
|           return; | ||||
|         } | ||||
|     // we have been handed too much data, return a 413 (payload too large) | ||||
|     if (request->contentLength() > _maxContentLength) { | ||||
|       request->send(413); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|         // try to allocate memory on first call | ||||
|         // NB: the memory allocated here is freed by ~AsyncWebServerRequest | ||||
|         if(index == 0 && !request->_tempObject){ | ||||
|           request->_tempObject = malloc(total); | ||||
|         } | ||||
|     // parse JSON and if possible handle the request | ||||
|     if (request->_tempObject) { | ||||
|       DynamicJsonDocument jsonDocument(_maxContentLength); | ||||
|       DeserializationError error = deserializeJson(jsonDocument, (uint8_t*)request->_tempObject); | ||||
|       if (error == DeserializationError::Ok) { | ||||
|         _onRequest(request, jsonDocument); | ||||
|       } else { | ||||
|         request->send(400); | ||||
|       } | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|         // copy the data into the buffer, if we have a buffer! | ||||
|         if (request->_tempObject) { | ||||
|             memcpy((uint8_t *) request->_tempObject+index, data, len); | ||||
|         } | ||||
|     // fallthrough, we have a null pointer, return 500. | ||||
|     // this can be due to running out of memory or never receiving body data. | ||||
|     request->send(500); | ||||
|   } | ||||
|  | ||||
|   virtual void handleBody(AsyncWebServerRequest* request, | ||||
|                           uint8_t* data, | ||||
|                           size_t len, | ||||
|                           size_t index, | ||||
|                           size_t total) override final { | ||||
|     if (_onRequest) { | ||||
|       // don't allocate if data is too large | ||||
|       if (total > _maxContentLength) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       // try to allocate memory on first call | ||||
|       // NB: the memory allocated here is freed by ~AsyncWebServerRequest | ||||
|       if (index == 0 && !request->_tempObject) { | ||||
|         request->_tempObject = malloc(total); | ||||
|       } | ||||
|  | ||||
|       // copy the data into the buffer, if we have a buffer! | ||||
|       if (request->_tempObject) { | ||||
|         memcpy((uint8_t*)request->_tempObject + index, data, len); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|     virtual bool isRequestHandlerTrivial() override final { | ||||
|       return _onRequest ? false : true; | ||||
|     } | ||||
|  | ||||
|   virtual bool isRequestHandlerTrivial() override final { | ||||
|     return _onRequest ? false : true; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end Async_Json_Request_Web_Handler_H_ | ||||
| #endif  // end Async_Json_Request_Web_Handler_H_ | ||||
|   | ||||
| @@ -1,36 +1,41 @@ | ||||
| #include <AuthenticationService.h> | ||||
|  | ||||
| AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) : _securityManager(securityManager) { | ||||
|   server->on(VERIFY_AUTHORIZATION_PATH, HTTP_GET, std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); | ||||
|  | ||||
| AuthenticationService::AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager) : | ||||
|     _securityManager(securityManager) { | ||||
|   server->on(VERIFY_AUTHORIZATION_PATH, | ||||
|              HTTP_GET, | ||||
|              std::bind(&AuthenticationService::verifyAuthorization, this, std::placeholders::_1)); | ||||
|   _signInHandler.setUri(SIGN_IN_PATH); | ||||
|   _signInHandler.setMethod(HTTP_POST); | ||||
|   _signInHandler.setMaxContentLength(MAX_AUTHENTICATION_SIZE); | ||||
|   _signInHandler.onRequest(std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|   _signInHandler.onRequest( | ||||
|       std::bind(&AuthenticationService::signIn, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|   server->addHandler(&_signInHandler); | ||||
| } | ||||
|  | ||||
| AuthenticationService::~AuthenticationService() {} | ||||
| AuthenticationService::~AuthenticationService() { | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Verifys that the request supplied a valid JWT. | ||||
|  */ | ||||
| void AuthenticationService::verifyAuthorization(AsyncWebServerRequest *request) { | ||||
| void AuthenticationService::verifyAuthorization(AsyncWebServerRequest* request) { | ||||
|   Authentication authentication = _securityManager->authenticateRequest(request); | ||||
|   request->send(authentication.isAuthenticated() ? 200: 401); | ||||
|   request->send(authentication.isAuthenticated() ? 200 : 401); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Signs in a user if the username and password match. Provides a JWT to be used in the Authorization header in subsequent requests. | ||||
|  * Signs in a user if the username and password match. Provides a JWT to be used in the Authorization header in | ||||
|  * subsequent requests. | ||||
|  */ | ||||
| void AuthenticationService::signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument){ | ||||
| void AuthenticationService::signIn(AsyncWebServerRequest* request, JsonDocument& jsonDocument) { | ||||
|   if (jsonDocument.is<JsonObject>()) { | ||||
|     String username =  jsonDocument["username"]; | ||||
|     String username = jsonDocument["username"]; | ||||
|     String password = jsonDocument["password"]; | ||||
|     Authentication authentication = _securityManager->authenticate(username, password); | ||||
|     if (authentication.isAuthenticated()) { | ||||
|       User* user = authentication.getUser(); | ||||
|       AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_AUTHENTICATION_SIZE); | ||||
|       AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_AUTHENTICATION_SIZE); | ||||
|       JsonObject jsonObject = response->getRoot(); | ||||
|       jsonObject["access_token"] = _securityManager->generateJWT(user); | ||||
|       response->setLength(); | ||||
| @@ -38,7 +43,6 @@ void AuthenticationService::signIn(AsyncWebServerRequest *request, JsonDocument | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
|   AsyncWebServerResponse *response =  request->beginResponse(401); | ||||
|   AsyncWebServerResponse* response = request->beginResponse(401); | ||||
|   request->send(response); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,32 +1,28 @@ | ||||
| #ifndef AuthenticationService_H_ | ||||
| #define AuthenticationService_H_ | ||||
|  | ||||
| #include <SecurityManager.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <SecurityManager.h> | ||||
|  | ||||
| #define VERIFY_AUTHORIZATION_PATH "/rest/verifyAuthorization" | ||||
| #define SIGN_IN_PATH "/rest/signIn" | ||||
|  | ||||
| #define MAX_AUTHENTICATION_SIZE 256 | ||||
|  | ||||
| class AuthenticationService  { | ||||
| class AuthenticationService { | ||||
|  public: | ||||
|   AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|   ~AuthenticationService(); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     AuthenticationService(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|     ~AuthenticationService(); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     SecurityManager* _securityManager; | ||||
|     AsyncJsonWebHandler _signInHandler; | ||||
|  | ||||
|     // endpoint functions | ||||
|     void signIn(AsyncWebServerRequest *request, JsonDocument &jsonDocument); | ||||
|     void verifyAuthorization(AsyncWebServerRequest *request); | ||||
|  private: | ||||
|   SecurityManager* _securityManager; | ||||
|   AsyncJsonWebHandler _signInHandler; | ||||
|  | ||||
|   // endpoint functions | ||||
|   void signIn(AsyncWebServerRequest* request, JsonDocument& jsonDocument); | ||||
|   void verifyAuthorization(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end SecurityManager_h | ||||
| #endif  // end SecurityManager_h | ||||
| @@ -1,18 +1,18 @@ | ||||
| #include <ESP8266React.h> | ||||
|  | ||||
| ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs):  | ||||
|   _securitySettingsService(server, fs), | ||||
|   _wifiSettingsService(server, fs, &_securitySettingsService), | ||||
|   _apSettingsService(server, fs, &_securitySettingsService), | ||||
|   _ntpSettingsService(server, fs, &_securitySettingsService), | ||||
|   _otaSettingsService(server, fs, &_securitySettingsService), | ||||
|   _restartService(server, &_securitySettingsService), | ||||
|   _authenticationService(server, &_securitySettingsService), | ||||
|   _wifiScanner(server, &_securitySettingsService), | ||||
|   _wifiStatus(server, &_securitySettingsService), | ||||
|   _ntpStatus(server, &_securitySettingsService), | ||||
|   _apStatus(server, &_securitySettingsService), | ||||
|   _systemStatus(server, &_securitySettingsService) {     | ||||
| ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs) : | ||||
|     _securitySettingsService(server, fs), | ||||
|     _wifiSettingsService(server, fs, &_securitySettingsService), | ||||
|     _apSettingsService(server, fs, &_securitySettingsService), | ||||
|     _ntpSettingsService(server, fs, &_securitySettingsService), | ||||
|     _otaSettingsService(server, fs, &_securitySettingsService), | ||||
|     _restartService(server, &_securitySettingsService), | ||||
|     _authenticationService(server, &_securitySettingsService), | ||||
|     _wifiScanner(server, &_securitySettingsService), | ||||
|     _wifiStatus(server, &_securitySettingsService), | ||||
|     _ntpStatus(server, &_securitySettingsService), | ||||
|     _apStatus(server, &_securitySettingsService), | ||||
|     _systemStatus(server, &_securitySettingsService) { | ||||
|   // Serve static resources from /www/ | ||||
|   server->serveStatic("/js/", SPIFFS, "/www/js/"); | ||||
|   server->serveStatic("/css/", SPIFFS, "/www/css/"); | ||||
| @@ -22,7 +22,7 @@ ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs): | ||||
|  | ||||
|   // Serving all other get requests with "/www/index.htm" | ||||
|   // OPTIONS get a straight up 200 response | ||||
|   server->onNotFound([](AsyncWebServerRequest *request) { | ||||
|   server->onNotFound([](AsyncWebServerRequest* request) { | ||||
|     if (request->method() == HTTP_GET) { | ||||
|       request->send(SPIFFS, "/www/index.html"); | ||||
|     } else if (request->method() == HTTP_OPTIONS) { | ||||
| @@ -32,12 +32,12 @@ ESP8266React::ESP8266React(AsyncWebServer* server, FS* fs): | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   // Disable CORS if required | ||||
|   #if defined(ENABLE_CORS) | ||||
| // Disable CORS if required | ||||
| #if defined(ENABLE_CORS) | ||||
|   DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", CORS_ORIGIN); | ||||
|   DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "Accept, Content-Type, Authorization"); | ||||
|   DefaultHeaders::Instance().addHeader("Access-Control-Allow-Credentials", "true"); | ||||
|   #endif   | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void ESP8266React::begin() { | ||||
|   | ||||
| @@ -4,59 +4,54 @@ | ||||
| #include <Arduino.h> | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
|   #include <SPIFFS.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <SPIFFS.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <FS.h> | ||||
| #include <SecuritySettingsService.h> | ||||
| #include <WiFiSettingsService.h> | ||||
| #include <APSettingsService.h> | ||||
| #include <NTPSettingsService.h> | ||||
| #include <OTASettingsService.h> | ||||
| #include <AuthenticationService.h> | ||||
| #include <WiFiScanner.h> | ||||
| #include <WiFiStatus.h> | ||||
| #include <NTPStatus.h> | ||||
| #include <APStatus.h> | ||||
| #include <SystemStatus.h> | ||||
| #include <AuthenticationService.h> | ||||
| #include <FS.h> | ||||
| #include <NTPSettingsService.h> | ||||
| #include <NTPStatus.h> | ||||
| #include <OTASettingsService.h> | ||||
| #include <RestartService.h> | ||||
| #include <SecuritySettingsService.h> | ||||
| #include <SystemStatus.h> | ||||
| #include <WiFiScanner.h> | ||||
| #include <WiFiSettingsService.h> | ||||
| #include <WiFiStatus.h> | ||||
|  | ||||
| class ESP8266React { | ||||
|  public: | ||||
|   ESP8266React(AsyncWebServer* server, FS* fs); | ||||
|  | ||||
|   public: | ||||
|   void begin(); | ||||
|   void loop(); | ||||
|  | ||||
|     ESP8266React(AsyncWebServer* server, FS* fs); | ||||
|   SecurityManager* getSecurityManager() { | ||||
|     return &_securitySettingsService; | ||||
|   } | ||||
|  | ||||
|     void begin(); | ||||
|     void loop(); | ||||
|  private: | ||||
|   SecuritySettingsService _securitySettingsService; | ||||
|  | ||||
|     SecurityManager* getSecurityManager(){ | ||||
|         return &_securitySettingsService; | ||||
|     } | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     SecuritySettingsService _securitySettingsService; | ||||
|  | ||||
|     WiFiSettingsService _wifiSettingsService; | ||||
|     APSettingsService _apSettingsService; | ||||
|     NTPSettingsService _ntpSettingsService; | ||||
|     OTASettingsService _otaSettingsService; | ||||
|     RestartService _restartService;     | ||||
|     AuthenticationService _authenticationService; | ||||
|  | ||||
|      | ||||
|     WiFiScanner _wifiScanner; | ||||
|     WiFiStatus _wifiStatus; | ||||
|     NTPStatus _ntpStatus;  | ||||
|     APStatus _apStatus; | ||||
|     SystemStatus _systemStatus; | ||||
|   WiFiSettingsService _wifiSettingsService; | ||||
|   APSettingsService _apSettingsService; | ||||
|   NTPSettingsService _ntpSettingsService; | ||||
|   OTASettingsService _otaSettingsService; | ||||
|   RestartService _restartService; | ||||
|   AuthenticationService _authenticationService; | ||||
|  | ||||
|   WiFiScanner _wifiScanner; | ||||
|   WiFiStatus _wifiStatus; | ||||
|   NTPStatus _ntpStatus; | ||||
|   APStatus _apStatus; | ||||
|   SystemStatus _systemStatus; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,22 +1,28 @@ | ||||
| #include <NTPSettingsService.h> | ||||
|  | ||||
| NTPSettingsService::NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, NTP_SETTINGS_SERVICE_PATH, NTP_SETTINGS_FILE) { | ||||
|  | ||||
| NTPSettingsService::NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : | ||||
|     AdminSettingsService(server, fs, securityManager, NTP_SETTINGS_SERVICE_PATH, NTP_SETTINGS_FILE) { | ||||
| #if defined(ESP8266) | ||||
|   _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); | ||||
|   _onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1)); | ||||
|   _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected( | ||||
|       std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); | ||||
|   _onStationModeGotIPHandler = | ||||
|       WiFi.onStationModeGotIP(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1)); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);  | ||||
|   WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); | ||||
|   WiFi.onEvent( | ||||
|       std::bind(&NTPSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), | ||||
|       WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); | ||||
|   WiFi.onEvent(std::bind(&NTPSettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), | ||||
|                WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); | ||||
| #endif | ||||
|  | ||||
|   NTP.onNTPSyncEvent ([this](NTPSyncEvent_t ntpEvent) { | ||||
|   NTP.onNTPSyncEvent([this](NTPSyncEvent_t ntpEvent) { | ||||
|     _ntpEvent = ntpEvent; | ||||
|     _syncEventTriggered = true; | ||||
|   }); | ||||
| } | ||||
|  | ||||
| NTPSettingsService::~NTPSettingsService() {} | ||||
| NTPSettingsService::~NTPSettingsService() { | ||||
| } | ||||
|  | ||||
| void NTPSettingsService::loop() { | ||||
|   // detect when we need to re-configure NTP and do it in the main loop | ||||
| @@ -41,12 +47,12 @@ void NTPSettingsService::readFromJsonObject(JsonObject& root) { | ||||
|  | ||||
|   // validate server is specified, resorting to default | ||||
|   _server.trim(); | ||||
|   if (!_server){ | ||||
|   if (!_server) { | ||||
|     _server = NTP_SETTINGS_SERVICE_DEFAULT_SERVER; | ||||
|   } | ||||
|  | ||||
|   // make sure interval is in bounds | ||||
|   if (_interval < NTP_SETTINGS_MIN_INTERVAL){ | ||||
|   if (_interval < NTP_SETTINGS_MIN_INTERVAL) { | ||||
|     _interval = NTP_SETTINGS_MIN_INTERVAL; | ||||
|   } else if (_interval > NTP_SETTINGS_MAX_INTERVAL) { | ||||
|     _interval = NTP_SETTINGS_MAX_INTERVAL; | ||||
| @@ -98,14 +104,14 @@ void NTPSettingsService::configureNTP() { | ||||
| } | ||||
|  | ||||
| void NTPSettingsService::processSyncEvent(NTPSyncEvent_t ntpEvent) { | ||||
|     if (ntpEvent) { | ||||
|         Serial.print ("Time Sync error: "); | ||||
|         if (ntpEvent == noResponse) | ||||
|             Serial.println ("NTP server not reachable"); | ||||
|         else if (ntpEvent == invalidAddress) | ||||
|             Serial.println ("Invalid NTP server address"); | ||||
|     } else { | ||||
|         Serial.print ("Got NTP time: "); | ||||
|         Serial.println (NTP.getTimeDateString (NTP.getLastNTPSync ())); | ||||
|     } | ||||
|   if (ntpEvent) { | ||||
|     Serial.print("Time Sync error: "); | ||||
|     if (ntpEvent == noResponse) | ||||
|       Serial.println("NTP server not reachable"); | ||||
|     else if (ntpEvent == invalidAddress) | ||||
|       Serial.println("Invalid NTP server address"); | ||||
|   } else { | ||||
|     Serial.print("Got NTP time: "); | ||||
|     Serial.println(NTP.getTimeDateString(NTP.getLastNTPSync())); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -3,8 +3,8 @@ | ||||
|  | ||||
| #include <AdminSettingsService.h> | ||||
|  | ||||
| #include <TimeLib.h> | ||||
| #include <NtpClientLib.h> | ||||
| #include <TimeLib.h> | ||||
|  | ||||
| // default time server | ||||
| #define NTP_SETTINGS_SERVICE_DEFAULT_SERVER "pool.ntp.org" | ||||
| @@ -18,43 +18,38 @@ | ||||
| #define NTP_SETTINGS_SERVICE_PATH "/rest/ntpSettings" | ||||
|  | ||||
| class NTPSettingsService : public AdminSettingsService { | ||||
|  public: | ||||
|   NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|   ~NTPSettingsService(); | ||||
|  | ||||
|   public: | ||||
|   void loop(); | ||||
|  | ||||
|     NTPSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|     ~NTPSettingsService(); | ||||
|  protected: | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
|   void onConfigUpdated(); | ||||
|  | ||||
|     void loop(); | ||||
|  private: | ||||
|   String _server; | ||||
|   int _interval; | ||||
|  | ||||
|   protected: | ||||
|  | ||||
|     void readFromJsonObject(JsonObject& root); | ||||
|     void writeToJsonObject(JsonObject& root); | ||||
|     void onConfigUpdated(); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     String _server; | ||||
|     int _interval; | ||||
|  | ||||
|     bool _reconfigureNTP = false; | ||||
|     bool _syncEventTriggered = false; | ||||
|     NTPSyncEvent_t _ntpEvent; | ||||
|   bool _reconfigureNTP = false; | ||||
|   bool _syncEventTriggered = false; | ||||
|   NTPSyncEvent_t _ntpEvent; | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|     WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|     WiFiEventHandler _onStationModeGotIPHandler; | ||||
|   WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|   WiFiEventHandler _onStationModeGotIPHandler; | ||||
|  | ||||
|     void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
|     void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
|   void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
|   void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|     void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|   void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|   void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
| #endif | ||||
|  | ||||
|     void configureNTP(); | ||||
|     void processSyncEvent(NTPSyncEvent_t ntpEvent); | ||||
|  | ||||
|   void configureNTP(); | ||||
|   void processSyncEvent(NTPSyncEvent_t ntpEvent); | ||||
| }; | ||||
|  | ||||
| #endif // end NTPSettingsService_h | ||||
| #endif  // end NTPSettingsService_h | ||||
|   | ||||
| @@ -1,27 +1,28 @@ | ||||
| #include <NTPStatus.h> | ||||
|  | ||||
| NTPStatus::NTPStatus(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|   server->on(NTP_STATUS_SERVICE_PATH, HTTP_GET,  | ||||
|     securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) | ||||
|   ); | ||||
|   server->on(NTP_STATUS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&NTPStatus::ntpStatus, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_AUTHENTICATED)); | ||||
| } | ||||
|  | ||||
| void NTPStatus::ntpStatus(AsyncWebServerRequest *request) { | ||||
|   AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_NTP_STATUS_SIZE); | ||||
| void NTPStatus::ntpStatus(AsyncWebServerRequest* request) { | ||||
|   AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_NTP_STATUS_SIZE); | ||||
|   JsonObject root = response->getRoot(); | ||||
|  | ||||
|   // request time now first, this can sometimes force a sync | ||||
|   time_t timeNow = now(); | ||||
|   timeStatus_t  status = timeStatus(); | ||||
|   timeStatus_t status = timeStatus(); | ||||
|   time_t lastSync = NTP.getLastNTPSync(); | ||||
|   root["status"] = (int) status; | ||||
|   root["status"] = (int)status; | ||||
|   root["last_sync"] = lastSync; | ||||
|   root["server"] = NTP.getNtpServerName(); | ||||
|   root["interval"] = NTP.getInterval(); | ||||
|   root["uptime"] = NTP.getUptime(); | ||||
|  | ||||
|   // only add now to response if we have successfully synced | ||||
|   if (status != timeNotSet){ | ||||
|   if (status != timeNotSet) { | ||||
|     root["now"] = timeNow; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -2,33 +2,29 @@ | ||||
| #define NTPStatus_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <TimeLib.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <NtpClientLib.h> | ||||
| #include <SecurityManager.h> | ||||
| #include <TimeLib.h> | ||||
|  | ||||
| #define MAX_NTP_STATUS_SIZE 1024 | ||||
| #define NTP_STATUS_SERVICE_PATH "/rest/ntpStatus" | ||||
|  | ||||
| class NTPStatus { | ||||
|  public: | ||||
|   NTPStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     NTPStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     void ntpStatus(AsyncWebServerRequest *request); | ||||
|  | ||||
|  private: | ||||
|   void ntpStatus(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end NTPStatus_h | ||||
| #endif  // end NTPStatus_h | ||||
|   | ||||
| @@ -1,17 +1,21 @@ | ||||
| #include <OTASettingsService.h> | ||||
|  | ||||
| OTASettingsService::OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, OTA_SETTINGS_SERVICE_PATH, OTA_SETTINGS_FILE) { | ||||
| OTASettingsService::OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : | ||||
|     AdminSettingsService(server, fs, securityManager, OTA_SETTINGS_SERVICE_PATH, OTA_SETTINGS_FILE) { | ||||
| #if defined(ESP8266) | ||||
|   _onStationModeGotIPHandler = WiFi.onStationModeGotIP(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1)); | ||||
|   _onStationModeGotIPHandler = | ||||
|       WiFi.onStationModeGotIP(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1)); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   WiFi.onEvent(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); | ||||
|   WiFi.onEvent(std::bind(&OTASettingsService::onStationModeGotIP, this, std::placeholders::_1, std::placeholders::_2), | ||||
|                WiFiEvent_t::SYSTEM_EVENT_STA_GOT_IP); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| OTASettingsService::~OTASettingsService() {} | ||||
| OTASettingsService::~OTASettingsService() { | ||||
| } | ||||
|  | ||||
| void OTASettingsService::loop() { | ||||
|   if (_enabled && _arduinoOTA){ | ||||
|   if (_enabled && _arduinoOTA) { | ||||
|     _arduinoOTA->handle(); | ||||
|   } | ||||
| } | ||||
| @@ -26,7 +30,7 @@ void OTASettingsService::readFromJsonObject(JsonObject& root) { | ||||
|   _password = root["password"] | DEFAULT_OTA_PASSWORD; | ||||
|  | ||||
|   // provide defaults | ||||
|   if (_port < 0){ | ||||
|   if (_port < 0) { | ||||
|     _port = DEFAULT_OTA_PORT; | ||||
|   } | ||||
| } | ||||
| @@ -38,7 +42,7 @@ void OTASettingsService::writeToJsonObject(JsonObject& root) { | ||||
| } | ||||
|  | ||||
| void OTASettingsService::configureArduinoOTA() { | ||||
|   if (_arduinoOTA){ | ||||
|   if (_arduinoOTA) { | ||||
| #if defined(ESP_PLATFORM) | ||||
|     _arduinoOTA->end(); | ||||
| #endif | ||||
| @@ -50,22 +54,23 @@ void OTASettingsService::configureArduinoOTA() { | ||||
|     _arduinoOTA = new ArduinoOTAClass; | ||||
|     _arduinoOTA->setPort(_port); | ||||
|     _arduinoOTA->setPassword(_password.c_str()); | ||||
|     _arduinoOTA->onStart([]() { | ||||
|       Serial.println("Starting"); | ||||
|     }); | ||||
|     _arduinoOTA->onEnd([]() { | ||||
|       Serial.println("\nEnd"); | ||||
|     }); | ||||
|     _arduinoOTA->onStart([]() { Serial.println("Starting"); }); | ||||
|     _arduinoOTA->onEnd([]() { Serial.println("\nEnd"); }); | ||||
|     _arduinoOTA->onProgress([](unsigned int progress, unsigned int total) { | ||||
|       Serial.printf("Progress: %u%%\r", (progress / (total / 100))); | ||||
|     }); | ||||
|     _arduinoOTA->onError([](ota_error_t error) { | ||||
|       Serial.printf("Error[%u]: ", error); | ||||
|       if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); | ||||
|       else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); | ||||
|       else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); | ||||
|       else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); | ||||
|       else if (error == OTA_END_ERROR) Serial.println("End Failed"); | ||||
|       if (error == OTA_AUTH_ERROR) | ||||
|         Serial.println("Auth Failed"); | ||||
|       else if (error == OTA_BEGIN_ERROR) | ||||
|         Serial.println("Begin Failed"); | ||||
|       else if (error == OTA_CONNECT_ERROR) | ||||
|         Serial.println("Connect Failed"); | ||||
|       else if (error == OTA_RECEIVE_ERROR) | ||||
|         Serial.println("Receive Failed"); | ||||
|       else if (error == OTA_END_ERROR) | ||||
|         Serial.println("End Failed"); | ||||
|     }); | ||||
|     _arduinoOTA->begin(); | ||||
|   } | ||||
|   | ||||
| @@ -4,13 +4,13 @@ | ||||
| #include <AdminSettingsService.h> | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266mDNS.h> | ||||
| #include <ESP8266mDNS.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <ESPmDNS.h> | ||||
| #include <ESPmDNS.h> | ||||
| #endif | ||||
|  | ||||
| #include <WiFiUdp.h> | ||||
| #include <ArduinoOTA.h> | ||||
| #include <WiFiUdp.h> | ||||
|  | ||||
| // Emergency defaults | ||||
| #define DEFAULT_OTA_PORT 8266 | ||||
| @@ -20,36 +20,31 @@ | ||||
| #define OTA_SETTINGS_SERVICE_PATH "/rest/otaSettings" | ||||
|  | ||||
| class OTASettingsService : public AdminSettingsService { | ||||
|  public: | ||||
|   OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|   ~OTASettingsService(); | ||||
|  | ||||
|   public: | ||||
|   void loop(); | ||||
|  | ||||
|     OTASettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|     ~OTASettingsService(); | ||||
|  protected: | ||||
|   void onConfigUpdated(); | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
|  | ||||
|     void loop(); | ||||
|  private: | ||||
|   ArduinoOTAClass* _arduinoOTA; | ||||
|   bool _enabled; | ||||
|   int _port; | ||||
|   String _password; | ||||
|  | ||||
|   protected: | ||||
|  | ||||
|       void onConfigUpdated(); | ||||
|       void readFromJsonObject(JsonObject& root); | ||||
|       void writeToJsonObject(JsonObject& root); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     ArduinoOTAClass *_arduinoOTA; | ||||
|     bool _enabled; | ||||
|     int _port; | ||||
|     String _password; | ||||
|  | ||||
|     void configureArduinoOTA(); | ||||
|   void configureArduinoOTA(); | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|     WiFiEventHandler _onStationModeGotIPHandler;     | ||||
|     void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
|   WiFiEventHandler _onStationModeGotIPHandler; | ||||
|   void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);     | ||||
|   void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
| #endif | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif // end OTASettingsService_h | ||||
| #endif  // end OTASettingsService_h | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| #include <RestartService.h> | ||||
|  | ||||
| RestartService::RestartService(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|   server->on(RESTART_SERVICE_PATH, HTTP_POST, securityManager->wrapRequest( | ||||
|     std::bind(&RestartService::restart, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN | ||||
|   )); | ||||
|   server->on(RESTART_SERVICE_PATH, | ||||
|              HTTP_POST, | ||||
|              securityManager->wrapRequest(std::bind(&RestartService::restart, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_ADMIN)); | ||||
| } | ||||
|  | ||||
| void RestartService::restart(AsyncWebServerRequest* request) { | ||||
|   | ||||
| @@ -2,11 +2,11 @@ | ||||
| #define RestartService_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| @@ -15,15 +15,11 @@ | ||||
| #define RESTART_SERVICE_PATH "/rest/restart" | ||||
|  | ||||
| class RestartService { | ||||
|  public: | ||||
|   RestartService(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|     | ||||
|     RestartService(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     void restart(AsyncWebServerRequest *request); | ||||
|  | ||||
|  private: | ||||
|   void restart(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end RestartService_h | ||||
| #endif  // end RestartService_h | ||||
| @@ -1,10 +1,10 @@ | ||||
| #include <SecurityManager.h> | ||||
|  | ||||
| Authentication SecurityManager::authenticateRequest(AsyncWebServerRequest *request) { | ||||
|   AsyncWebHeader* authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); | ||||
|   AsyncWebHeader *authorizationHeader = request->getHeader(AUTHORIZATION_HEADER); | ||||
|   if (authorizationHeader) { | ||||
|     String value = authorizationHeader->value(); | ||||
|     if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)){ | ||||
|     if (value.startsWith(AUTHORIZATION_HEADER_PREFIX)) { | ||||
|       value = value.substring(AUTHORIZATION_HEADER_PREFIX_LEN); | ||||
|       return authenticateJWT(value); | ||||
|     } | ||||
| @@ -19,7 +19,7 @@ Authentication SecurityManager::authenticateJWT(String jwt) { | ||||
|     JsonObject parsedPayload = payloadDocument.as<JsonObject>(); | ||||
|     String username = parsedPayload["username"]; | ||||
|     for (User _user : _users) { | ||||
|       if (_user.getUsername() == username && validatePayload(parsedPayload, &_user)){ | ||||
|       if (_user.getUsername() == username && validatePayload(parsedPayload, &_user)) { | ||||
|         return Authentication(_user); | ||||
|       } | ||||
|     } | ||||
| @@ -29,7 +29,7 @@ Authentication SecurityManager::authenticateJWT(String jwt) { | ||||
|  | ||||
| Authentication SecurityManager::authenticate(String username, String password) { | ||||
|   for (User _user : _users) { | ||||
|     if (_user.getUsername() == username && _user.getPassword() == password){ | ||||
|     if (_user.getUsername() == username && _user.getPassword() == password) { | ||||
|       return Authentication(_user); | ||||
|     } | ||||
|   } | ||||
| @@ -38,7 +38,7 @@ Authentication SecurityManager::authenticate(String username, String password) { | ||||
|  | ||||
| inline void populateJWTPayload(JsonObject &payload, User *user) { | ||||
|   payload["username"] = user->getUsername(); | ||||
|   payload["admin"] = user -> isAdmin();   | ||||
|   payload["admin"] = user->isAdmin(); | ||||
| } | ||||
|  | ||||
| boolean SecurityManager::validatePayload(JsonObject &parsedPayload, User *user) { | ||||
| @@ -55,8 +55,9 @@ String SecurityManager::generateJWT(User *user) { | ||||
|   return _jwtHandler.buildJWT(payload); | ||||
| } | ||||
|  | ||||
| ArRequestHandlerFunction SecurityManager::wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate) { | ||||
|   return [this, onRequest, predicate](AsyncWebServerRequest *request){ | ||||
| ArRequestHandlerFunction SecurityManager::wrapRequest(ArRequestHandlerFunction onRequest, | ||||
|                                                       AuthenticationPredicate predicate) { | ||||
|   return [this, onRequest, predicate](AsyncWebServerRequest *request) { | ||||
|     Authentication authentication = authenticateRequest(request); | ||||
|     if (!predicate(authentication)) { | ||||
|       request->send(401); | ||||
| @@ -65,4 +66,3 @@ ArRequestHandlerFunction SecurityManager::wrapRequest(ArRequestHandlerFunction o | ||||
|     onRequest(request); | ||||
|   }; | ||||
| } | ||||
|      | ||||
| @@ -1,9 +1,9 @@ | ||||
| #ifndef SecurityManager_h | ||||
| #define SecurityManager_h | ||||
|  | ||||
| #include <list> | ||||
| #include <ArduinoJsonJWT.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <list> | ||||
|  | ||||
| #define DEFAULT_JWT_SECRET "esp8266-react" | ||||
|  | ||||
| @@ -14,97 +14,97 @@ | ||||
| #define MAX_JWT_SIZE 128 | ||||
|  | ||||
| class User { | ||||
|   private: | ||||
|     String _username; | ||||
|     String _password; | ||||
|     bool _admin; | ||||
|   public: | ||||
|     User(String username, String password, bool admin): _username(username), _password(password), _admin(admin) {} | ||||
|     String getUsername() { | ||||
|       return _username; | ||||
|     } | ||||
|     String getPassword() { | ||||
|       return _password; | ||||
|     }     | ||||
|     bool isAdmin() { | ||||
|       return _admin; | ||||
|     } | ||||
|  private: | ||||
|   String _username; | ||||
|   String _password; | ||||
|   bool _admin; | ||||
|  | ||||
|  public: | ||||
|   User(String username, String password, bool admin) : _username(username), _password(password), _admin(admin) { | ||||
|   } | ||||
|   String getUsername() { | ||||
|     return _username; | ||||
|   } | ||||
|   String getPassword() { | ||||
|     return _password; | ||||
|   } | ||||
|   bool isAdmin() { | ||||
|     return _admin; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| class Authentication { | ||||
|   private: | ||||
|     User *_user; | ||||
|     boolean _authenticated; | ||||
|   public: | ||||
|     Authentication(User& user): _user(new User(user)), _authenticated(true) {} | ||||
|     Authentication() : _user(nullptr), _authenticated(false) {}   | ||||
|     ~Authentication() { | ||||
|       delete(_user);    | ||||
|     } | ||||
|     User* getUser() { | ||||
|       return _user; | ||||
|     } | ||||
|     bool isAuthenticated() { | ||||
|       return _authenticated; | ||||
|     } | ||||
|  private: | ||||
|   User* _user; | ||||
|   boolean _authenticated; | ||||
|  | ||||
|  public: | ||||
|   Authentication(User& user) : _user(new User(user)), _authenticated(true) { | ||||
|   } | ||||
|   Authentication() : _user(nullptr), _authenticated(false) { | ||||
|   } | ||||
|   ~Authentication() { | ||||
|     delete (_user); | ||||
|   } | ||||
|   User* getUser() { | ||||
|     return _user; | ||||
|   } | ||||
|   bool isAuthenticated() { | ||||
|     return _authenticated; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| typedef std::function<boolean(Authentication &authentication)> AuthenticationPredicate; | ||||
| typedef std::function<boolean(Authentication& authentication)> AuthenticationPredicate; | ||||
|  | ||||
| class AuthenticationPredicates { | ||||
|   public: | ||||
|     static bool NONE_REQUIRED(Authentication &authentication) { | ||||
|       return true; | ||||
|     }; | ||||
|     static bool IS_AUTHENTICATED(Authentication &authentication) { | ||||
|       return authentication.isAuthenticated(); | ||||
|     };     | ||||
|     static bool IS_ADMIN(Authentication &authentication) { | ||||
|       return authentication.isAuthenticated() && authentication.getUser()->isAdmin(); | ||||
|     }; | ||||
|  public: | ||||
|   static bool NONE_REQUIRED(Authentication& authentication) { | ||||
|     return true; | ||||
|   }; | ||||
|   static bool IS_AUTHENTICATED(Authentication& authentication) { | ||||
|     return authentication.isAuthenticated(); | ||||
|   }; | ||||
|   static bool IS_ADMIN(Authentication& authentication) { | ||||
|     return authentication.isAuthenticated() && authentication.getUser()->isAdmin(); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| class SecurityManager { | ||||
|  public: | ||||
|   /* | ||||
|    * Authenticate, returning the user if found | ||||
|    */ | ||||
|   Authentication authenticate(String username, String password); | ||||
|  | ||||
|   public: | ||||
|   /* | ||||
|    * Check the request header for the Authorization token | ||||
|    */ | ||||
|   Authentication authenticateRequest(AsyncWebServerRequest* request); | ||||
|  | ||||
|     /* | ||||
|     * Authenticate, returning the user if found | ||||
|     */ | ||||
|     Authentication authenticate(String username, String password); | ||||
|   /* | ||||
|    * Generate a JWT for the user provided | ||||
|    */ | ||||
|   String generateJWT(User* user); | ||||
|  | ||||
|     /* | ||||
|     * Check the request header for the Authorization token | ||||
|     */ | ||||
|     Authentication authenticateRequest(AsyncWebServerRequest *request); | ||||
|   /** | ||||
|    * Wrap the provided request to provide validation against an AuthenticationPredicate. | ||||
|    */ | ||||
|   ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate); | ||||
|  | ||||
|     /* | ||||
|     * Generate a JWT for the user provided | ||||
|     */ | ||||
|     String generateJWT(User *user); | ||||
|  protected: | ||||
|   ArduinoJsonJWT _jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET); | ||||
|   std::list<User> _users; | ||||
|  | ||||
|     /** | ||||
|      * Wrap the provided request to provide validation against an AuthenticationPredicate. | ||||
|      */ | ||||
|     ArRequestHandlerFunction wrapRequest(ArRequestHandlerFunction onRequest, AuthenticationPredicate predicate);  | ||||
|  | ||||
|   protected: | ||||
|  | ||||
|     ArduinoJsonJWT _jwtHandler = ArduinoJsonJWT(DEFAULT_JWT_SECRET); | ||||
|     std::list<User> _users; | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     /* | ||||
|     * Lookup the user by JWT | ||||
|     */ | ||||
|     Authentication authenticateJWT(String jwt); | ||||
|  | ||||
|     /* | ||||
|     * Verify the payload is correct | ||||
|     */ | ||||
|     boolean validatePayload(JsonObject &parsedPayload, User *user); | ||||
|  private: | ||||
|   /* | ||||
|    * Lookup the user by JWT | ||||
|    */ | ||||
|   Authentication authenticateJWT(String jwt); | ||||
|  | ||||
|   /* | ||||
|    * Verify the payload is correct | ||||
|    */ | ||||
|   boolean validatePayload(JsonObject& parsedPayload, User* user); | ||||
| }; | ||||
|  | ||||
| #endif // end SecurityManager_h | ||||
| #endif  // end SecurityManager_h | ||||
| @@ -1,7 +1,11 @@ | ||||
| #include <SecuritySettingsService.h> | ||||
|  | ||||
| SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : AdminSettingsService(server, fs, this, SECURITY_SETTINGS_PATH, SECURITY_SETTINGS_FILE), SecurityManager() {} | ||||
| SecuritySettingsService::~SecuritySettingsService() {} | ||||
| SecuritySettingsService::SecuritySettingsService(AsyncWebServer* server, FS* fs) : | ||||
|     AdminSettingsService(server, fs, this, SECURITY_SETTINGS_PATH, SECURITY_SETTINGS_FILE), | ||||
|     SecurityManager() { | ||||
| } | ||||
| SecuritySettingsService::~SecuritySettingsService() { | ||||
| } | ||||
|  | ||||
| void SecuritySettingsService::readFromJsonObject(JsonObject& root) { | ||||
|   // secret | ||||
| @@ -10,7 +14,7 @@ void SecuritySettingsService::readFromJsonObject(JsonObject& root) { | ||||
|   // users | ||||
|   _users.clear(); | ||||
|   if (root["users"].is<JsonArray>()) { | ||||
|     for (JsonVariant user :  root["users"].as<JsonArray>()) { | ||||
|     for (JsonVariant user : root["users"].as<JsonArray>()) { | ||||
|       _users.push_back(User(user["username"], user["password"], user["admin"])); | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -8,17 +8,13 @@ | ||||
| #define SECURITY_SETTINGS_PATH "/rest/securitySettings" | ||||
|  | ||||
| class SecuritySettingsService : public AdminSettingsService, public SecurityManager { | ||||
|  public: | ||||
|   SecuritySettingsService(AsyncWebServer* server, FS* fs); | ||||
|   ~SecuritySettingsService(); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     SecuritySettingsService(AsyncWebServer* server, FS* fs); | ||||
|     ~SecuritySettingsService(); | ||||
|  | ||||
|   protected: | ||||
|  | ||||
|     void readFromJsonObject(JsonObject& root); | ||||
|     void writeToJsonObject(JsonObject& root); | ||||
|  | ||||
|  protected: | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
| }; | ||||
|  | ||||
| #endif // end SecuritySettingsService_h | ||||
| #endif  // end SecuritySettingsService_h | ||||
| @@ -1,26 +1,24 @@ | ||||
| #ifndef SettingsPersistence_h | ||||
| #define SettingsPersistence_h | ||||
|  | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <FS.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <AsyncJson.h> | ||||
|  | ||||
| /** | ||||
| * At the moment, not expecting settings service to have to deal with large JSON | ||||
| * files this could be made configurable fairly simply, it's exposed on | ||||
| * AsyncJsonWebHandler with a setter. | ||||
| */ | ||||
|  * At the moment, not expecting settings service to have to deal with large JSON | ||||
|  * files this could be made configurable fairly simply, it's exposed on | ||||
|  * AsyncJsonWebHandler with a setter. | ||||
|  */ | ||||
| #define MAX_SETTINGS_SIZE 1024 | ||||
|  | ||||
| /* | ||||
| * Mixin for classes which need to save settings to/from a file on the the file system as JSON. | ||||
| */ | ||||
|  * Mixin for classes which need to save settings to/from a file on the the file system as JSON. | ||||
|  */ | ||||
| class SettingsPersistence { | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   // will store and retrieve config from the file system | ||||
|   FS* _fs; | ||||
|  | ||||
| @@ -58,7 +56,7 @@ protected: | ||||
|       if (size <= MAX_SETTINGS_SIZE) { | ||||
|         DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE); | ||||
|         DeserializationError error = deserializeJson(jsonDocument, configFile); | ||||
|         if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()){ | ||||
|         if (error == DeserializationError::Ok && jsonDocument.is<JsonObject>()) { | ||||
|           JsonObject root = jsonDocument.as<JsonObject>(); | ||||
|           readFromJsonObject(root); | ||||
|           configFile.close(); | ||||
| @@ -73,26 +71,26 @@ protected: | ||||
|     applyDefaultConfig(); | ||||
|   } | ||||
|  | ||||
|   // serialization routene, from local config to JsonObject | ||||
|   virtual void readFromJsonObject(JsonObject& root) { | ||||
|   } | ||||
|   virtual void writeToJsonObject(JsonObject& root) { | ||||
|   } | ||||
|  | ||||
|     // serialization routene, from local config to JsonObject | ||||
|     virtual void readFromJsonObject(JsonObject& root){} | ||||
|     virtual void writeToJsonObject(JsonObject& root){} | ||||
|   // We assume the readFromJsonObject supplies sensible defaults if an empty object | ||||
|   // is supplied, this virtual function allows that to be changed. | ||||
|   virtual void applyDefaultConfig() { | ||||
|     DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE); | ||||
|     JsonObject root = jsonDocument.to<JsonObject>(); | ||||
|     readFromJsonObject(root); | ||||
|   } | ||||
|  | ||||
|     // We assume the readFromJsonObject supplies sensible defaults if an empty object | ||||
|     // is supplied, this virtual function allows that to be changed. | ||||
|     virtual void applyDefaultConfig(){ | ||||
|       DynamicJsonDocument jsonDocument = DynamicJsonDocument(MAX_SETTINGS_SIZE); | ||||
|       JsonObject root = jsonDocument.to<JsonObject>(); | ||||
|       readFromJsonObject(root); | ||||
|     } | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     SettingsPersistence(FS* fs, char const* filePath): | ||||
|       _fs(fs), _filePath(filePath) {} | ||||
|  | ||||
|     virtual ~SettingsPersistence() {} | ||||
|  public: | ||||
|   SettingsPersistence(FS* fs, char const* filePath) : _fs(fs), _filePath(filePath) { | ||||
|   } | ||||
|  | ||||
|   virtual ~SettingsPersistence() { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end SettingsPersistence | ||||
| #endif  // end SettingsPersistence | ||||
|   | ||||
| @@ -5,64 +5,66 @@ | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
| #include <WiFi.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <SecurityManager.h> | ||||
| #include <SettingsPersistence.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <AsyncJsonCallbackResponse.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <SecurityManager.h> | ||||
| #include <SettingsPersistence.h> | ||||
|  | ||||
| /* | ||||
| * Abstraction of a service which stores it's settings as JSON in a file system. | ||||
| */ | ||||
|  * Abstraction of a service which stores it's settings as JSON in a file system. | ||||
|  */ | ||||
| class SettingsService : public SettingsPersistence { | ||||
|  public: | ||||
|   SettingsService(AsyncWebServer* server, FS* fs, char const* servicePath, char const* filePath) : | ||||
|       SettingsPersistence(fs, filePath), | ||||
|       _servicePath(servicePath) { | ||||
|     server->on(_servicePath, HTTP_GET, std::bind(&SettingsService::fetchConfig, this, std::placeholders::_1)); | ||||
|     _updateHandler.setUri(servicePath); | ||||
|     _updateHandler.setMethod(HTTP_POST); | ||||
|     _updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE); | ||||
|     _updateHandler.onRequest( | ||||
|         std::bind(&SettingsService::updateConfig, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|     server->addHandler(&_updateHandler); | ||||
|   } | ||||
|  | ||||
|   public: | ||||
|   virtual ~SettingsService() { | ||||
|   } | ||||
|  | ||||
|     SettingsService(AsyncWebServer* server, FS* fs, char const* servicePath, char const* filePath): SettingsPersistence(fs, filePath), _servicePath(servicePath) { | ||||
|       server->on(_servicePath, HTTP_GET, std::bind(&SettingsService::fetchConfig, this, std::placeholders::_1));     | ||||
|   void begin() { | ||||
|     // read the initial data from the file system | ||||
|     readFromFS(); | ||||
|   } | ||||
|  | ||||
|       _updateHandler.setUri(servicePath); | ||||
|       _updateHandler.setMethod(HTTP_POST); | ||||
|       _updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE); | ||||
|       _updateHandler.onRequest(std::bind(&SettingsService::updateConfig, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|       server->addHandler(&_updateHandler);      | ||||
|     } | ||||
|  | ||||
|     virtual ~SettingsService() {} | ||||
|  | ||||
|     void begin() { | ||||
|       // read the initial data from the file system | ||||
|       readFromFS(); | ||||
|     } | ||||
|  | ||||
| protected: | ||||
|  protected: | ||||
|   char const* _servicePath; | ||||
|   AsyncJsonWebHandler _updateHandler; | ||||
|  | ||||
|   virtual void fetchConfig(AsyncWebServerRequest *request) { | ||||
|   virtual void fetchConfig(AsyncWebServerRequest* request) { | ||||
|     // handle the request | ||||
|     AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_SETTINGS_SIZE); | ||||
|     AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_SETTINGS_SIZE); | ||||
|     JsonObject jsonObject = response->getRoot(); | ||||
|     writeToJsonObject(jsonObject); | ||||
|     response->setLength(); | ||||
|     request->send(response); | ||||
|   } | ||||
|  | ||||
|   virtual void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) { | ||||
|   virtual void updateConfig(AsyncWebServerRequest* request, JsonDocument& jsonDocument) { | ||||
|     // handle the request | ||||
|     if (jsonDocument.is<JsonObject>()){ | ||||
|     if (jsonDocument.is<JsonObject>()) { | ||||
|       JsonObject newConfig = jsonDocument.as<JsonObject>(); | ||||
|       readFromJsonObject(newConfig); | ||||
|       writeToFS(); | ||||
|  | ||||
|       // write settings back with a callback to reconfigure the wifi | ||||
|       AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();}, false, MAX_SETTINGS_SIZE); | ||||
|       AsyncJsonCallbackResponse* response = | ||||
|           new AsyncJsonCallbackResponse([this]() { onConfigUpdated(); }, false, MAX_SETTINGS_SIZE); | ||||
|       JsonObject jsonObject = response->getRoot(); | ||||
|       writeToJsonObject(jsonObject); | ||||
|       response->setLength(); | ||||
| @@ -73,8 +75,8 @@ protected: | ||||
|   } | ||||
|  | ||||
|   // implement to perform action when config has been updated | ||||
|   virtual void onConfigUpdated(){} | ||||
|  | ||||
|   virtual void onConfigUpdated() { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end SettingsService | ||||
| #endif  // end SettingsService | ||||
|   | ||||
| @@ -2,53 +2,52 @@ | ||||
| #define Service_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <AsyncJsonCallbackResponse.h> | ||||
| #include <AsyncJsonWebHandler.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
|  | ||||
| /** | ||||
| * At the moment, not expecting services to have to deal with large JSON | ||||
| * files this could be made configurable fairly simply, it's exposed on | ||||
| * AsyncJsonWebHandler with a setter. | ||||
| */ | ||||
|  * At the moment, not expecting services to have to deal with large JSON | ||||
|  * files this could be made configurable fairly simply, it's exposed on | ||||
|  * AsyncJsonWebHandler with a setter. | ||||
|  */ | ||||
| #define MAX_SETTINGS_SIZE 1024 | ||||
|  | ||||
| /* | ||||
| * Abstraction of a service which reads and writes data from an endpoint. | ||||
| * | ||||
| * Not currently used, but indended for use by features which do not | ||||
| * require setting persistance. | ||||
| */ | ||||
|  * Abstraction of a service which reads and writes data from an endpoint. | ||||
|  * | ||||
|  * Not currently used, but indended for use by features which do not | ||||
|  * require setting persistance. | ||||
|  */ | ||||
| class SimpleService { | ||||
|  | ||||
| private: | ||||
|  | ||||
|  private: | ||||
|   AsyncJsonWebHandler _updateHandler; | ||||
|  | ||||
|   void fetchConfig(AsyncWebServerRequest *request) { | ||||
|     AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_SETTINGS_SIZE); | ||||
|   void fetchConfig(AsyncWebServerRequest* request) { | ||||
|     AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_SETTINGS_SIZE); | ||||
|     JsonObject jsonObject = response->getRoot(); | ||||
|     writeToJsonObject(jsonObject); | ||||
|     response->setLength(); | ||||
|     request->send(response); | ||||
|   } | ||||
|  | ||||
|   void updateConfig(AsyncWebServerRequest *request, JsonDocument &jsonDocument) { | ||||
|   void updateConfig(AsyncWebServerRequest* request, JsonDocument& jsonDocument) { | ||||
|     if (jsonDocument.is<JsonObject>()) { | ||||
|       JsonObject newConfig = jsonDocument.as<JsonObject>(); | ||||
|       readFromJsonObject(newConfig); | ||||
|  | ||||
|       // write settings back with a callback to reconfigure the wifi | ||||
|       AsyncJsonCallbackResponse * response = new AsyncJsonCallbackResponse([this] () {onConfigUpdated();}, false,  MAX_SETTINGS_SIZE); | ||||
|       AsyncJsonCallbackResponse* response = | ||||
|           new AsyncJsonCallbackResponse([this]() { onConfigUpdated(); }, false, MAX_SETTINGS_SIZE); | ||||
|       JsonObject jsonObject = response->getRoot(); | ||||
|       writeToJsonObject(jsonObject); | ||||
|       response->setLength(); | ||||
| @@ -58,29 +57,31 @@ private: | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   protected: | ||||
|  protected: | ||||
|   // reads the local config from the | ||||
|   virtual void readFromJsonObject(JsonObject& root) { | ||||
|   } | ||||
|   virtual void writeToJsonObject(JsonObject& root) { | ||||
|   } | ||||
|  | ||||
|     // reads the local config from the | ||||
|     virtual void readFromJsonObject(JsonObject& root) {} | ||||
|     virtual void writeToJsonObject(JsonObject& root) {} | ||||
|   // implement to perform action when config has been updated | ||||
|   virtual void onConfigUpdated() { | ||||
|   } | ||||
|  | ||||
|     // implement to perform action when config has been updated | ||||
|     virtual void onConfigUpdated() {} | ||||
|  public: | ||||
|   SimpleService(AsyncWebServer* server, char const* servicePath) { | ||||
|     server->on(servicePath, HTTP_GET, std::bind(&SimpleService::fetchConfig, this, std::placeholders::_1)); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     SimpleService(AsyncWebServer* server, char const* servicePath) { | ||||
|       server->on(servicePath, HTTP_GET, std::bind(&SimpleService::fetchConfig, this, std::placeholders::_1));     | ||||
|  | ||||
|       _updateHandler.setUri(servicePath); | ||||
|       _updateHandler.setMethod(HTTP_POST); | ||||
|       _updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE); | ||||
|       _updateHandler.onRequest(std::bind(&SimpleService::updateConfig, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|       server->addHandler(&_updateHandler);   | ||||
|     } | ||||
|      | ||||
|     virtual ~SimpleService() {} | ||||
|     _updateHandler.setUri(servicePath); | ||||
|     _updateHandler.setMethod(HTTP_POST); | ||||
|     _updateHandler.setMaxContentLength(MAX_SETTINGS_SIZE); | ||||
|     _updateHandler.onRequest( | ||||
|         std::bind(&SimpleService::updateConfig, this, std::placeholders::_1, std::placeholders::_2)); | ||||
|     server->addHandler(&_updateHandler); | ||||
|   } | ||||
|  | ||||
|   virtual ~SimpleService() { | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // end SimpleService | ||||
| #endif  // end SimpleService | ||||
|   | ||||
| @@ -1,13 +1,14 @@ | ||||
| #include <SystemStatus.h> | ||||
|  | ||||
| SystemStatus::SystemStatus(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|   server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, | ||||
|     securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) | ||||
|   ); | ||||
|   server->on(SYSTEM_STATUS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_AUTHENTICATED)); | ||||
| } | ||||
|  | ||||
| void SystemStatus::systemStatus(AsyncWebServerRequest *request) { | ||||
|   AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE); | ||||
| void SystemStatus::systemStatus(AsyncWebServerRequest* request) { | ||||
|   AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE); | ||||
|   JsonObject root = response->getRoot(); | ||||
| #if defined(ESP8266) | ||||
|   root["esp_platform"] = "esp8266"; | ||||
|   | ||||
| @@ -2,31 +2,27 @@ | ||||
| #define SystemStatus_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <SecurityManager.h> | ||||
|  | ||||
| #define MAX_ESP_STATUS_SIZE 1024 | ||||
| #define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" | ||||
|  | ||||
| class SystemStatus { | ||||
|  public: | ||||
|   SystemStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|     | ||||
|     SystemStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     void systemStatus(AsyncWebServerRequest *request); | ||||
|  | ||||
|  private: | ||||
|   void systemStatus(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end SystemStatus_h | ||||
| #endif  // end SystemStatus_h | ||||
| @@ -1,29 +1,31 @@ | ||||
| #include <WiFiScanner.h> | ||||
|  | ||||
| WiFiScanner::WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager)  { | ||||
|   server->on(SCAN_NETWORKS_SERVICE_PATH, HTTP_GET,  | ||||
|     securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN) | ||||
|   ); | ||||
|   server->on(LIST_NETWORKS_SERVICE_PATH, HTTP_GET,  | ||||
|     securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), AuthenticationPredicates::IS_ADMIN) | ||||
|   ); | ||||
| WiFiScanner::WiFiScanner(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|   server->on(SCAN_NETWORKS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&WiFiScanner::scanNetworks, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_ADMIN)); | ||||
|   server->on(LIST_NETWORKS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&WiFiScanner::listNetworks, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_ADMIN)); | ||||
| }; | ||||
|  | ||||
| void WiFiScanner::scanNetworks(AsyncWebServerRequest *request) { | ||||
|       if (WiFi.scanComplete() != -1){ | ||||
|         WiFi.scanDelete(); | ||||
|         WiFi.scanNetworks(true); | ||||
|       } | ||||
|       request->send(202); | ||||
| void WiFiScanner::scanNetworks(AsyncWebServerRequest* request) { | ||||
|   if (WiFi.scanComplete() != -1) { | ||||
|     WiFi.scanDelete(); | ||||
|     WiFi.scanNetworks(true); | ||||
|   } | ||||
|   request->send(202); | ||||
| } | ||||
|  | ||||
| void WiFiScanner::listNetworks(AsyncWebServerRequest *request) { | ||||
| void WiFiScanner::listNetworks(AsyncWebServerRequest* request) { | ||||
|   int numNetworks = WiFi.scanComplete(); | ||||
|   if (numNetworks > -1){ | ||||
|     AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_WIFI_SCANNER_SIZE); | ||||
|   if (numNetworks > -1) { | ||||
|     AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_WIFI_SCANNER_SIZE); | ||||
|     JsonObject root = response->getRoot(); | ||||
|     JsonArray networks = root.createNestedArray("networks"); | ||||
|     for (int i=0; i<numNetworks ; i++){ | ||||
|     for (int i = 0; i < numNetworks; i++) { | ||||
|       JsonObject network = networks.createNestedObject(); | ||||
|       network["rssi"] = WiFi.RSSI(i); | ||||
|       network["ssid"] = WiFi.SSID(i); | ||||
| @@ -32,14 +34,14 @@ void WiFiScanner::listNetworks(AsyncWebServerRequest *request) { | ||||
| #if defined(ESP8266) | ||||
|       network["encryption_type"] = convertEncryptionType(WiFi.encryptionType(i)); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|       network["encryption_type"] = (uint8_t) WiFi.encryptionType(i);  | ||||
|       network["encryption_type"] = (uint8_t)WiFi.encryptionType(i); | ||||
| #endif | ||||
|     } | ||||
|     response->setLength(); | ||||
|     request->send(response); | ||||
|   } else if (numNetworks == -1){ | ||||
|   } else if (numNetworks == -1) { | ||||
|     request->send(202); | ||||
|   }else{ | ||||
|   } else { | ||||
|     scanNetworks(request); | ||||
|   } | ||||
| } | ||||
| @@ -50,8 +52,8 @@ void WiFiScanner::listNetworks(AsyncWebServerRequest *request) { | ||||
|  * | ||||
|  * This allows us to use a single set of mappings in the UI. | ||||
|  */ | ||||
| uint8_t WiFiScanner::convertEncryptionType(uint8_t encryptionType){ | ||||
|   switch (encryptionType){ | ||||
| uint8_t WiFiScanner::convertEncryptionType(uint8_t encryptionType) { | ||||
|   switch (encryptionType) { | ||||
|     case ENC_TYPE_NONE: | ||||
|       return AUTH_OPEN; | ||||
|     case ENC_TYPE_WEP: | ||||
|   | ||||
| @@ -2,18 +2,18 @@ | ||||
| #define WiFiScanner_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <TimeLib.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <SecurityManager.h> | ||||
| #include <TimeLib.h> | ||||
|  | ||||
| #define SCAN_NETWORKS_SERVICE_PATH "/rest/scanNetworks" | ||||
| #define LIST_NETWORKS_SERVICE_PATH "/rest/listNetworks" | ||||
| @@ -21,20 +21,16 @@ | ||||
| #define MAX_WIFI_SCANNER_SIZE 1024 | ||||
|  | ||||
| class WiFiScanner { | ||||
|  public: | ||||
|   WiFiScanner(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     WiFiScanner(AsyncWebServer *server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     void scanNetworks(AsyncWebServerRequest *request); | ||||
|     void listNetworks(AsyncWebServerRequest *request); | ||||
|  private: | ||||
|   void scanNetworks(AsyncWebServerRequest* request); | ||||
|   void listNetworks(AsyncWebServerRequest* request); | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|     uint8_t convertEncryptionType(uint8_t encryptionType); | ||||
|   uint8_t convertEncryptionType(uint8_t encryptionType); | ||||
| #endif | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif // end WiFiScanner_h | ||||
| #endif  // end WiFiScanner_h | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #include <WiFiSettingsService.h> | ||||
|  | ||||
| WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) { | ||||
| WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : | ||||
|     AdminSettingsService(server, fs, securityManager, WIFI_SETTINGS_SERVICE_PATH, WIFI_SETTINGS_FILE) { | ||||
|   // We want the device to come up in opmode=0 (WIFI_OFF), when erasing the flash this is not the default. | ||||
|   // If needed, we save opmode=0 before disabling persistence so the device boots with WiFi disabled in the future. | ||||
|   if (WiFi.getMode() != WIFI_OFF) { | ||||
| @@ -12,62 +13,66 @@ WiFiSettingsService::WiFiSettingsService(AsyncWebServer* server, FS* fs, Securit | ||||
|   WiFi.setAutoReconnect(false); | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); | ||||
|   _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected( | ||||
|       std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1)); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   // Init the wifi driver on ESP32 | ||||
|   WiFi.mode(WIFI_MODE_MAX); | ||||
|   WiFi.mode(WIFI_MODE_NULL); | ||||
|   WiFi.onEvent(std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED);  | ||||
|   WiFi.onEvent( | ||||
|       std::bind(&WiFiSettingsService::onStationModeDisconnected, this, std::placeholders::_1, std::placeholders::_2), | ||||
|       WiFiEvent_t::SYSTEM_EVENT_STA_DISCONNECTED); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| WiFiSettingsService::~WiFiSettingsService() {} | ||||
| WiFiSettingsService::~WiFiSettingsService() { | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::begin() { | ||||
|   SettingsService::begin(); | ||||
|   reconfigureWiFiConnection(); | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::readFromJsonObject(JsonObject& root){ | ||||
|     _ssid = root["ssid"] | ""; | ||||
|     _password = root["password"] | ""; | ||||
|     _hostname = root["hostname"] | ""; | ||||
|     _staticIPConfig = root["static_ip_config"] | false; | ||||
| void WiFiSettingsService::readFromJsonObject(JsonObject& root) { | ||||
|   _ssid = root["ssid"] | ""; | ||||
|   _password = root["password"] | ""; | ||||
|   _hostname = root["hostname"] | ""; | ||||
|   _staticIPConfig = root["static_ip_config"] | false; | ||||
|  | ||||
|     // extended settings | ||||
|     readIP(root, "local_ip", _localIP); | ||||
|     readIP(root, "gateway_ip", _gatewayIP); | ||||
|     readIP(root, "subnet_mask", _subnetMask); | ||||
|     readIP(root, "dns_ip_1", _dnsIP1); | ||||
|     readIP(root, "dns_ip_2", _dnsIP2); | ||||
|   // extended settings | ||||
|   readIP(root, "local_ip", _localIP); | ||||
|   readIP(root, "gateway_ip", _gatewayIP); | ||||
|   readIP(root, "subnet_mask", _subnetMask); | ||||
|   readIP(root, "dns_ip_1", _dnsIP1); | ||||
|   readIP(root, "dns_ip_2", _dnsIP2); | ||||
|  | ||||
|     // Swap around the dns servers if 2 is populated but 1 is not | ||||
|     if (_dnsIP1 == INADDR_NONE && _dnsIP2 != INADDR_NONE){ | ||||
|       _dnsIP1 = _dnsIP2; | ||||
|       _dnsIP2 = INADDR_NONE; | ||||
|     } | ||||
|   // Swap around the dns servers if 2 is populated but 1 is not | ||||
|   if (_dnsIP1 == INADDR_NONE && _dnsIP2 != INADDR_NONE) { | ||||
|     _dnsIP1 = _dnsIP2; | ||||
|     _dnsIP2 = INADDR_NONE; | ||||
|   } | ||||
|  | ||||
|     // Turning off static ip config if we don't meet the minimum requirements | ||||
|     // of ipAddress, gateway and subnet. This may change to static ip only | ||||
|     // as sensible defaults can be assumed for gateway and subnet | ||||
|     if (_staticIPConfig && (_localIP == INADDR_NONE || _gatewayIP == INADDR_NONE || _subnetMask == INADDR_NONE)){ | ||||
|       _staticIPConfig = false; | ||||
|     } | ||||
|   // Turning off static ip config if we don't meet the minimum requirements | ||||
|   // of ipAddress, gateway and subnet. This may change to static ip only | ||||
|   // as sensible defaults can be assumed for gateway and subnet | ||||
|   if (_staticIPConfig && (_localIP == INADDR_NONE || _gatewayIP == INADDR_NONE || _subnetMask == INADDR_NONE)) { | ||||
|     _staticIPConfig = false; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::writeToJsonObject(JsonObject& root){ | ||||
|       // connection settings | ||||
|       root["ssid"] = _ssid; | ||||
|       root["password"] = _password; | ||||
|       root["hostname"] = _hostname; | ||||
|       root["static_ip_config"] = _staticIPConfig; | ||||
| void WiFiSettingsService::writeToJsonObject(JsonObject& root) { | ||||
|   // connection settings | ||||
|   root["ssid"] = _ssid; | ||||
|   root["password"] = _password; | ||||
|   root["hostname"] = _hostname; | ||||
|   root["static_ip_config"] = _staticIPConfig; | ||||
|  | ||||
|       // extended settings | ||||
|       writeIP(root, "local_ip", _localIP); | ||||
|       writeIP(root, "gateway_ip", _gatewayIP); | ||||
|       writeIP(root, "subnet_mask", _subnetMask); | ||||
|       writeIP(root, "dns_ip_1", _dnsIP1); | ||||
|       writeIP(root, "dns_ip_2", _dnsIP2); | ||||
|   // extended settings | ||||
|   writeIP(root, "local_ip", _localIP); | ||||
|   writeIP(root, "gateway_ip", _gatewayIP); | ||||
|   writeIP(root, "subnet_mask", _subnetMask); | ||||
|   writeIP(root, "dns_ip_1", _dnsIP1); | ||||
|   writeIP(root, "dns_ip_2", _dnsIP2); | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::onConfigUpdated() { | ||||
| @@ -75,21 +80,21 @@ void WiFiSettingsService::onConfigUpdated() { | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::reconfigureWiFiConnection() { | ||||
|     // disconnect and de-configure wifi | ||||
|     WiFi.disconnect(true); | ||||
|   // disconnect and de-configure wifi | ||||
|   WiFi.disconnect(true); | ||||
|  | ||||
|     // reset last connection attempt to force loop to reconnect immediately | ||||
|     _lastConnectionAttempt = 0; | ||||
|   // reset last connection attempt to force loop to reconnect immediately | ||||
|   _lastConnectionAttempt = 0; | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::readIP(JsonObject& root, String key, IPAddress& _ip){ | ||||
|   if (!root[key].is<String>() || !_ip.fromString(root[key].as<String>())){ | ||||
| void WiFiSettingsService::readIP(JsonObject& root, String key, IPAddress& _ip) { | ||||
|   if (!root[key].is<String>() || !_ip.fromString(root[key].as<String>())) { | ||||
|     _ip = INADDR_NONE; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void WiFiSettingsService::writeIP(JsonObject& root, String key, IPAddress& _ip){ | ||||
|   if (_ip != INADDR_NONE){ | ||||
| void WiFiSettingsService::writeIP(JsonObject& root, String key, IPAddress& _ip) { | ||||
|   if (_ip != INADDR_NONE) { | ||||
|     root[key] = _ip.toString(); | ||||
|   } | ||||
| } | ||||
| @@ -98,7 +103,7 @@ void WiFiSettingsService::loop() { | ||||
|   unsigned long currentMillis = millis(); | ||||
|   if (!_lastConnectionAttempt || (unsigned long)(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) { | ||||
|     _lastConnectionAttempt = currentMillis; | ||||
|      manageSTA(); | ||||
|     manageSTA(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -112,7 +117,7 @@ void WiFiSettingsService::manageSTA() { | ||||
|     Serial.println("Connecting to WiFi."); | ||||
|     if (_staticIPConfig) { | ||||
|       // configure for static IP | ||||
|       WiFi.config(_localIP, _gatewayIP,  _subnetMask, _dnsIP1, _dnsIP2); | ||||
|       WiFi.config(_localIP, _gatewayIP, _subnetMask, _dnsIP1, _dnsIP2); | ||||
|     } else { | ||||
|       // configure for DHCP | ||||
| #if defined(ESP8266) | ||||
| @@ -137,4 +142,3 @@ void WiFiSettingsService::onStationModeDisconnected(WiFiEvent_t event, WiFiEvent | ||||
|   WiFi.disconnect(true); | ||||
| } | ||||
| #endif | ||||
|  | ||||
|   | ||||
| @@ -9,50 +9,46 @@ | ||||
| #define WIFI_RECONNECTION_DELAY 1000 * 60 | ||||
|  | ||||
| class WiFiSettingsService : public AdminSettingsService { | ||||
|  public: | ||||
|   WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|   ~WiFiSettingsService(); | ||||
|  | ||||
|   public: | ||||
|   void begin(); | ||||
|   void loop(); | ||||
|  | ||||
|     WiFiSettingsService(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|     ~WiFiSettingsService(); | ||||
|  protected: | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
|   void onConfigUpdated(); | ||||
|  | ||||
|     void begin(); | ||||
|     void loop(); | ||||
|  private: | ||||
|   // connection settings | ||||
|   String _ssid; | ||||
|   String _password; | ||||
|   String _hostname; | ||||
|   bool _staticIPConfig; | ||||
|  | ||||
|   protected: | ||||
|   // for the mangement delay loop | ||||
|   unsigned long _lastConnectionAttempt; | ||||
|  | ||||
|     void readFromJsonObject(JsonObject& root); | ||||
|     void writeToJsonObject(JsonObject& root); | ||||
|     void onConfigUpdated(); | ||||
|  | ||||
|   private: | ||||
|     // connection settings | ||||
|     String _ssid; | ||||
|     String _password; | ||||
|     String _hostname; | ||||
|     bool _staticIPConfig; | ||||
|  | ||||
|     // for the mangement delay loop | ||||
|     unsigned long _lastConnectionAttempt; | ||||
|  | ||||
|     // optional configuration for static IP address | ||||
|     IPAddress _localIP; | ||||
|     IPAddress _gatewayIP; | ||||
|     IPAddress _subnetMask; | ||||
|     IPAddress _dnsIP1; | ||||
|     IPAddress _dnsIP2; | ||||
|   // optional configuration for static IP address | ||||
|   IPAddress _localIP; | ||||
|   IPAddress _gatewayIP; | ||||
|   IPAddress _subnetMask; | ||||
|   IPAddress _dnsIP1; | ||||
|   IPAddress _dnsIP2; | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|     WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|     void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
|   WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|   void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|   void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
| #endif | ||||
|  | ||||
|     void readIP(JsonObject& root, String key, IPAddress& _ip); | ||||
|     void writeIP(JsonObject& root, String key, IPAddress& _ip); | ||||
|     void reconfigureWiFiConnection(); | ||||
|     void manageSTA(); | ||||
|  | ||||
|   void readIP(JsonObject& root, String key, IPAddress& _ip); | ||||
|   void writeIP(JsonObject& root, String key, IPAddress& _ip); | ||||
|   void reconfigureWiFiConnection(); | ||||
|   void manageSTA(); | ||||
| }; | ||||
|  | ||||
| #endif // end WiFiSettingsService_h | ||||
| #endif  // end WiFiSettingsService_h | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| #include <WiFiStatus.h> | ||||
|  | ||||
| WiFiStatus::WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager)  { | ||||
|   server->on(WIFI_STATUS_SERVICE_PATH, HTTP_GET,  | ||||
|     securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), AuthenticationPredicates::IS_AUTHENTICATED) | ||||
|   );   | ||||
| WiFiStatus::WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager) { | ||||
|   server->on(WIFI_STATUS_SERVICE_PATH, | ||||
|              HTTP_GET, | ||||
|              securityManager->wrapRequest(std::bind(&WiFiStatus::wifiStatus, this, std::placeholders::_1), | ||||
|                                           AuthenticationPredicates::IS_AUTHENTICATED)); | ||||
| #if defined(ESP8266) | ||||
|   _onStationModeConnectedHandler = WiFi.onStationModeConnected(onStationModeConnected); | ||||
|   _onStationModeDisconnectedHandler = WiFi.onStationModeDisconnected(onStationModeDisconnected); | ||||
| @@ -50,12 +51,12 @@ void WiFiStatus::onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| void WiFiStatus::wifiStatus(AsyncWebServerRequest *request) { | ||||
|   AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_WIFI_STATUS_SIZE); | ||||
| void WiFiStatus::wifiStatus(AsyncWebServerRequest* request) { | ||||
|   AsyncJsonResponse* response = new AsyncJsonResponse(false, MAX_WIFI_STATUS_SIZE); | ||||
|   JsonObject root = response->getRoot(); | ||||
|   wl_status_t status = WiFi.status(); | ||||
|   root["status"] = (uint8_t) status; | ||||
|   if (status == WL_CONNECTED){ | ||||
|   root["status"] = (uint8_t)status; | ||||
|   if (status == WL_CONNECTED) { | ||||
|     root["local_ip"] = WiFi.localIP().toString(); | ||||
|     root["mac_address"] = WiFi.macAddress(); | ||||
|     root["rssi"] = WiFi.RSSI(); | ||||
| @@ -66,10 +67,10 @@ void WiFiStatus::wifiStatus(AsyncWebServerRequest *request) { | ||||
|     root["gateway_ip"] = WiFi.gatewayIP().toString(); | ||||
|     IPAddress dnsIP1 = WiFi.dnsIP(0); | ||||
|     IPAddress dnsIP2 = WiFi.dnsIP(1); | ||||
|     if (dnsIP1 != INADDR_NONE){ | ||||
|     if (dnsIP1 != INADDR_NONE) { | ||||
|       root["dns_ip_1"] = dnsIP1.toString(); | ||||
|     } | ||||
|     if (dnsIP2 != INADDR_NONE){ | ||||
|     if (dnsIP2 != INADDR_NONE) { | ||||
|       root["dns_ip_2"] = dnsIP2.toString(); | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -2,16 +2,16 @@ | ||||
| #define WiFiStatus_h | ||||
|  | ||||
| #if defined(ESP8266) | ||||
|   #include <ESP8266WiFi.h> | ||||
|   #include <ESPAsyncTCP.h> | ||||
| #include <ESP8266WiFi.h> | ||||
| #include <ESPAsyncTCP.h> | ||||
| #elif defined(ESP_PLATFORM) | ||||
|   #include <WiFi.h> | ||||
|   #include <AsyncTCP.h> | ||||
| #include <AsyncTCP.h> | ||||
| #include <WiFi.h> | ||||
| #endif | ||||
|  | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <ArduinoJson.h> | ||||
| #include <AsyncJson.h> | ||||
| #include <ESPAsyncWebServer.h> | ||||
| #include <IPAddress.h> | ||||
| #include <SecurityManager.h> | ||||
|  | ||||
| @@ -19,31 +19,27 @@ | ||||
| #define WIFI_STATUS_SERVICE_PATH "/rest/wifiStatus" | ||||
|  | ||||
| class WiFiStatus { | ||||
|  public: | ||||
|   WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   public: | ||||
|  | ||||
|     WiFiStatus(AsyncWebServer* server, SecurityManager* securityManager); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|  private: | ||||
| #if defined(ESP8266) | ||||
|     // handler refrences for logging important WiFi events over serial | ||||
|     WiFiEventHandler _onStationModeConnectedHandler; | ||||
|     WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|     WiFiEventHandler _onStationModeGotIPHandler;     | ||||
|     // static functions for logging WiFi events to the UART | ||||
|     static void onStationModeConnected(const WiFiEventStationModeConnected& event); | ||||
|     static void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
|     static void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
|   // handler refrences for logging important WiFi events over serial | ||||
|   WiFiEventHandler _onStationModeConnectedHandler; | ||||
|   WiFiEventHandler _onStationModeDisconnectedHandler; | ||||
|   WiFiEventHandler _onStationModeGotIPHandler; | ||||
|   // static functions for logging WiFi events to the UART | ||||
|   static void onStationModeConnected(const WiFiEventStationModeConnected& event); | ||||
|   static void onStationModeDisconnected(const WiFiEventStationModeDisconnected& event); | ||||
|   static void onStationModeGotIP(const WiFiEventStationModeGotIP& event); | ||||
| #elif defined(ESP_PLATFORM) | ||||
|     // static functions for logging WiFi events to the UART | ||||
|     static void onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|     static void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|     static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info);     | ||||
|   // static functions for logging WiFi events to the UART | ||||
|   static void onStationModeConnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|   static void onStationModeDisconnected(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
|   static void onStationModeGotIP(WiFiEvent_t event, WiFiEventInfo_t info); | ||||
| #endif | ||||
|  | ||||
|     void wifiStatus(AsyncWebServerRequest *request); | ||||
|  | ||||
|   void wifiStatus(AsyncWebServerRequest* request); | ||||
| }; | ||||
|  | ||||
| #endif // end WiFiStatus_h | ||||
| #endif  // end WiFiStatus_h | ||||
|   | ||||
| @@ -1,10 +1,12 @@ | ||||
| #include <DemoProject.h> | ||||
|  | ||||
| DemoProject::DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : AdminSettingsService(server, fs, securityManager, DEMO_SETTINGS_PATH, DEMO_SETTINGS_FILE) { | ||||
| DemoProject::DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager) : | ||||
|     AdminSettingsService(server, fs, securityManager, DEMO_SETTINGS_PATH, DEMO_SETTINGS_FILE) { | ||||
|   pinMode(BLINK_LED, OUTPUT); | ||||
| } | ||||
|  | ||||
| DemoProject::~DemoProject() {} | ||||
| DemoProject::~DemoProject() { | ||||
| } | ||||
|  | ||||
| void DemoProject::loop() { | ||||
|   unsigned delay = MAX_DELAY / 255 * (255 - _blinkSpeed); | ||||
| @@ -23,4 +25,3 @@ void DemoProject::writeToJsonObject(JsonObject& root) { | ||||
|   // connection settings | ||||
|   root["blink_speed"] = _blinkSpeed; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -11,24 +11,19 @@ | ||||
| #define DEMO_SETTINGS_PATH "/rest/demoSettings" | ||||
|  | ||||
| class DemoProject : public AdminSettingsService { | ||||
|  public: | ||||
|   DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|   ~DemoProject(); | ||||
|  | ||||
|   public: | ||||
|   void loop(); | ||||
|  | ||||
|     DemoProject(AsyncWebServer* server, FS* fs, SecurityManager* securityManager); | ||||
|     ~DemoProject(); | ||||
|      | ||||
|     void loop(); | ||||
|  | ||||
|   private: | ||||
|  | ||||
|     unsigned long _lastBlink = 0; | ||||
|     uint8_t _blinkSpeed = 255; | ||||
|  | ||||
|   protected: | ||||
|  | ||||
|     void readFromJsonObject(JsonObject& root); | ||||
|     void writeToJsonObject(JsonObject& root); | ||||
|  private: | ||||
|   unsigned long _lastBlink = 0; | ||||
|   uint8_t _blinkSpeed = 255; | ||||
|  | ||||
|  protected: | ||||
|   void readFromJsonObject(JsonObject& root); | ||||
|   void writeToJsonObject(JsonObject& root); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| #include <ESP8266React.h> | ||||
| #include <DemoProject.h> | ||||
| #include <ESP8266React.h> | ||||
| #include <FS.h> | ||||
|  | ||||
| #define SERIAL_BAUD_RATE 115200 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user