diff --git a/ESPFirewall/include/theCerts-example.h b/ESPFirewall/include/theCerts-example.h index 7103257..5523ed9 100644 --- a/ESPFirewall/include/theCerts-example.h +++ b/ESPFirewall/include/theCerts-example.h @@ -3,7 +3,7 @@ #include "pgmspace.h" -const char serverCert[] PROGMEM = R"EOF( +const char cert[] PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIDSzCCAjMCCQD2ahcfZAwXxDANBgkqhkiG9w0BAQsFADCBiTELMAkGA1UEBhMC VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU9yYW5nZSBDb3VudHkx @@ -26,7 +26,7 @@ JfUvYadSYxh3nblvA4OL+iEZiW8NE3hbW6WPXxvS7Euge0uWMPc4uEcnsE0ZVG3m -----END CERTIFICATE----- )EOF"; -const char serverKey[] PROGMEM = R"EOF( +const char key[] PROGMEM = R"EOF( -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA9UoHBtn4oNKXjRgIOQ/rLxK/iI0a8Q5mDxhfuwa9//FkftSI IFY8UhGk2YNJpnfKOyYWqbqwuJhIZJ2sEIWp2301OnavuGBrpKOgBJJljgH2l/4Z diff --git a/ESPFirewall/lib/Firewall/src/API.cpp b/ESPFirewall/lib/Firewall/src/API.cpp index 33abe6e..3ee7f6b 100644 --- a/ESPFirewall/lib/Firewall/src/API.cpp +++ b/ESPFirewall/lib/Firewall/src/API.cpp @@ -2,8 +2,10 @@ namespace fw { - API::API(const char *cert, const char *key, const char *username, const char *password, const uint16_t port) + API::API(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port) { + this->server_ip = ip; + this->server_port = port; if (this->setup_auth(username, password) == ERROR) endless_loop(); #ifdef ESP32 @@ -52,7 +54,7 @@ namespace fw } else { - this->json_message_response("unauthorized", 403); + this->json_message_response("please provide username and password", 403); return DENIED; } } @@ -63,16 +65,55 @@ namespace fw this->server->getServer().setRSACert(new BearSSL::X509List(cert), new BearSSL::PrivateKey(key)); this->server->getServer().setCache(serverCache); #endif - this->server->on(UriRegex("/api/v1/firewall/([0-9]+)"), HTTP_GET, std::bind(&API::get_firewall_rule_handler, this)); - this->server->on("/api/v1/firewall", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this)); - this->server->on("/api/v1/firewall", HTTP_POST, std::bind(&API::post_firewall_handler, this)); - this->server->on(UriRegex("/api/v1/firewall/([0-9]+)"), HTTP_DELETE, std::bind(&API::delete_firewall_handler, this)); + this->server->on("/firewall", HTTP_GET, std::bind(&API::get_firewall_rules_handler, this)); + add_api_endpoint("/firewall", "GET", "Get all Firewall Rules"); + + this->server->on(UriRegex("/firewall/([0-9]+)"), HTTP_GET, std::bind(&API::get_firewall_rule_handler, this)); + add_api_endpoint("/firewall/1", "GET", "Get Firewall Rule by key"); + + this->server->on("/firewall", HTTP_POST, std::bind(&API::post_firewall_handler, this)); + add_api_endpoint("/firewall", "POST", "Create Firewall Rule"); + + this->server->on(UriRegex("/firewall/([0-9]+)"), HTTP_DELETE, std::bind(&API::delete_firewall_handler, this)); + add_api_endpoint("/firewall/1", "DELETE", "Delete Firewall Rule by key"); + this->server->onNotFound(std::bind(&API::not_found_handler, this)); } + void API::add_api_endpoint(const String uri, const char *method, const char *description) + { + api_endpoint_t *temp; +#ifdef ESP32 + const String url = "http://" + this->server_ip + ":" + this->server_port + uri; +#elif defined(ESP8266) + const String url = "https://" + this->server_ip + ":" + this->server_port + uri; +#endif + + api_endpoint_t *api_ptr = (api_endpoint_t *)malloc(sizeof(api_endpoint_t)); + strncpy(api_ptr->uri, url.c_str(), sizeof(api_ptr->uri)); + strncpy(api_ptr->method, method, sizeof(api_ptr->method)); + strncpy(api_ptr->description, description, sizeof(api_ptr->description)); + + if (this->endpoint_head == NULL) + { + this->endpoint_head = api_ptr; + api_ptr->next = NULL; + return; + } + temp = this->endpoint_head; + while (temp->next != NULL) + { + temp = temp->next; + } + temp->next = api_ptr; + api_ptr->next = NULL; + return; + } + void API::not_found_handler() { - this->json_message_response("not found", 404); + uint16_t response_code = 404; + this->json_generic_response(this->construct_json_api(response_code), response_code); } void API::get_firewall_rule_handler() @@ -83,13 +124,9 @@ namespace fw int rule_number = atoi(param.c_str()); firewall_rule_t *rule_ptr = get_rule_from_firewall(rule_number); if (rule_ptr == NULL) - { - this->json_message_response("rule not found", 404); - } + this->json_message_response("rule does not exist", 404); else - { this->json_generic_response(construct_json_firewall_rule(rule_ptr), 200); - } } void API::get_firewall_rules_handler() @@ -105,25 +142,16 @@ namespace fw return; if (request_has_firewall_parameter()) { - firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); - rule_ptr->key = ++amount_of_rules; - - String source = this->server->arg("source"); - strncpy(rule_ptr->source, source.c_str(), sizeof(rule_ptr->source)); - String destination = this->server->arg("destination"); - strncpy(rule_ptr->destination, destination.c_str(), sizeof(rule_ptr->destination)); - - String protocol = this->server->arg("protocol"); - rule_ptr->protocol = string_to_protocol(protocol); - String target = this->server->arg("target"); - rule_ptr->target = string_to_target(target); - - add_rule_to_firewall(rule_ptr); + firewall_rule_t *rule_ptr = add_rule_to_firewall( + this->server->arg("source"), + this->server->arg("destination"), + this->server->arg("protocol"), + this->server->arg("target")); this->json_generic_response(this->construct_json_firewall_rule(rule_ptr), 200); } else { - this->json_message_response("not enough parameter", 400); + this->json_message_response("not enough parameter provided", 400); } } @@ -134,21 +162,15 @@ namespace fw String param = this->server->pathArg(0); int rule_number = atoi(param.c_str()); if (delete_rule_from_firewall(rule_number) == SUCCESS) - { this->json_message_response("firewall rule deleted", 200); - } else - { this->json_message_response("cannot delete firewall rule", 500); - } } bool API::request_has_firewall_parameter() { if (!this->server->args()) - { return false; - } else { return this->server->hasArg("source") || @@ -180,6 +202,7 @@ namespace fw void API::json_message_response(String message, const uint16_t response_code) { String serialized_string = "{"; + serialized_string += json_new_attribute("status", response_code_to_string(response_code)); serialized_string += json_new_attribute("message", message, true); serialized_string += "}"; this->server->send(response_code, "application/json; charset=utf-8", serialized_string); @@ -199,15 +222,43 @@ namespace fw String API::construct_json_firewall() { - firewall_rule_t *rule_ptr = head; + firewall_rule_t *rule_ptr = rule_head; String serialized_string = "{"; - serialized_string += json_new_attribute("amount_of_rules", amount_of_rules); + serialized_string += json_new_attribute("status", response_code_to_string(200)); serialized_string += "\"rules\": ["; while (rule_ptr != NULL) { serialized_string += construct_json_firewall_rule(rule_ptr); - serialized_string += ","; rule_ptr = rule_ptr->next; + if (rule_ptr != NULL) + serialized_string += ","; + } + serialized_string += "]}"; + return serialized_string; + } + + String API::construct_json_api_endpoint(api_endpoint_t *api_ptr) + { + String serialized_string = "{"; + serialized_string += json_new_attribute("endpoint", api_ptr->uri); + serialized_string += json_new_attribute("description", api_ptr->description); + serialized_string += json_new_attribute("method", api_ptr->method, true); + serialized_string += "}"; + return serialized_string; + } + + String API::construct_json_api(const uint16_t response_code) + { + api_endpoint_t *api_ptr = this->endpoint_head; + String serialized_string = "{"; + serialized_string += json_new_attribute("status", response_code_to_string(response_code)); + serialized_string += "\"endpoints\": ["; + while (api_ptr != NULL) + { + serialized_string += construct_json_api_endpoint(api_ptr); + api_ptr = api_ptr->next; + if (api_ptr != NULL) + serialized_string += ","; } serialized_string += "]}"; return serialized_string; diff --git a/ESPFirewall/lib/Firewall/src/API.hpp b/ESPFirewall/lib/Firewall/src/API.hpp index caf3394..28c934a 100644 --- a/ESPFirewall/lib/Firewall/src/API.hpp +++ b/ESPFirewall/lib/Firewall/src/API.hpp @@ -14,6 +14,14 @@ namespace fw { + typedef struct api_endpoints + { + char uri[40]; + char method[7]; + char description[30]; + struct api_endpoints *next; + } api_endpoint_t; + class API : public Rules { private: @@ -24,11 +32,13 @@ namespace fw BearSSL::ServerSessions *serverCache; #endif credential_t credentials; + api_endpoint_t *endpoint_head = NULL; - ok_t setup_auth(const char *, const char *); + ok_t setup_auth(const char *username, const char *password); auth_t check_auth(); - void setup_routing(const char *, const char *); + void setup_routing(const char *cert, const char *key); + void add_api_endpoint(const String uri, const char *method, const char *description); void get_firewall_rule_handler(); void get_firewall_rules_handler(); void post_firewall_handler(); @@ -42,12 +52,17 @@ namespace fw void json_message_response(String message, const uint16_t response_code); String construct_json_firewall_rule(firewall_rule_t *); String construct_json_firewall(); + String construct_json_api_endpoint(api_endpoint_t *); + String construct_json_api(const uint16_t response_code); + String construct_json_array(String message, String array_name); protected: + String server_ip; + uint16_t server_port; void handle_client(); public: - API(const char *cert, const char *key, const char *username, const char *password, const uint16_t port); + API(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port); ~API(); }; } diff --git a/ESPFirewall/lib/Firewall/src/Firewall.hpp b/ESPFirewall/lib/Firewall/src/Firewall.hpp index 7a4bbe6..bbd3b8f 100644 --- a/ESPFirewall/lib/Firewall/src/Firewall.hpp +++ b/ESPFirewall/lib/Firewall/src/Firewall.hpp @@ -9,13 +9,13 @@ namespace fw { private: public: - Firewall(const char *, const char *, const char *, const char *, const uint16_t = 8080); + Firewall(const char *, const char *, const char *, const char *, const String ip, const uint16_t = 8080); ~Firewall(); void handle_api_client(); }; - Firewall::Firewall(const char *cert, const char *key, const char *username, const char *password, const uint16_t port) - : API(cert, key, username, password, port) {} + Firewall::Firewall(const char *cert, const char *key, const char *username, const char *password, const String ip, const uint16_t port) + : API(cert, key, username, password, ip, port) {} Firewall::~Firewall() {} void Firewall::handle_api_client() { diff --git a/ESPFirewall/lib/Firewall/src/Rules.cpp b/ESPFirewall/lib/Firewall/src/Rules.cpp index c292d9c..e2f804e 100644 --- a/ESPFirewall/lib/Firewall/src/Rules.cpp +++ b/ESPFirewall/lib/Firewall/src/Rules.cpp @@ -23,26 +23,40 @@ namespace fw store_settings_value("amount_of_rules", this->amount_of_rules); store_firewall_rule(rule_ptr); firewall_rule_t *temp; - if (this->head == NULL) + if (this->rule_head == NULL) { - this->head = rule_ptr; + this->rule_head = rule_ptr; rule_ptr->next = NULL; return; } - temp = this->head; + temp = this->rule_head; while (temp->next != NULL) { temp = temp->next; } temp->next = rule_ptr; rule_ptr->next = NULL; - return; + } + + firewall_rule_t *Rules::add_rule_to_firewall(String source, String destination, String protocol, String target) + { + firewall_rule_t *rule_ptr = (firewall_rule_t *)malloc(sizeof(firewall_rule_t)); + rule_ptr->key = ++amount_of_rules; + + strncpy(rule_ptr->source, source.c_str(), sizeof(rule_ptr->source)); + strncpy(rule_ptr->destination, destination.c_str(), sizeof(rule_ptr->destination)); + + rule_ptr->protocol = string_to_protocol(protocol); + rule_ptr->target = string_to_target(target); + + add_rule_to_firewall(rule_ptr); + return rule_ptr; } firewall_rule_t *Rules::get_rule_from_firewall(uint8_t key) { - firewall_rule_t *rule_ptr = this->head; - if (this->head == NULL) + firewall_rule_t *rule_ptr = this->rule_head; + if (this->rule_head == NULL) { return NULL; } @@ -62,9 +76,9 @@ namespace fw ok_t Rules::delete_rule_from_firewall(uint8_t key) { - if (this->head == NULL) + if (this->rule_head == NULL) return NO_ACTION; - firewall_rule_t *current_rule_ptr = this->head; + firewall_rule_t *current_rule_ptr = this->rule_head; firewall_rule_t *previous_rule_ptr = NULL; firewall_rule_t *temp = NULL; while (current_rule_ptr->key != key) @@ -77,10 +91,10 @@ namespace fw current_rule_ptr = current_rule_ptr->next; } } - if (current_rule_ptr == this->head) + if (current_rule_ptr == this->rule_head) { - this->head = head->next; - temp = this->head; + this->rule_head = rule_head->next; + temp = this->rule_head; } else { @@ -96,7 +110,7 @@ namespace fw this->amount_of_rules--; store_settings_value("amount_of_rules", this->amount_of_rules); if (this->amount_of_rules != 0) - store_all_firewall_rules(head); + store_all_firewall_rules(rule_head); return SUCCESS; } } diff --git a/ESPFirewall/lib/Firewall/src/Rules.hpp b/ESPFirewall/lib/Firewall/src/Rules.hpp index 66ff854..1656573 100644 --- a/ESPFirewall/lib/Firewall/src/Rules.hpp +++ b/ESPFirewall/lib/Firewall/src/Rules.hpp @@ -10,9 +10,10 @@ namespace fw { protected: uint8_t amount_of_rules = 0; - firewall_rule_t *head = NULL; + firewall_rule_t *rule_head = NULL; void add_rule_to_firewall(firewall_rule_t *); + firewall_rule_t *add_rule_to_firewall(String source, String destination, String protocol, String target); firewall_rule_t *get_rule_from_firewall(uint8_t); ok_t delete_rule_from_firewall(uint8_t); diff --git a/ESPFirewall/lib/Firewall/src/Storage.cpp b/ESPFirewall/lib/Firewall/src/Storage.cpp index 71ac0d0..99fea25 100644 --- a/ESPFirewall/lib/Firewall/src/Storage.cpp +++ b/ESPFirewall/lib/Firewall/src/Storage.cpp @@ -132,10 +132,10 @@ namespace fw return rule_ptr; } - void Storage::store_all_firewall_rules(firewall_rule_t *head) + void Storage::store_all_firewall_rules(firewall_rule_t *rule_head) { #ifdef ESP32 - firewall_rule_t *temp = head; + firewall_rule_t *temp = rule_head; while (temp != NULL) { store_firewall_rule(temp); diff --git a/ESPFirewall/lib/Firewall/src/Utils.cpp b/ESPFirewall/lib/Firewall/src/Utils.cpp index e6a2f75..4eeeaac 100644 --- a/ESPFirewall/lib/Firewall/src/Utils.cpp +++ b/ESPFirewall/lib/Firewall/src/Utils.cpp @@ -48,6 +48,23 @@ namespace fw return TARGET_ACCEPT; } + String response_code_to_string(const uint16_t response_code) + { + switch (response_code) + { + case 200: + return "success"; + case 403: + return "unauthorized"; + case 404: + return "not found"; + case 500: + return "server error"; + default: + return "unknown error"; + } + } + void endless_loop() { Serial.printf("Something went wrong. Running endless loop until fixed..."); diff --git a/ESPFirewall/lib/Firewall/src/Utils.hpp b/ESPFirewall/lib/Firewall/src/Utils.hpp index 19c6fdc..c2e6d03 100644 --- a/ESPFirewall/lib/Firewall/src/Utils.hpp +++ b/ESPFirewall/lib/Firewall/src/Utils.hpp @@ -56,6 +56,7 @@ namespace fw firewall_protocol_t string_to_protocol(String &protocol); String target_to_string(firewall_target_t &target); firewall_target_t string_to_target(String &target); + String response_code_to_string(const uint16_t response_code); void endless_loop(); } diff --git a/ESPFirewall/src/main.cpp b/ESPFirewall/src/main.cpp index f387983..0d0d349 100644 --- a/ESPFirewall/src/main.cpp +++ b/ESPFirewall/src/main.cpp @@ -10,6 +10,7 @@ #include "Firewall.hpp" fw::Firewall *firewall; +String ip = "0.0.0.0"; void setup_wifi() { @@ -24,13 +25,14 @@ void setup_wifi() } Serial.println(); Serial.print("IP Address: "); - Serial.println(WiFi.localIP()); + ip = WiFi.localIP().toString(); + Serial.println(ip); } void setup() { setup_wifi(); - firewall = new fw::Firewall(cert, key, username, password, 8080); + firewall = new fw::Firewall(cert, key, username, password, ip, 8080); } void loop()