#include "WebConsole.h" using namespace webconsole; WebConsole::WebConsole() { } WebConsole::~WebConsole() { _server->close(); delete (_server); } bool WebConsole::init(userdb::UserDb *userdb) { _server = new ESP8266WebServer(80); this->userdb = userdb; const char *headerkeys[] = {"Authentification"}; size_t headerkeyssize = sizeof(headerkeys) / sizeof(char *); _server->collectHeaders(headerkeys, headerkeyssize); _server->begin(); _server->on("/api/auth", HTTPMethod::HTTP_POST, std::bind(&WebConsole::_auth, this)); _server->on("/api/userdb", HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_dropUserDb, this)); _server->on("/api/userdb", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUserDb, this)); _server->on("/api/rfid", HTTPMethod::HTTP_GET, std::bind(&WebConsole::_catchRFID, this)); _server->on("/api/debug/printfile", std::bind(&WebConsole::_print_db_raw, this)); _server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_DELETE, std::bind(&WebConsole::_deleteUser, this)); _server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_GET, std::bind(&WebConsole::_getUser, this)); _server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_PUT, std::bind(&WebConsole::_createUser, this)); _server->on(UriBraces("/api/user/{}"), HTTPMethod::HTTP_POST, std::bind(&WebConsole::_updateUser, this)); _server->on(UriBraces("/api/config/{}"), std::bind(&WebConsole::_deleteUser, this)); //_server->on("/bypin",std::bind(&WebConsole::_findPin,this)); _server->serveStatic("/", LittleFS, "/s/"); _server->onNotFound(std::bind(&WebConsole::_handleUnknown, this)); return true; } void WebConsole::attachRfid(Rfid *rfid) { this->rfid = rfid; } void WebConsole::serve() { if (catch_rfid) { if (millis() - catch_rfid_millis > 2000){ catch_rfid = 0; } else if (catch_rfid > 1 && rfid != nullptr && rfid->available()) { rfid_buffer = rfid->getID(); catch_rfid = 1; } } _server->handleClient(); } uint8_t WebConsole::isInterceptingRfid() { if(catch_rfid==3){ catch_rfid=2; return 3; } return catch_rfid; } bool WebConsole::_isAuth() { if (!_server->hasHeader("Authentification")) { _server->send(401, "text/plain", "Error 401: Unauthorized (missing auth token)"); return false; } const char *token = _server->header("Authentification").c_str(); bool res = auth.isAuth(token); if (!res) _server->send(401, "text/plain", "Error 401: Unauthorized (missing auth token)"); return res; } void WebConsole::_auth() { _sendCORS(); String action = _server->arg("action"); if (action.equals("check")) { const char *token = _server->arg("token").c_str(); bool res = auth.isAuth(token); _server->send(200, "text/plain", res ? "valid" : "invalid"); } else if (action.equals("login")) { char *token = auth.login(_server->arg("username"), _server->arg("password")); if (token == nullptr) _server->send(401, "text/plain", "login_failed"); else _server->send(200, "text/plain", token); } else if (action.equals("logout")) { const char *token = _server->arg("token").c_str(); bool res = auth.logout(token); _server->send(200, "text/plain", res ? "success" : "failed"); } else if (action.equals("update")) { // if (!_isAuth()) // return; bool res = auth.setAuth(_server->arg("username"), _server->arg("password")); _server->send(200, "text/plain", res ? "success" : "failed"); } else _server->send(404, "text/plain", "unknown action"); } void WebConsole::_sendCORS() { _server->sendHeader("Access-Control-Allow-Origin", "*"); _server->sendHeader("Access-Control-Max-Age", "10000"); _server->sendHeader("Access-Control-Allow-Methods", "PUT,POST,GET,OPTIONS,DELETE"); _server->sendHeader("Access-Control-Allow-Headers", "*"); } void WebConsole::_handleUnknown() { _sendCORS(); if (_server->method() == HTTP_OPTIONS) { _server->send(204); } else { File src = LittleFS.open("s/index.html", "r"); _server->streamFile(src, "text/html"); src.close(); } } void WebConsole::_getUserDb() { _sendCORS(); if (!_isAuth()) return; File src = LittleFS.open("userdb.csv", "r"); if (src) { _server->streamFile(src, "text/csv"); } src.close(); } void WebConsole::_deleteUser() { _sendCORS(); if (!_isAuth()) return; if (userdb == nullptr) { _server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}"); return; } String uid = _server->pathArg(0); userdb::User del = userdb->user_by_uid(uid); if (del.match == true) { userdb->remove_user(del); _server->send(200, "text/plain", del.toJSONString()); } else { _server->send(500, "text/json", "{\"error\":\"User not found.\"}"); } } void WebConsole::_getUser() { _sendCORS(); if (!_isAuth()) return; if (userdb == nullptr) { _server->send(500, "text/json", "{\"error\":\"UserDb not initialized\"}"); return; } String uid = _server->pathArg(0); userdb::User res = userdb->user_by_uid(uid); if (res.match == true) { _server->send(200, "text/json", res.toJSONString()); } else { _server->send(500, "text/json", "{\"error\":\"User not found.\"}"); } } void WebConsole::_updateUser() { _sendCORS(); if (!_isAuth()) return; userdb::User updated; String body = _server->arg("plain"); const int capacity = 256; StaticJsonDocument doc; DeserializationError err = deserializeJson(doc, body); if (err.code() != err.Ok) { Serial.println(err.c_str()); Serial.println(body); String response = "{\"error\":\""; response += err.c_str(); response += "\"}"; _server->send(500, "text/json", response); return; } if (doc.containsKey("line")) { updated = userdb->user_by_line(doc["line"].as()); } if (!updated.match && doc.containsKey("uid")) { updated = userdb->user_by_uid(doc["uid"].as()); } if (!updated.match && !_server->pathArg(0).isEmpty()) { updated = userdb->user_by_uid(_server->pathArg(0).toInt()); } if (updated.match == false) { _server->send(500, "text/json", "{\"error\":\"user could not be found.\"}"); return; } // created.line = doc["line"].as(); if (doc.containsKey("uid")) updated.uid = doc["uid"].as(); if (doc.containsKey("first_name")) updated.first_name = doc["first_name"].as(); if (doc.containsKey("last_name")) updated.last_name = doc["last_name"].as(); if (doc.containsKey("rfid_uid")) updated.rfid_uid = doc["rfid_uid"].as(); if (doc.containsKey("user_pin")) updated.user_pin = doc["user_pin"].as(); if (doc.containsKey("enabled")) updated.enabled = doc["enabled"].as(); userdb->update_user(&updated); _server->send(200, "text/json", updated.toJSONString().c_str()); } void WebConsole::_createUser() { _sendCORS(); if (!_isAuth()) return; userdb::User created; String body = _server->arg("plain"); const int capacity = 1024; StaticJsonDocument doc; DeserializationError err = deserializeJson(doc, body); if (err.code() != err.Ok) { Serial.println(err.c_str()); Serial.println(body); String response = "{\"error\":\""; response += err.c_str(); response += "\"}"; _server->send(500, "text/json", response); return; } if (!_server->pathArg(0).isEmpty()) created.uid = _server->pathArg(0).toInt(); else if (!doc["uid"].isNull()) created.uid = doc["uid"].as(); else { _server->send(500, "text/json", "{\"error\":\"UserId not provided.\"}"); return; } created.first_name = doc["first_name"].as(); created.last_name = doc["last_name"].as(); created.rfid_uid = doc["rfid_uid"].as(); created.user_pin = doc["user_pin"].as(); created.enabled = doc["enabled"].as(); userdb->add_user(created); _server->send(200, "text/json", created.toJSONString()); } void WebConsole::_dropUserDb() { _sendCORS(); if (!_isAuth()) return; if (userdb->drop()) _server->send(500, "text/json", "{\"ok\":\"UserDb dropped.\"}"); else _server->send(500, "text/json", "{\"error\":\"UserDb could not be dropped.\"}"); } void WebConsole::_catchRFID() { _sendCORS(); if (!_isAuth()) return; if (rfid == nullptr) { _server->send(500, "text/json", "{\"error\":\"RFID not attached.\",\"state\":\"" + String(catch_rfid) + "\"}"); return; } if (catch_rfid == 1) { String response = "{\"rfid_uid\":\"" + rfid_buffer + "\",\"state\":\"" + String(catch_rfid) + "\"}"; _server->send(200, "text/json", response); catch_rfid = 0; } else { catch_rfid = 3; // 3 - Start listening catch_rfid_millis = millis(); _server->send(200, "text/json", "{\"ok\":\"listening\",\"state\":\"" + String(catch_rfid) + "\"}"); } } void WebConsole::_updateAdmin() { }