diff --git a/include/aclwebserver.h b/include/aclwebserver.h new file mode 100644 index 0000000..84a0da1 --- /dev/null +++ b/include/aclwebserver.h @@ -0,0 +1,168 @@ +#ifndef aclwebserver_h +#define aclwebserver_h + +#include "Arduino.h" +#include "stdlib_noniso.h" +#include "WiFi.h" +#include "AsyncTCP.h" +#include "Update.h" +#include "esp_int_wdt.h" +#include "esp_task_wdt.h" +#include "ESPAsyncWebServer.h" +#include "hardware.h" +#include +#include + + + +class ACLWebServerClass{ + + public: + + void begin(AsyncWebServer *server, const char* username = "", const char* password = ""){ + _server = server; + + if(strlen(username) > 0){ + _authRequired = true; + _username = username; + _password = password; + }else{ + _authRequired = false; + _username = ""; + _password = ""; + } + + _server->on("/users", HTTP_GET, [&](AsyncWebServerRequest *request){ + + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + // Create a JSON array to store the users + StaticJsonDocument<512> jsonDoc; + JsonArray usersArray = jsonDoc.to(); + + // Retrieve the ACL data using the getter function + const User* aclData = acl.getACL(); + + // Iterate over each user in the ACL and add it to the JSON array + for (int i = 0; i < acl.getACLSize(); i++) { + JsonObject user = usersArray.createNestedObject(); + user["cardId"] = aclData[i].cardId; + user["desc"] = aclData[i].desc; + } + + // Convert the JSON array to a string + String response; + serializeJson(usersArray, response); + + // Set the response content type to JSON + request->send(200, "application/json", response); + }); + + _server->on("/users/create", HTTP_POST, [&](AsyncWebServerRequest *request){ + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + + if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); + request->send(response); + } + + if(request->hasParam("desc", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}"); + request->send(response); + } + + String cardId = String(request->arg("cardId")); + String desc = String(request->arg("desc")); + + if (acl.validateAccess(String(cardId))) { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Duplicate ACL\"}"); + request->send(response); + } else { + acl.addUser(cardId, desc); + acl.saveToEEPROM(); + request->send(201); // Create + } + }); + + _server->on("/users/update", HTTP_POST, [&](AsyncWebServerRequest *request){ + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + + if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); + request->send(response); + } + + if(request->hasParam("newCardId", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "\"msg\":\"No newCardId\"}"); + request->send(response); + } + + if(request->hasParam("desc", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}"); + request->send(response); + } + String cardId = String(request->arg("cardId")); + String newCardId = String(request->arg("newCardId")); + String desc = String(request->arg("desc")); + acl.updateUser(cardId, newCardId, desc); + acl.saveToEEPROM(); + request->send(201); // Created + }); + + _server->on("/users/remove", HTTP_POST, [&](AsyncWebServerRequest *request){ + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + + if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); + request->send(response); + } + String cardId = String(request->arg("cardId")); + acl.removeUser(cardId); + acl.saveToEEPROM(); + request->send(201); // Created + }); + } + + // deprecated, keeping for backward compatibility + void loop() { + } + + private: + AsyncWebServer *_server; + String _username = ""; + String _password = ""; + bool _authRequired = false; + + static String outputState(int output){ + if(digitalRead(output)){ + return "checked"; + } + else { + return ""; + } + } +}; + +ACLWebServerClass ACLWebServer; +#endif diff --git a/include/hardware.h b/include/hardware.h index e9db3f5..d75f029 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -34,4 +34,5 @@ void lockDoor(); void toggleDoor(); String stateDoor(); + #endif diff --git a/include/main.h b/include/main.h index 792de14..ac78e03 100644 --- a/include/main.h +++ b/include/main.h @@ -6,12 +6,8 @@ #include "secrets.h" #include "settings.h" - #ifdef LOCAL_ACL - #include "ACL.h" - ACL acl = { - }; - #endif - + Settings settings; + #ifdef WIFI #include "WiFi.h" #endif @@ -30,7 +26,14 @@ #endif #include "mainwebserver.h" - + #ifdef LOCAL_ACL + #include "acl.h" + ACL acl = { + }; + #ifdef LOCAL_ACL_API + #include "aclwebserver.h" + #endif + #endif #endif #ifdef BUZZER diff --git a/include/mainwebserver.h b/include/mainwebserver.h index 2e4b91b..a1cfa21 100644 --- a/include/mainwebserver.h +++ b/include/mainwebserver.h @@ -11,6 +11,7 @@ #include "ESPAsyncWebServer.h" #include "SPIFFS.h" #include "hardware.h" +#include "settings.h" class MainWebServerClass{ @@ -40,9 +41,109 @@ class MainWebServerClass{ }); _server->onNotFound([&](AsyncWebServerRequest *request){ + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } request->send(200, "application/json", "{\"msg\":\"The content you are looking for was not found\"}"); }); + _server->on("/gpio", HTTP_GET, [&] (AsyncWebServerRequest *request) { + String paramOutput; + String paramState; + + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + + // GET input1 value on /gpio?output=&state= + if (request->hasParam("output") && request->hasParam("state")) { + paramOutput = request->getParam("output")->value(); + paramState = request->getParam("state")->value(); + + #ifdef RELAY1 + if (paramOutput == "relay1") { + if (paramState == String(0)){ + unlockDoor(false); + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Unlocked.\"}"); + request->send(response); + } + else if (paramState == String(1)) { + lockDoor(); + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Locked.\"}"); + request->send(response); + } + else { + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Incorect state provide 0 to unlock and 1 to lock.\"}"); + request->send(response); + } + } + + + #endif + + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Error with request, incorrect GPIO pin number.\"}"); + request->send(response); + + } + }); + + #ifdef RELAY1 + _server->on("/state/relay1", HTTP_GET, [&] (AsyncWebServerRequest *request) { + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"state\":\""+stateDoor()+"\"}"); + request->send(response); + }); + #endif + + _server->on("/settings/get/DoorDisabled", HTTP_GET, [&] (AsyncWebServerRequest *request) { + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"value\":\""+String(settings.DoorDisabled())+"\"}"); + request->send(response); + }); + + _server->on("/settings/set/DoorDisabled", HTTP_GET, [&] (AsyncWebServerRequest *request) { + String value; + + if(_authRequired){ + if(!request->authenticate(_username.c_str(), _password.c_str())){ + return request->requestAuthentication(); + } + } + + if (request->hasParam("value")) { + value = request->getParam("value")->value(); + if (value == "0") { + settings.setDisableDoor(0); + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 0\"}"); + request->send(response); + } + else if (value =="1") { + settings.setDisableDoor(1); + AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 1\"}"); + request->send(response); + + } else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"value should be 0 or 1\"}"); + request->send(response); + } + } + else { + AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Missing 'value' param.\"}"); + request->send(response); + } + }); } // deprecated, keeping for backward compatibility diff --git a/src/main.cpp b/src/main.cpp index 17385b1..2928bec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,6 @@ const unsigned long displayDelay = 1000; // Delay in milliseconds after which th const unsigned long wifiRebootTimeout = 20000; // Delay before reboot after disconnect unsigned int bitCount = 0; // Variable to keep track of the bit count unsigned int maxReaderWaitTime = 9000; // Variable to timeout reader after too long of no data. -Settings settings; AsyncWebServer server(80); #ifdef WIFI @@ -97,117 +96,6 @@ void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info){ #ifdef WEB_SERVER - -#ifdef LOCAL_ACL - #ifdef LOCAL_ACL_API - // Handler for the '/users' endpoint to list all users - void handleListUsers(AsyncWebServerRequest* request) { - - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - // Create a JSON array to store the users - StaticJsonDocument<512> jsonDoc; - JsonArray usersArray = jsonDoc.to(); - - // Retrieve the ACL data using the getter function - const User* aclData = acl.getACL(); - - // Iterate over each user in the ACL and add it to the JSON array - for (int i = 0; i < acl.getACLSize(); i++) { - JsonObject user = usersArray.createNestedObject(); - user["cardId"] = aclData[i].cardId; - user["desc"] = aclData[i].desc; - } - - // Convert the JSON array to a string - String response; - serializeJson(usersArray, response); - - // Set the response content type to JSON - request->send(200, "application/json", response); - } - - - - void handleCreateUser(AsyncWebServerRequest* request) { - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - - if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); - request->send(response); - } - - if(request->hasParam("desc", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}"); - request->send(response); - } - - String cardId = String(request->arg("cardId")); - String desc = String(request->arg("desc")); - - if (acl.validateAccess(String(cardId))) { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Duplicate ACL\"}"); - request->send(response); - } else { - acl.addUser(cardId, desc); - acl.saveToEEPROM(); - request->send(201); // Create - } - - } - - // Handler for the '/users/update' endpoint to remove a user - void handleUpdateUser(AsyncWebServerRequest* request) { - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - - if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); - request->send(response); - } - - if(request->hasParam("newCardId", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "\"msg\":\"No newCardId\"}"); - request->send(response); - } - - if(request->hasParam("desc", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No desc\"}"); - request->send(response); - } - String cardId = String(request->arg("cardId")); - String newCardId = String(request->arg("newCardId")); - String desc = String(request->arg("desc")); - acl.updateUser(cardId, newCardId, desc); - acl.saveToEEPROM(); - request->send(201); // Created - } - - // Handler for the '/users/remove' endpoint to remove a user - void handleRemoveUser(AsyncWebServerRequest* request) { - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - - if(request->hasParam("cardId", true)) {} //This is important, otherwise the sketch will crash if there is no body - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"No cardId\"}"); - request->send(response); - } - String cardId = String(request->arg("cardId")); - acl.removeUser(cardId); - acl.saveToEEPROM(); - request->send(201); // Created - } - #endif - #endif - - #endif void handleInterrupt(int bitValue) { @@ -247,7 +135,6 @@ void setup() { acl.loadFromEEPROM(); #endif - settings.loadFromEEPROM(); // Initialize SPIFFS @@ -303,117 +190,16 @@ void setup() { #ifdef BUZZER pinMode(ALARM_PIN, OUTPUT); - // Do not set to low or it will constantly beep. - digitalWrite(ALARM_PIN, HIGH); + digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep. #endif #ifdef WEB_SERVER - // Route for root / web page - - - #ifdef RELAY1 - server.on("/state/relay1", HTTP_GET, [] (AsyncWebServerRequest *request) { - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"state\":\""+stateDoor()+"\"}"); - request->send(response); - }); - #endif - - server.on("/settings/get/DoorDisabled", HTTP_GET, [] (AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"value\":\""+String(settings.DoorDisabled())+"\"}"); - request->send(response); - }); - - - - // Send a GET request to /gpio?output=&state= - server.on("/settings/set/DoorDisabled", HTTP_GET, [] (AsyncWebServerRequest *request) { - String value; - - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - - if (request->hasParam("value")) { - value = request->getParam("value")->value(); - if (value == "0") { - settings.setDisableDoor(0); - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 0\"}"); - request->send(response); - } - else if (value =="1") { - settings.setDisableDoor(1); - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"value set to 1\"}"); - request->send(response); - - } else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"value should be 0 or 1\"}"); - request->send(response); - } - } - else { - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Missing 'value' param.\"}"); - request->send(response); - } - - }); - - - - - - // Send a GET request to /gpio?output=&state= - server.on("/gpio", HTTP_GET, [] (AsyncWebServerRequest *request) { - String paramOutput; - String paramState; - - if(!request->authenticate(http_username, http_password)) - return request->requestAuthentication(); - - // GET input1 value on /gpio?output=&state= - if (request->hasParam("output") && request->hasParam("state")) { - paramOutput = request->getParam("output")->value(); - paramState = request->getParam("state")->value(); - - #ifdef RELAY1 - if (paramOutput == "relay1") { - if (paramState == String(0)){ - unlockDoor(false); - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Unlocked.\"}"); - request->send(response); - } - else if (paramState == String(1)) { - lockDoor(); - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Door Locked.\"}"); - request->send(response); - } - else { - AsyncWebServerResponse *response = request->beginResponse(200, "application/json", "{\"msg\":\"Incorect state provide 0 to unlock and 1 to lock.\"}"); - request->send(response); - } - } - - - #endif - - AsyncWebServerResponse *response = request->beginResponse(400, "application/json", "{\"msg\":\"Error with request, incorrect GPIO pin number.\"}"); - request->send(response); - - } - }); - MainWebServer.begin(&server, http_username, http_password); - - #ifdef LOCAL_ACL #ifdef LOCAL_ACL_API - server.on("/users", HTTP_GET, handleListUsers); - server.on("/users/create", HTTP_POST, handleCreateUser); - server.on("/users/update", HTTP_POST, handleUpdateUser); - server.on("/users/remove", HTTP_POST, handleRemoveUser); + ACLWebServer.begin(&server, http_username, http_password); #endif #endif - server.begin(); #endif