diff --git a/.gitignore b/.gitignore index 9fd7364..0c222fb 100644 --- a/.gitignore +++ b/.gitignore @@ -880,3 +880,4 @@ Temporary Items .pio/ .vscode/ +SourceCode/arduino/lib/esp32_https_server/ diff --git a/SourceCode/arduino/lib/Firewall/Firewall.cpp b/SourceCode/arduino/lib/Firewall/Firewall.cpp index 976e34c..45de01f 100644 --- a/SourceCode/arduino/lib/Firewall/Firewall.cpp +++ b/SourceCode/arduino/lib/Firewall/Firewall.cpp @@ -1,11 +1,15 @@ #include "Firewall.h" -ESPFirewall::ESPFirewall(int port) +ESPFirewall::ESPFirewall(int api_port) { this->setup_eeprom(); - log_i("Starting Firewall-API on %i", port); - this->firewall_api = new AsyncWebServer(port); - this->setup_routing(); + this->setup_certificate(); + this->setup_firewall_api(api_port); +} + +void ESPFirewall::handle_firewall_api_clients() +{ + this->firewall_api->loop(); } String ESPFirewall::protocol_to_string(firewall_protocol_t &protocol) @@ -21,11 +25,11 @@ String ESPFirewall::protocol_to_string(firewall_protocol_t &protocol) } } -firewall_protocol_t ESPFirewall::string_to_protocol(String &protocol) +firewall_protocol_t ESPFirewall::string_to_protocol(std::string &protocol) { - if (protocol.equals("TCP")) + if (protocol.compare("TCP") == 0) return FW_TCP; - else if (protocol.equals("UDP")) + else if (protocol.compare("UDP") == 0) return FW_UDP; else return FW_ALL; @@ -44,11 +48,11 @@ String ESPFirewall::target_to_string(firewall_target_t &target) } } -firewall_target_t ESPFirewall::string_to_target(String &target) +firewall_target_t ESPFirewall::string_to_target(std::string &target) { - if (target.equals("REJECT")) + if (target.compare("REJECT") == 0) return FW_REJECT; - else if (target.equals("DROP")) + else if (target.compare("DROP") == 0) return FW_DROP; else return FW_ACCEPT; @@ -206,30 +210,70 @@ bool ESPFirewall::delete_rule_from_firewall(uint8_t key) return true; } -void ESPFirewall::setup_routing() +void ESPFirewall::setup_certificate() { - this->firewall_api->on("^\\/api/v1/firewall\\/([0-9]+)$", HTTP_GET, std::bind(&ESPFirewall::get_firewall_rule_handler, this, std::placeholders::_1)); - this->firewall_api->on("/api/v1/firewall", HTTP_GET, std::bind(&ESPFirewall::get_firewall_rules_handler, this, std::placeholders::_1)); - this->firewall_api->on("/api/v1/firewall", HTTP_POST, std::bind(&ESPFirewall::post_firewall_handler, this, std::placeholders::_1)); - this->firewall_api->on("^\\/api/v1/firewall\\/([0-9]+)$", HTTP_DELETE, std::bind(&ESPFirewall::delete_firewall_handler, this, std::placeholders::_1)); - - this->firewall_api->on("/api/v1/device/restart", HTTP_GET, std::bind(&ESPFirewall::restart_device_handler, this, std::placeholders::_1)); - this->firewall_api->onNotFound(std::bind(&ESPFirewall::not_found, this, std::placeholders::_1)); - this->firewall_api->begin(); + log_i("Creating the certificate..."); + this->certificate = new SSLCert(); + int createCertResult = createSelfSignedCert( + *this->certificate, + KEYSIZE_2048, + "CN=myesp32.local,O=Firewall,C=DE", + "20220101000000", + "20320101000000"); + if (createCertResult != 0) + { + log_e("Cerating certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details", createCertResult); + while (true) + delay(500); + } + log_i("Creating the certificate was successful"); } -void ESPFirewall::json_message_response(AsyncWebServerRequest *request, String message, int response_code) +void ESPFirewall::setup_firewall_api(int api_port) { - DynamicJsonDocument json(256); - String response; + this->firewall_api = new HTTPSServer(this->certificate, api_port, 5); + ResourceNode *get_firewall_rule = new ResourceNode("/api/v1/firewall/*", "GET", std::bind(&ESPFirewall::get_firewall_rule_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *get_firewall_rules = new ResourceNode("/api/v1/firewall", "GET", std::bind(&ESPFirewall::get_firewall_rules_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *post_firewall = new ResourceNode("/api/v1/firewall", "POST", std::bind(&ESPFirewall::post_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *delete_firewall = new ResourceNode("/api/v1/firewall/*", "DELETE", std::bind(&ESPFirewall::delete_firewall_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *restart_device = new ResourceNode("/api/v1/device/restart", "GET", std::bind(&ESPFirewall::restart_device_handler, this, std::placeholders::_1, std::placeholders::_2)); + ResourceNode *not_found = new ResourceNode("", "GET", std::bind(&ESPFirewall::not_found_handler, this, std::placeholders::_1, std::placeholders::_2)); + this->firewall_api->registerNode(get_firewall_rule); + this->firewall_api->registerNode(get_firewall_rules); + this->firewall_api->registerNode(post_firewall); + this->firewall_api->registerNode(delete_firewall); + this->firewall_api->setDefaultNode(restart_device); + this->firewall_api->setDefaultNode(not_found); + + log_i("Starting server..."); + this->firewall_api->start(); + if (this->firewall_api->isRunning()) + { + log_i("Server ready."); + } +} + +void ESPFirewall::json_generic_response(HTTPResponse *response, String serialized, int response_code) +{ + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(response_code); + response->println(serialized); +} + +void ESPFirewall::json_message_response(HTTPResponse *response, String message, int response_code) +{ + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(response_code); + StaticJsonDocument<96> json; + String serialized; json["message"] = message; - serializeJson(json, response); - request->send(response_code, "application/json", response); + serializeJson(json, serialized); + response->println(serialized); } String ESPFirewall::construct_json_firewall_rule(firewall_rule_t *rule_ptr) { - StaticJsonDocument<192> doc; + StaticJsonDocument<256> doc; doc["key"] = rule_ptr->key; doc["source"] = rule_ptr->source; doc["destination"] = rule_ptr->destination; @@ -262,77 +306,88 @@ String ESPFirewall::construct_json_firewall() return response; } -void ESPFirewall::not_found(AsyncWebServerRequest *request) +void ESPFirewall::not_found_handler(HTTPRequest *request, HTTPResponse *response) { - this->json_message_response(request, "not found", 404); + this->json_message_response(response, "not found", 404); } -void ESPFirewall::restart_device_handler(AsyncWebServerRequest *request) +void ESPFirewall::restart_device_handler(HTTPRequest *request, HTTPResponse *response) { - this->json_message_response(request, "restarting device in 2 sec", 200); + this->json_message_response(response, "restarting device in 2 sec", 200); sleep(2000); esp_restart(); } -void ESPFirewall::get_firewall_rule_handler(AsyncWebServerRequest *request) +void ESPFirewall::get_firewall_rule_handler(HTTPRequest *request, HTTPResponse *response) { - int rule_number = request->pathArg(0).toInt(); + ResourceParameters *params = request->getParams(); + int rule_number = atoi(params->getPathParameter(0).c_str()); firewall_rule_t *rule_ptr = this->get_rule_from_firewall(rule_number); if (rule_ptr == NULL) { - this->json_message_response(request, "rule not found", 404); + this->json_message_response(response, "rule not found", 404); } else { - request->send(200, "application/json", this->construct_json_firewall_rule(rule_ptr)); + response->setHeader("Content-Type", "application/json"); + response->setStatusCode(200); + response->print(this->construct_json_firewall_rule(rule_ptr)); } } -void ESPFirewall::get_firewall_rules_handler(AsyncWebServerRequest *request) +void ESPFirewall::get_firewall_rules_handler(HTTPRequest *request, HTTPResponse *response) { - String response = this->construct_json_firewall(); - request->send(200, "application/json", response); + this->json_generic_response(response, this->construct_json_firewall(), 200); } -bool ESPFirewall::request_has_firewall_parameter(AsyncWebServerRequest *request) +bool ESPFirewall::request_has_firewall_parameter(ResourceParameters *params) { - return request->hasParam("source") || request->hasParam("destination") || request->hasParam("protocol") || request->hasParam("target"); + return params->isQueryParameterSet("source") || params->isQueryParameterSet("destination") || params->isQueryParameterSet("protocol") || params->isQueryParameterSet("target"); } -void ESPFirewall::post_firewall_handler(AsyncWebServerRequest *request) +void ESPFirewall::post_firewall_handler(HTTPRequest *request, HTTPResponse *response) { - if (request_has_firewall_parameter(request)) + ResourceParameters *params = request->getParams(); + if (request_has_firewall_parameter(params)) { firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); rule_ptr->key = ++amount_of_rules; // carefully copying c-string that is shorter then the destination char-array length - String source = request->getParam("source")->value(); + std::string source; + params->getQueryParameter("source", source); strcpy(rule_ptr->source, source.length() <= IP4ADDR_STRLEN_MAX ? source.c_str() : ""); - String destination = request->getParam("destination")->value(); + std::string destination; + params->getQueryParameter("destination", destination); strcpy(rule_ptr->destination, destination.length() <= IP4ADDR_STRLEN_MAX ? destination.c_str() : ""); - String protocol = request->getParam("protocol")->value(); + std::string protocol; + params->getQueryParameter("protocol", protocol); rule_ptr->protocol = string_to_protocol(protocol); - String target = request->getParam("target")->value(); + std::string target; + params->getQueryParameter("target", target); rule_ptr->target = string_to_target(target); this->add_rule_to_firewall(rule_ptr); this->eeprom_write_firewall_rule(rule_ptr); - request->send(200, "application/json", this->construct_json_firewall_rule(rule_ptr)); + this->json_generic_response(response, this->construct_json_firewall_rule(rule_ptr), 200); } else { - this->json_message_response(request, "not enough parameter", 200); + this->json_message_response(response, "not enough parameter", 400); } } -void ESPFirewall::delete_firewall_handler(AsyncWebServerRequest *request) +void ESPFirewall::delete_firewall_handler(HTTPRequest *request, HTTPResponse *response) { - int rule_number = request->pathArg(0).toInt(); + ResourceParameters *params = request->getParams(); + int rule_number = atoi(params->getPathParameter(0).c_str()); if (this->delete_rule_from_firewall(rule_number)) { - this->json_message_response(request, "firewall rule deleted", 200); + this->json_message_response(response, "firewall rule deleted", 200); + } + else + { + this->json_message_response(response, "cannot delete firewall rule", 500); } - this->json_message_response(request, "cannot delete firewall rule", 500); } diff --git a/SourceCode/arduino/lib/Firewall/Firewall.h b/SourceCode/arduino/lib/Firewall/Firewall.h index 65033c4..75cb181 100644 --- a/SourceCode/arduino/lib/Firewall/Firewall.h +++ b/SourceCode/arduino/lib/Firewall/Firewall.h @@ -2,19 +2,16 @@ #define FIREWALL_H #include "Arduino.h" -#include "AsyncJson.h" #include "ArduinoJson.h" #include "EEPROM.h" -#ifdef ESP32 -#include "WiFi.h" -#include "AsyncTCP.h" -#elif defined(ESP8266) -#include "ESP8266WiFi.h" -#include "ESPAsyncTCP.h" -#endif -#include "ESPAsyncWebServer.h" + +#include "HTTPSServer.hpp" +#include "SSLCert.hpp" +#include "HTTPRequest.hpp" +#include "HTTPResponse.hpp" #define eeprom_start_firewall_rules 4 +using namespace httpsserver; typedef enum firewall_target : uint8_t { @@ -49,13 +46,14 @@ class ESPFirewall int eeprom_rules_head = eeprom_start_firewall_rules; struct firewall_rule *head = NULL; - AsyncWebServer *firewall_api; + HTTPSServer *firewall_api; + SSLCert *certificate; // Protocol / Target conversion String protocol_to_string(firewall_protocol_t &); - firewall_protocol_t string_to_protocol(String &); + firewall_protocol_t string_to_protocol(std::string &); String target_to_string(firewall_target_t &); - firewall_target_t string_to_target(String &); + firewall_target_t string_to_target(std::string &); // EEPROM void setup_eeprom(); @@ -70,20 +68,23 @@ class ESPFirewall bool delete_rule_from_firewall(uint8_t); // Firewall-API Actions - void setup_routing(); - void json_message_response(AsyncWebServerRequest *, String, int); + void setup_certificate(); + void setup_firewall_api(int); + void json_generic_response(HTTPResponse *, String, int); + void json_message_response(HTTPResponse *, String, int); String construct_json_firewall_rule(firewall_rule_t *); String construct_json_firewall(); - void not_found(AsyncWebServerRequest *); - void restart_device_handler(AsyncWebServerRequest *); - void get_firewall_rule_handler(AsyncWebServerRequest *); - void get_firewall_rules_handler(AsyncWebServerRequest *); - bool request_has_firewall_parameter(AsyncWebServerRequest *); - void post_firewall_handler(AsyncWebServerRequest *); - void delete_firewall_handler(AsyncWebServerRequest *); + void not_found_handler(HTTPRequest *, HTTPResponse *); + void restart_device_handler(HTTPRequest *, HTTPResponse *); + void get_firewall_rule_handler(HTTPRequest *, HTTPResponse *); + void get_firewall_rules_handler(HTTPRequest *, HTTPResponse *); + bool request_has_firewall_parameter(ResourceParameters *); + void post_firewall_handler(HTTPRequest *, HTTPResponse *); + void delete_firewall_handler(HTTPRequest *, HTTPResponse *); public: ESPFirewall(int port = 8080); + void handle_firewall_api_clients(); }; #endif diff --git a/SourceCode/arduino/platformio.ini b/SourceCode/arduino/platformio.ini index 4c4e078..823bfc9 100644 --- a/SourceCode/arduino/platformio.ini +++ b/SourceCode/arduino/platformio.ini @@ -13,21 +13,17 @@ platform = espressif32 board = esp32-evb framework = arduino monitor_speed = 115200 -build_flags = +build_flags = -DCORE_DEBUG_LEVEL=3 - -DASYNCWEBSERVER_REGEX -lib_deps = +lib_deps = bblanchon/ArduinoJson@^6.19.4 - ottowinter/ESPAsyncWebServer-esphome@^2.1.0 [env:esp32-dev] platform = espressif32 board = az-delivery-devkit-v4 framework = arduino monitor_speed = 115200 -build_flags = +build_flags = -DCORE_DEBUG_LEVEL=3 - -DASYNCWEBSERVER_REGEX -lib_deps = +lib_deps = bblanchon/ArduinoJson@^6.19.4 - ottowinter/ESPAsyncWebServer-esphome@^2.1.0 diff --git a/SourceCode/arduino/src/main.cpp b/SourceCode/arduino/src/main.cpp index 08e942a..43c95f6 100644 --- a/SourceCode/arduino/src/main.cpp +++ b/SourceCode/arduino/src/main.cpp @@ -1,5 +1,6 @@ -#include +#include "Arduino.h" #include "theSecrets.h" +#include "WiFi.h" #include "Firewall.h" #include "esp32-hal-log.h" @@ -30,4 +31,5 @@ void setup() void loop() { + firewall->handle_firewall_api_clients(); } \ No newline at end of file