| Current bootloop prevention state | ");
response.print(_preferences->getBool(preference_enable_bootloop_reset, false) ? "Enabled" : "Disabled");
@@ -5233,14 +5860,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 +5909,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..ba055dd 100644
--- a/src/WebCfgServer.h
+++ b/src/WebCfgServer.h
@@ -100,14 +100,20 @@ private:
std::vector _rssiList;
String generateConfirmCode();
String _confirmCode = "----";
-
- void saveSessions();
- void loadSessions();
+
+ int checkDuoAuth(PsychicRequest *request);
+ int checkDuoApprove();
+ bool startDuoAuth();
+ 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 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 +139,22 @@ 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;
+ 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..a255b56 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -618,6 +618,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 +794,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 =
|