diff --git a/lib/PsychicHttp/src/PsychicRequest.cpp b/lib/PsychicHttp/src/PsychicRequest.cpp index e4272d0..9f0b921 100644 --- a/lib/PsychicHttp/src/PsychicRequest.cpp +++ b/lib/PsychicHttp/src/PsychicRequest.cpp @@ -303,7 +303,7 @@ String PsychicRequest::getCookie(const char* key) // how big is our cookie? size_t size; - if (!hasCookie("counter", &size)) + if (!hasCookie(key, &size)) return cookie; // allocate cookie buffer... keep it on the stack diff --git a/lib/nuki_ble b/lib/nuki_ble index a579d58..cf762e7 160000 --- a/lib/nuki_ble +++ b/lib/nuki_ble @@ -1 +1 @@ -Subproject commit a579d58a1c0d3d6119a780f4376b77046795cc16 +Subproject commit cf762e7dbd6ed501e9b719a7a4b9590ec85c7f99 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index c3091fa..50c7787 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -120,4 +120,5 @@ CONFIG_ESP_WIFI_IRAM_OPT=n CONFIG_ESP_WIFI_RX_IRAM_OPT=n CONFIG_MBEDTLS_DYNAMIC_BUFFER=y CONFIG_LWIP_DHCP_GET_NTP_SRV=y -CONFIG_LWIP_SNTP_UPDATE_DELAY=43200000 \ No newline at end of file +CONFIG_LWIP_SNTP_UPDATE_DELAY=43200000 +CONFIG_LWIP_SNTP_MAX_SERVERS=3 \ No newline at end of file diff --git a/src/Config.h b/src/Config.h index ec1e067..de392ab 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.08" #define NUKI_HUB_VERSION_INT (uint32_t)908 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2025-01-15" +#define NUKI_HUB_DATE "2025-01-17" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h index e99f3cb..1b0b60f 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -226,6 +226,7 @@ inline void initPreferences(Preferences* preferences) preferences->putInt(preference_query_interval_configuration, 3600); preferences->putInt(preference_query_interval_battery, 1800); preferences->putInt(preference_query_interval_keypad, 1800); + preferences->putInt(preference_http_auth_type, 0); preferences->putBool(preference_debug_connect, false); preferences->putBool(preference_debug_communication, false); @@ -233,7 +234,6 @@ inline void initPreferences(Preferences* preferences) preferences->putBool(preference_debug_hex_data, false); preferences->putBool(preference_debug_command, false); preferences->putBool(preference_connect_mode, true); - preferences->putBool(preference_http_auth_type, false); preferences->putBool(preference_retain_gpio, false); preferences->putBool(preference_enable_debug_mode, false); @@ -508,7 +508,7 @@ private: preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled, preference_retain_gpio, preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json, preference_update_from_mqtt, preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled, preference_hass_device_discovery, - preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_http_auth_type, + preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_debug_connect, preference_debug_communication, preference_debug_readable_data, preference_debug_hex_data, preference_debug_command, preference_connect_mode, preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_mqtt_ssl_enabled, preference_hybrid_reboot_on_disconnect, preference_lock_gemini_enabled, preference_enable_debug_mode @@ -528,7 +528,7 @@ private: preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries, preference_ble_tx_power, preference_network_custom_mdc, preference_network_custom_clk, preference_network_custom_phy, preference_network_custom_addr, preference_network_custom_irq, preference_network_custom_rst, preference_network_custom_cs, preference_network_custom_sck, preference_network_custom_miso, - preference_network_custom_mosi, preference_network_custom_pwr, preference_network_custom_mdio + preference_network_custom_mosi, preference_network_custom_pwr, preference_network_custom_mdio, preference_http_auth_type }; std::vector _uintPrefs = { diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 5423b94..924428f 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -56,8 +56,12 @@ WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool str = _preferences->getString(preference_cred_password, ""); const char *pass = str.c_str(); memcpy(&_credPassword, pass, str.length()); - } + if (_preferences->getInt(preference_http_auth_type, 0) == 2) + { + loadSessions(); + } + } _confirmCode = generateConfirmCode(); #ifndef NUKI_HUB_UPDATER @@ -76,41 +80,115 @@ WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool #endif } -void WebCfgServer::initialize() +bool WebCfgServer::isAuthenticated(PsychicRequest *request) { - _psychicServer->onOpen([&](PsychicClient* client) { Log->printf("[http] connection #%u connected from %s\n", client->socket(), client->localIP().toString().c_str()); }); - _psychicServer->onClose([&](PsychicClient* client) { Log->printf("[http] connection #%u closed from %s\n", client->socket(), client->localIP().toString().c_str()); }); + if (request->hasCookie("sessionId")) { + String cookie = request->getCookie("sessionId"); - HTTPAuthMethod auth_type = BASIC_AUTH; - if (_preferences->getBool(preference_http_auth_type, false)) + if (_httpSessions[cookie].is()) + { + struct timeval time; + gettimeofday(&time, NULL); + int64_t time_us = (int64_t)time.tv_sec * 1000000L + (int64_t)time.tv_usec; + + if (_httpSessions[cookie].as() > time_us) + { + return true; + } + else + { + Log->println("Cookie found, but not valid anymore"); + } + } + } + Log->println("Authentication Failed"); + return false; +} + +esp_err_t WebCfgServer::logoutSession(PsychicRequest *request, PsychicResponse* resp) +{ + Log->print("Logging out"); + resp->setCookie("sessionId", "", 0, "HttpOnly"); + + if (request->hasCookie("sessionId")) { + String cookie = request->getCookie("sessionId"); + _httpSessions.remove(cookie); + saveSessions(); + } + else { - auth_type = DIGEST_AUTH; + Log->print("No session cookie found"); } - _psychicServer->on("/", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp) - { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) - { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); - } + return buildConfirmHtml(request, resp, "Logging out", 3, true); +} -#ifndef CONFIG_IDF_TARGET_ESP32H2 - if(!_network->isApOpen()) - { -#endif -#ifndef NUKI_HUB_UPDATER - return buildHtml(request, resp); -#else - return buildOtaHtml(request, resp); -#endif -#ifndef CONFIG_IDF_TARGET_ESP32H2 +void WebCfgServer::saveSessions() +{ + if(_preferences->getBool(preference_update_time, false)) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/sessions.json", "w"); + serializeJson(_httpSessions, file); + file.close(); + } + } +} +void WebCfgServer::loadSessions() +{ + if(_preferences->getBool(preference_update_time, false)) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); } else { - return buildWifiConnectHtml(request, resp); + File file = SPIFFS.open("/sessions.json", "r"); + + if (!file || file.isDirectory()) { + Log->println("sessions.json not found"); + } + else + { + deserializeJson(_httpSessions, file); + } + file.close(); } -#endif - }); + } +} + +int WebCfgServer::doAuthentication(PsychicRequest *request) +{ + if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) + { + int savedAuthType = _preferences->getInt(preference_http_auth_type, 0); + if (savedAuthType == 2) + { + if (!isAuthenticated(request)) { + return savedAuthType; + } + } + else + { + if (!request->authenticate(_credUser, _credPassword)) + { + return savedAuthType; + } + } + } + + return 4; +} + +void WebCfgServer::initialize() +{ + //_psychicServer->onOpen([&](PsychicClient* client) { Log->printf("[http] connection #%u connected from %s\n", client->socket(), client->localIP().toString().c_str()); }); + //_psychicServer->onClose([&](PsychicClient* client) { Log->printf("[http] connection #%u closed from %s\n", client->socket(), client->localIP().toString().c_str()); }); + _psychicServer->on("/style.css", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp) { return sendCss(request, resp); @@ -129,9 +207,23 @@ void WebCfgServer::initialize() }); _psychicServer->on("/savewifi", HTTP_POST, [&](PsychicRequest *request, PsychicResponse* resp) { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) + int authReq = doAuthentication(request); + + switch (authReq) { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + case 4: + default: + break; } String message = ""; @@ -148,9 +240,23 @@ void WebCfgServer::initialize() }); _psychicServer->on("/reboot", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp) { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) + int authReq = doAuthentication(request); + + switch (authReq) { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + case 4: + default: + break; } String value = ""; @@ -169,6 +275,8 @@ void WebCfgServer::initialize() if(value != _confirmCode) { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); } esp_err_t res = buildConfirmHtml(request, resp, "Rebooting...", 2, true); @@ -191,16 +299,44 @@ void WebCfgServer::initialize() value = p->value(); } } - - if (value != "status") + int authReq = doAuthentication(request); + + if (value != "status" && value != "login" && value != "logout") { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) + switch (authReq) { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + case 4: + default: + break; } } + else if (value == "status" && authReq != 4) + { + resp->setCode(200); + resp->setContentType("application/json"); + resp->setContent("{}"); + return resp->send(); + } - if (value == "reboot") + if (value == "login") + { + return buildLoginHtml(request, resp); + } + else if (value == "logout") + { + return logoutSession(request, resp); + } + else if (value == "reboot") { String value = ""; if(request->hasParam("CONFIRMTOKEN")) @@ -218,6 +354,8 @@ void WebCfgServer::initialize() if(value != _confirmCode) { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); } esp_err_t res = buildConfirmHtml(request, resp, "Rebooting...", 2, true); @@ -250,18 +388,7 @@ void WebCfgServer::initialize() } else if (value == "status") { - if(request->hasParam("token")) - { - const PsychicWebParameter* p2 = request->getParam("token"); - if(p2->value().toInt() == _randomInt) - { - return buildStatusHtml(request, resp); - } - } - resp->setCode(200); - resp->setContentType("text/html"); - resp->setContent(""); - return resp->send(); + return buildStatusHtml(request, resp); } else if (value == "acclvl") { @@ -337,6 +464,8 @@ void WebCfgServer::initialize() } if(value != _confirmCode) { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); } if(!_allowRestartToPortal) @@ -376,6 +505,8 @@ void WebCfgServer::initialize() if(value != _confirmCode) { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); } esp_err_t res = buildConfirmHtml(request, resp, "Rebooting to other partition...", 2, true); @@ -389,36 +520,21 @@ void WebCfgServer::initialize() #ifndef NUKI_HUB_UPDATER return processUpdate(request, resp); #else + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); return resp->redirect("/"); #endif } else { - #ifndef CONFIG_IDF_TARGET_ESP32H2 - if(!_network->isApOpen()) - { - #endif - #ifndef NUKI_HUB_UPDATER - return buildHtml(request, resp); - #else - return buildOtaHtml(request, resp); - #endif - #ifndef CONFIG_IDF_TARGET_ESP32H2 - } - else - { - return buildWifiConnectHtml(request, resp); - } - #endif + Log->println("Page not found, loading index"); + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/"); } }); _psychicServer->on("/post", HTTP_POST, [&](PsychicRequest *request, PsychicResponse* resp) { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) - { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); - } - String value = ""; if(request->hasParam("page")) { @@ -429,8 +545,46 @@ void WebCfgServer::initialize() } } + if (value != "login") + { + int authReq = doAuthentication(request); + + switch (authReq) + { + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + case 4: + default: + break; + } + } + + if (value == "login") + { + bool loggedIn = processLogin(request, resp); + if (loggedIn) + { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/"); + } + else + { + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + } + } #ifndef NUKI_HUB_UPDATER - if (value == "savecfg") + else if (value == "savecfg") { String message = ""; bool restart = processArgs(request, resp, message); @@ -474,10 +628,8 @@ void WebCfgServer::initialize() bool restart = processImport(request, resp, message); return buildConfirmHtml(request, resp, message, 3, true); } - else - #else - if (1 == 1) #endif + else { #ifndef CONFIG_IDF_TARGET_ESP32H2 if(!_network->isApOpen()) @@ -501,19 +653,44 @@ void WebCfgServer::initialize() PsychicUploadHandler *updateHandler = new PsychicUploadHandler(); updateHandler->onUpload([&](PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool last) { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) - { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); - } + int authReq = doAuthentication(request); + switch (authReq) + { + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + return ESP_FAIL; + case 4: + default: + break; + } return handleOtaUpload(request, filename, index, data, len, last); }); updateHandler->onRequest([&](PsychicRequest* request, PsychicResponse* resp) { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0 && !request->authenticate(_credUser, _credPassword)) + int authReq = doAuthentication(request); + + switch (authReq) { - return request->requestAuthentication(auth_type, "Nuki Hub", "You must log in."); + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + case 4: + default: + break; } String result; @@ -546,6 +723,47 @@ void WebCfgServer::initialize() _psychicServer->on("/uploadota", HTTP_POST, updateHandler); //Update.onProgress(printProgress); } + + _psychicServer->on("/", HTTP_GET, [&](PsychicRequest *request, PsychicResponse* resp) + { + int authReq = doAuthentication(request); + + switch (authReq) + { + case 0: + return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + break; + case 1: + return request->requestAuthentication(DIGEST_AUTH, "Nuki Hub", "You must log in."); + break; + case 2: + resp->setCode(302); + resp->addHeader("Cache-Control", "no-cache"); + return resp->redirect("/get?page=login"); + break; + case 4: + default: + break; + } + +#ifndef CONFIG_IDF_TARGET_ESP32H2 + if(!_network->isApOpen()) + { +#endif +#ifndef NUKI_HUB_UPDATER + return buildHtml(request, resp); +#else + return buildOtaHtml(request, resp); +#endif +#ifndef CONFIG_IDF_TARGET_ESP32H2 + } + else + { + return buildWifiConnectHtml(request, resp); + } +#endif + }); + } void WebCfgServer::printCheckBox(PsychicStreamResponse *response, const char *token, const char *description, const bool value, const char *htmlClass) @@ -1266,6 +1484,54 @@ void WebCfgServer::printInputField(PsychicStreamResponse *response, printInputField(response, token, description, valueStr, maxLength, args); } +esp_err_t WebCfgServer::buildLoginHtml(PsychicRequest *request, PsychicResponse* resp) +{ + PsychicStreamResponse response(resp, "text/html"); + response.beginSend(); + response.print(""); + response.print(""); + response.print(""); + response.print("

NukiHub login

"); + response.print("
"); + response.print(""); + response.print("
"); + response.print("
"); + return response.endSend(); +} + +bool WebCfgServer::processLogin(PsychicRequest *request, PsychicResponse* resp) +{ + if(request->hasParam("username") && request->hasParam("password")) + { + const PsychicWebParameter* user = request->getParam("username"); + const PsychicWebParameter* pass = request->getParam("password"); + if(user->value() != "" && pass->value() != "") + { + if (user->value() == _preferences->getString(preference_cred_user, "") && pass->value() == _preferences->getString(preference_cred_password, "")) + { + char buffer[33]; + int i; + int64_t durationLength = 60*60*24*30; + for (i = 0; i < 4; i++) { + sprintf(buffer + (i * 8), "%08lx", (unsigned long int)esp_random()); + } + if(!request->hasParam("remember")) { + durationLength = 60*60; + } + resp->setCookie("sessionId", buffer, durationLength, "HttpOnly"); + + struct timeval time; + gettimeofday(&time, NULL); + int64_t time_us = (int64_t)time.tv_sec * 1000000L + (int64_t)time.tv_usec; + _httpSessions[buffer] = time_us + (durationLength*1000000L); + saveSessions(); + return true; + } + } + } + return false; +} + #ifndef NUKI_HUB_UPDATER esp_err_t WebCfgServer::sendSettings(PsychicRequest *request, PsychicResponse* resp) { @@ -2788,9 +3054,9 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } else if(key == "CREDDIGEST") { - if(_preferences->getBool(preference_http_auth_type, false) != (value == "1")) + if(_preferences->getInt(preference_http_auth_type, 0) != value.toInt()) { - _preferences->putBool(preference_http_auth_type, (value == "1")); + _preferences->putInt(preference_http_auth_type, value.toInt()); Log->print(("Setting changed: ")); Log->println(key); configChanged = true; @@ -3914,8 +4180,7 @@ esp_err_t WebCfgServer::buildCustomNetworkConfigHtml(PsychicRequest *request, Ps esp_err_t WebCfgServer::buildHtml(PsychicRequest *request, PsychicResponse* resp) { - _randomInt = esp_random(); - String header = (String)""; + String header = (String)""; PsychicStreamResponse response(resp, "text/html"); response.beginSend(); buildHtmlHeader(&response, header); @@ -4008,6 +4273,10 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request, PsychicResponse* resp #endif String rebooturl = "/get?page=reboot&CONFIRMTOKEN=" + _confirmCode; buildNavigationMenuEntry(&response, "Reboot Nuki Hub", rebooturl.c_str()); + if (_preferences->getInt(preference_http_auth_type, 0) == 2) + { + buildNavigationMenuEntry(&response, "Logout", "/get?page=logout"); + } response.print(""); return response.endSend(); } @@ -4024,7 +4293,13 @@ esp_err_t WebCfgServer::buildCredHtml(PsychicRequest *request, PsychicResponse* printInputField(&response, "CREDUSER", "User (# to clear)", _preferences->getString(preference_cred_user).c_str(), 30, "id=\"inputuser\"", false, true); printInputField(&response, "CREDPASS", "Password", "*", 30, "id=\"inputpass\"", true, true); printInputField(&response, "CREDPASSRE", "Retype password", "*", 30, "id=\"inputpass2\"", true); - printCheckBox(&response, "CREDDIGEST", "Use Digest Authentication (more secure)", _preferences->getBool(preference_http_auth_type, false), ""); + + std::vector> httpAuthOptions; + httpAuthOptions.push_back(std::make_pair("0", "Basic")); + httpAuthOptions.push_back(std::make_pair("1", "Digest")); + httpAuthOptions.push_back(std::make_pair("2", "Form")); + + printDropDown(&response, "CREDDIGEST", "HTTP Authentication type", String(_preferences->getInt(preference_http_auth_type, 0)), httpAuthOptions, ""); response.print(""); response.print("
"); response.print(""); @@ -4964,7 +5239,7 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse* response.print("\nWeb configurator password: "); response.print(_preferences->getString(preference_cred_password, "").length() > 0 ? "***" : "Not set"); response.print("\nWeb configurator authentication: "); - response.print(_preferences->getBool(preference_http_auth_type, false) ? "Digest" : "Basic"); + response.print(_preferences->getInt(preference_http_auth_type, 0) == 0 ? "Basic" : _preferences->getInt(preference_http_auth_type, 0) == 1 ? "Digest" : "Form"); response.print("\nWeb configurator enabled: "); response.print(_preferences->getBool(preference_webserver_enabled, true) ? "Yes" : "No"); response.print("\nHTTP SSL: "); diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h index 67ed731..a5c6a1d 100644 --- a/src/WebCfgServer.h +++ b/src/WebCfgServer.h @@ -100,7 +100,14 @@ private: std::vector _rssiList; String generateConfirmCode(); String _confirmCode = "----"; - + + void saveSessions(); + void loadSessions(); + esp_err_t logoutSession(PsychicRequest *request, PsychicResponse* resp); + bool isAuthenticated(PsychicRequest *request); + bool processLogin(PsychicRequest *request, PsychicResponse* resp); + int doAuthentication(PsychicRequest *request); + esp_err_t buildLoginHtml(PsychicRequest *request, PsychicResponse* resp); esp_err_t buildSSIDListHtml(PsychicRequest *request, PsychicResponse* resp); esp_err_t buildConfirmHtml(PsychicRequest *request, PsychicResponse* resp, const String &message, uint32_t redirectDelay = 5, bool redirect = false, String redirectTo = "/"); esp_err_t buildOtaHtml(PsychicRequest *request, PsychicResponse* resp, bool debug = false); @@ -128,6 +135,6 @@ private: bool _allowRestartToPortal = false; uint8_t _partitionType = 0; size_t _otaContentLen = 0; - uint32_t _randomInt = 0; String _hostname; + JsonDocument _httpSessions; }; diff --git a/src/main.cpp b/src/main.cpp index 4509efa..ea05698 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,10 @@ #include "esp32-hal-log.h" #include "hal/wdt_hal.h" #include "esp_chip_info.h" +#include +#include +#include "esp_netif.h" +#include "esp_netif_sntp.h" #ifdef CONFIG_SOC_SPIRAM_SUPPORTED #include "esp_psram.h" #include "FS.h" @@ -29,7 +33,6 @@ #include "RestartReason.h" #include "EspMillis.h" #include "NimBLEDevice.h" -#include "esp_netif_sntp.h" /* #ifdef DEBUG_NUKIHUB @@ -38,8 +41,6 @@ #endif */ -char log_print_buffer[1024]; - NukiNetworkLock* networkLock = nullptr; NukiNetworkOpener* networkOpener = nullptr; BleScanner::Scanner* bleScanner = nullptr; @@ -71,6 +72,8 @@ int64_t restartTs = 10 * 60 * 1000; #endif +char log_print_buffer[1024]; + PsychicHttpServer* psychicServer = nullptr; PsychicHttpsServer* psychicSSLServer = nullptr; NukiNetwork* network = nullptr; @@ -97,7 +100,6 @@ RestartReason currentRestartReason = RestartReason::NotApplicable; TaskHandle_t otaTaskHandle = nullptr; TaskHandle_t networkTaskHandle = nullptr; -#ifndef NUKI_HUB_UPDATER ssize_t write_fn(void* cookie, const char* buf, ssize_t size) { Log->write((uint8_t *)buf, (size_t)size); @@ -157,7 +159,6 @@ void setReroute() } } -#endif uint8_t checkPartition() { @@ -181,6 +182,10 @@ uint8_t checkPartition() } } +void cbSyncTime(struct timeval *tv) { + Log->println("NTP time synched"); +} + void networkTask(void *pvParameters) { int64_t networkLoopTs = 0; @@ -204,13 +209,15 @@ void networkTask(void *pvParameters) network->update(); bool connected = network->isConnected(); - #ifndef NUKI_HUB_UPDATER if(connected && reroute) { + if(preferences->getBool(preference_update_time, false)) + { + esp_netif_sntp_start(); + } reroute = false; setReroute(); } - #endif #ifndef NUKI_HUB_UPDATER wifiConnected = network->wifiConnected(); @@ -503,10 +510,6 @@ void setupTasks(bool ota) } } -void cbSyncTime(struct timeval *tv) { - Log->println(("NTP time synched")); -} - void setup() { //Set Log level to error for all TAGS @@ -822,16 +825,14 @@ void setup() } #endif */ - } - if(preferences->getBool(preference_update_time, false)) - { - esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(preferences->getString(preference_time_server, "pool.ntp.org").c_str()); + String timeserver = preferences->getString(preference_time_server, "pool.ntp.org"); + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeserver.c_str()); config.start = false; config.server_from_dhcp = true; config.renew_servers_after_new_IP = true; config.index_of_first_server = 1; - + if (network->networkDeviceType() == NetworkDeviceType::WiFi) { config.ip_event_to_renew = IP_EVENT_STA_GOT_IP;