| Current bootloop prevention state | ");
response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
@@ -5233,14 +6003,39 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
response.print(_preferences->getString(preference_latest_version, ""));
response.print("\nAllow update from MQTT: ");
response.print(_preferences->getBool(preference_update_from_mqtt, false) ? "Yes" : "No");
- response.print("\nUpdate NukiHub and Nuki devices time using NTP: ");
+ response.print("\nUpdate Nuki Hub and Nuki devices time using NTP: ");
response.print(_preferences->getBool(preference_update_time, false) ? "Yes" : "No");
response.print("\nWeb configurator username: ");
response.print(_preferences->getString(preference_cred_user, "").length() > 0 ? "***" : "Not set");
response.print("\nWeb configurator password: ");
response.print(_preferences->getString(preference_cred_password, "").length() > 0 ? "***" : "Not set");
+ response.print("\nWeb configurator bypass for proxy IP: ");
+ response.print(_preferences->getString(preference_bypass_proxy, "").length() > 0 ? "***" : "Not set");
response.print("\nWeb configurator authentication: ");
response.print(_preferences->getInt(preference_http_auth_type, 0) == 0 ? "Basic" : _preferences->getInt(preference_http_auth_type, 0) == 1 ? "Digest" : "Form");
+ response.print("\nSession validity (in seconds): ");
+ response.print(_preferences->getInt(preference_cred_session_lifetime, 3600));
+ response.print("\nSession validity remember (in hours): ");
+ response.print(_preferences->getInt(preference_cred_session_lifetime_remember, 720));
+ response.print("\nDuo Push MFA enabled: ");
+ response.print(_preferences->getBool(preference_cred_duo_enabled, false) ? "Yes" : "No");
+
+ if (_preferences->getBool(preference_cred_duo_enabled, false))
+ {
+ response.print("\nDuo Host: ");
+ response.print(_preferences->getString(preference_cred_duo_host, "").length() > 0 ? "***" : "Not set");
+ response.print("\nDuo IKey: ");
+ response.print(_preferences->getString(preference_cred_duo_ikey, "").length() > 0 ? "***" : "Not set");
+ response.print("\nDuo SKey: ");
+ response.print(_preferences->getString(preference_cred_duo_skey, "").length() > 0 ? "***" : "Not set");
+ response.print("\nDuo User: ");
+ response.print(_preferences->getString(preference_cred_duo_user, "").length() > 0 ? "***" : "Not set");
+ response.print("\nDuo Session validity (in seconds): ");
+ response.print(_preferences->getInt(preference_cred_session_lifetime_duo, 3600));
+ response.print("\nDuo Session validity remember (in hours): ");
+ response.print(_preferences->getInt(preference_cred_session_lifetime_duo_remember, 720));
+ }
+
response.print("\nWeb configurator enabled: ");
response.print(_preferences->getBool(preference_webserver_enabled, true) ? "Yes" : "No");
response.print("\nHTTP SSL: ");
@@ -5257,6 +6052,8 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse*
response.print((!file || file.isDirectory() || !file2 || file2.isDirectory()) ? "Disabled" : "Enabled");
file.close();
file2.close();
+ response.print("\nNuki Hub FQDN for HTTP redirect: ");
+ response.print(_preferences->getString(preference_https_fqdn, "").length() > 0 ? "***" : "Not set");
}
}
else
diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h
index a5c6a1d..d93ce78 100644
--- a/src/WebCfgServer.h
+++ b/src/WebCfgServer.h
@@ -100,14 +100,21 @@ private:
std::vector _rssiList;
String generateConfirmCode();
String _confirmCode = "----";
-
- void saveSessions();
- void loadSessions();
+
+ int checkDuoAuth(PsychicRequest *request);
+ int checkDuoApprove();
+ bool startDuoAuth(char* pushType = (char*)"");
+ void saveSessions(bool duo = false);
+ void loadSessions(bool duo = false);
+ void clearSessions();
esp_err_t logoutSession(PsychicRequest *request, PsychicResponse* resp);
- bool isAuthenticated(PsychicRequest *request);
+ bool isAuthenticated(PsychicRequest *request, bool duo = false);
bool processLogin(PsychicRequest *request, PsychicResponse* resp);
int doAuthentication(PsychicRequest *request);
- esp_err_t buildLoginHtml(PsychicRequest *request, PsychicResponse* resp);
+ esp_err_t buildCoredumpHtml(PsychicRequest *request, PsychicResponse* resp);
+ esp_err_t buildLoginHtml(PsychicRequest *request, PsychicResponse* resp);
+ esp_err_t buildDuoHtml(PsychicRequest *request, PsychicResponse* resp);
+ esp_err_t buildDuoCheckHtml(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);
@@ -133,8 +140,25 @@ private:
char _credUser[31] = {0};
char _credPassword[31] = {0};
bool _allowRestartToPortal = false;
+ bool _isSSL = false;
uint8_t _partitionType = 0;
size_t _otaContentLen = 0;
String _hostname;
JsonDocument _httpSessions;
+ JsonDocument _duoSessions;
+ JsonDocument _sessionsOpts;
+ struct tm timeinfo;
+ bool _duoActiveRequest;
+ bool _duoEnabled = false;
+ bool _bypassGPIO = false;
+ int _bypassGPIOHigh = -1;
+ int _bypassGPIOLow = -1;
+ int64_t _duoRequestTS = 0;
+ String _duoTransactionId;
+ String _duoHost;
+ String _duoSkey;
+ String _duoIkey;
+ String _duoUser;
+ String _duoCheckId;
+ String _duoCheckIP;
};
diff --git a/src/main.cpp b/src/main.cpp
index dde42f7..9da9be3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,10 +11,11 @@
#include "hal/wdt_hal.h"
#include "esp_chip_info.h"
#include "esp_netif_sntp.h"
-#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
-#include "esp_psram.h"
+#include "esp_core_dump.h"
#include "FS.h"
#include "SPIFFS.h"
+#ifdef CONFIG_SOC_SPIRAM_SUPPORTED
+#include "esp_psram.h"
#endif
#ifndef NUKI_HUB_UPDATER
@@ -88,6 +89,8 @@ RTC_NOINIT_ATTR bool forceEnableWebServer;
RTC_NOINIT_ATTR bool disableNetwork;
RTC_NOINIT_ATTR bool wifiFallback;
RTC_NOINIT_ATTR bool ethCriticalFailure;
+bool coredumpPrinted = true;
+bool timeSynced = false;
int lastHTTPeventId = -1;
bool doOta = false;
@@ -180,7 +183,8 @@ uint8_t checkPartition()
}
void cbSyncTime(struct timeval *tv) {
- Log->println("NTP time synched");
+ Log->println("NTP time synced");
+ timeSynced = true;
}
void networkTask(void *pvParameters)
@@ -507,6 +511,93 @@ void setupTasks(bool ota)
}
}
+void logCoreDump()
+{
+ coredumpPrinted = false;
+ delay(500);
+ Serial.println("Printing coredump and saving to coredump.hex on SPIFFS");
+ size_t size = 0;
+ size_t address = 0;
+ if (esp_core_dump_image_get(&address, &size) == ESP_OK)
+ {
+ const esp_partition_t *pt = NULL;
+ pt = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, "coredump");
+
+ if (pt != NULL)
+ {
+ uint8_t bf[256];
+ char str_dst[640];
+ int16_t toRead;
+
+ if (!SPIFFS.begin(true))
+ {
+ Log->println("SPIFFS Mount Failed");
+ }
+
+ File file = SPIFFS.open("/coredump.hex", FILE_WRITE);
+ if (!file) {
+ Log->println("Failed to open /coredump.hex for writing");
+ }
+ else
+ {
+ file.printf("%s\r\n", NUKI_HUB_HW);
+ file.printf("%s\r\n", NUKI_HUB_BUILD);
+ }
+
+ Serial.printf("%s\r\n", NUKI_HUB_HW);
+ Serial.printf("%s\r\n", NUKI_HUB_BUILD);
+
+ for (int16_t i = 0; i < (size/256)+1; i++)
+ {
+ strcpy(str_dst, "");
+ toRead = (size - i*256) > 256 ? 256 : (size - i*256);
+
+ esp_err_t er = esp_partition_read(pt, i*256, bf, toRead);
+ if (er != ESP_OK)
+ {
+ Serial.printf("FAIL [%x]", er);
+ break;
+ }
+
+ for (int16_t j = 0; j < 256; j++)
+ {
+ char str_tmp[2];
+ if (bf[j] <= 0x0F)
+ {
+ sprintf(str_tmp, "0%x", bf[j]);
+ }
+ else
+ {
+ sprintf(str_tmp, "%x", bf[j]);
+ }
+ strcat(str_dst, str_tmp);
+ }
+ Serial.printf("%s", str_dst);
+
+ if (file) {
+ file.printf("%s", str_dst);
+ }
+ }
+
+ Serial.println("");
+
+ if (file) {
+ file.println("");
+ file.close();
+ }
+ }
+ else
+ {
+ Serial.println("Partition NULL");
+ }
+ }
+ else
+ {
+ Serial.println("esp_core_dump_image_get() FAIL");
+ }
+ coredumpPrinted = true;
+}
+
void setup()
{
//Set Log level to error for all TAGS
@@ -529,10 +620,18 @@ void setup()
preferences = new Preferences();
preferences->begin("nukihub", false);
initPreferences(preferences);
- uint8_t partitionType = checkPartition();
-
initializeRestartReason();
+ if(esp_reset_reason() == esp_reset_reason_t::ESP_RST_PANIC ||
+ esp_reset_reason() == esp_reset_reason_t::ESP_RST_INT_WDT ||
+ esp_reset_reason() == esp_reset_reason_t::ESP_RST_TASK_WDT ||
+ esp_reset_reason() == esp_reset_reason_t::ESP_RST_WDT)
+ {
+ logCoreDump();
+ }
+
+ uint8_t partitionType = checkPartition();
+
//default disableNetwork RTC_ATTR to false on power-on
if(espRunning != 1)
{
@@ -618,6 +717,20 @@ void setup()
file2.close();
key[filesize2] = '\0';
+ psychicServer = new PsychicHttpServer();
+ psychicServer->config.ctrl_port = 20424;
+ psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
+ String url = "https://" + request->host() + request->url();
+ if (preferences->getString(preference_https_fqdn, "") != "")
+ {
+ url = "https://" + preferences->getString(preference_https_fqdn) + request->url();
+ }
+
+ response->setCode(301);
+ response->addHeader("Cache-Control", "no-cache");
+ return response->redirect(url.c_str());
+ });
+ psychicServer->begin();
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;
psychicSSLServer->setCertificate(cert, key);
@@ -780,6 +893,20 @@ void setup()
file2.close();
key[filesize2] = '\0';
+ psychicServer = new PsychicHttpServer();
+ psychicServer->config.ctrl_port = 20424;
+ psychicServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
+ String url = "https://" + request->host() + request->url();
+ if (preferences->getString(preference_https_fqdn, "") != "")
+ {
+ url = "https://" + preferences->getString(preference_https_fqdn) + request->url();
+ }
+
+ response->setCode(301);
+ response->addHeader("Cache-Control", "no-cache");
+ return response->redirect(url.c_str());
+ });
+ psychicServer->begin();
psychicSSLServer = new PsychicHttpsServer;
psychicSSLServer->ssl_config.httpd.max_open_sockets = 8;
psychicSSLServer->setCertificate(cert, key);
diff --git a/updater/platformio.ini b/updater/platformio.ini
index 1ceacf0..6ceb202 100644
--- a/updater/platformio.ini
+++ b/updater/platformio.ini
@@ -51,6 +51,7 @@ lib_ignore =
lib_deps =
PsychicHttp=symlink://../lib/PsychicHttp
ArduinoJson=symlink://../lib/ArduinoJson
+ DuoAuthLibrary=symlink://../lib/DuoAuthLibrary
monitor_speed = 115200
monitor_filters =
|