Coredump and Duo Auth

This commit is contained in:
iranl
2025-01-21 21:41:43 +01:00
parent 6c3a0f078d
commit 2964f54e96
13 changed files with 356 additions and 52 deletions

View File

@@ -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-20"
#define NUKI_HUB_DATE "2025-01-22"
#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"
@@ -24,6 +24,7 @@
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32c3.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32c3.bin"
#define NUKI_HUB_HW (char*)"ESP32-C3"
#define BOOT_BUTTON_GPIO (gpio_num_t)9
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(CONFIG_SPIRAM_MODE_OCT)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3oct.bin"
@@ -41,6 +42,7 @@
#define GITHUB_LATEST_RELEASE_BINARY_URL_OTHER (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL_OTHER (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32s3.bin"
#define NUKI_HUB_HW (char*)"ESP32-S3 (Octal PSRAM)"
#define BOOT_BUTTON_GPIO (gpio_num_t)0
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32s3.bin"
@@ -57,6 +59,7 @@
#define GITHUB_LATEST_RELEASE_BINARY_URL_OTHER (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3oct.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL_OTHER (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32s3oct.bin"
#define NUKI_HUB_HW (char*)"ESP32-S3"
#define BOOT_BUTTON_GPIO (gpio_num_t)0
#endif
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32c6.bin"
@@ -72,6 +75,7 @@
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32c6.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32c6.bin"
#define NUKI_HUB_HW (char*)"ESP32-C6"
#define BOOT_BUTTON_GPIO (gpio_num_t)9
#elif defined(CONFIG_IDF_TARGET_ESP32H2)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32h2.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32h2.bin"
@@ -86,6 +90,7 @@
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32h2.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32h2.bin"
#define NUKI_HUB_HW (char*)"ESP32-H2"
#define BOOT_BUTTON_GPIO (gpio_num_t)9
#else
#if defined(CONFIG_FREERTOS_UNICORE)
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32-solo1.bin"
@@ -101,6 +106,7 @@
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32-solo1.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32-solo1.bin"
#define NUKI_HUB_HW (char*)"ESP32-SOLO1"
#define BOOT_BUTTON_GPIO (gpio_num_t)0
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32.bin"
@@ -115,6 +121,7 @@
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32.bin"
#define NUKI_HUB_HW (char*)"ESP32"
#define BOOT_BUTTON_GPIO (gpio_num_t)0
#endif
#endif

View File

@@ -122,6 +122,19 @@ void Gpio::init()
bool hasInputPin = false;
if (_inst->_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false))
{
pinMode(BOOT_BUTTON_GPIO, INPUT);
}
if (_inst->_preferences->getInt(preference_cred_bypass_gpio_high, -1) > -1)
{
pinMode(_inst->_preferences->getInt(preference_cred_bypass_gpio_high, -1), INPUT);
}
if (_inst->_preferences->getInt(preference_cred_bypass_gpio_low, -1) > -1)
{
pinMode(_inst->_preferences->getInt(preference_cred_bypass_gpio_low, -1), INPUT);
}
for(const auto& entry : _inst->_pinConfiguration)
{
const auto it = std::find(_inst->availablePins().begin(), _inst->availablePins().end(), entry.pin);
@@ -238,10 +251,23 @@ void Gpio::loadPinConfiguration()
}
}
const std::vector<int> Gpio::getDisabledPins() const
const std::vector<int> Gpio::getDisabledPins() const
{
std::vector<int> disabledPins;
if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false))
{
disabledPins.push_back(BOOT_BUTTON_GPIO);
}
if (_preferences->getInt(preference_cred_bypass_gpio_high, -1) > -1)
{
disabledPins.push_back(_preferences->getInt(preference_cred_bypass_gpio_high, -1));
}
if (_preferences->getInt(preference_cred_bypass_gpio_low, -1) > -1)
{
disabledPins.push_back(_preferences->getInt(preference_cred_bypass_gpio_low, -1));
}
switch(_preferences->getInt(preference_network_hardware, 0))
{
case 2:
@@ -333,7 +359,7 @@ const std::vector<int> Gpio::getDisabledPins() const
break;
}
Log->print(("GPIO Ethernet disabled pins:"));
Log->print(("GPIO Boot button and Ethernet disabled pins:"));
for_each_n(disabledPins.begin(), disabledPins.size(),
[](int x)
{

View File

@@ -636,7 +636,7 @@ bool NukiNetwork::reconnect()
{
Log->println(("MQTT Broker not configured, aborting connection attempt."));
_nextReconnect = espMillis() + 5000;
if(_device->isConnected())
{
_lastConnectedTs = espMillis();
@@ -1036,7 +1036,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
return;
}
Log->println(("Webserver enabled, restarting."));
_preferences->putBool(preference_webserver_enabled, true);
_preferences->putBool(preference_webserver_enabled, true);
}
else if (strcmp(data, "0") == 0)
{

View File

@@ -88,6 +88,9 @@
#define preference_cred_session_lifetime_duo (char*)"credLfDuo"
#define preference_cred_session_lifetime_duo_remember (char*)"credLfDuoRmbr"
#define preference_cred_duo_approval (char*)"duoApprove"
#define preference_cred_bypass_boot_btn_enabled (char*)"bypassBtBtn"
#define preference_cred_bypass_gpio_high (char*)"bypassHigh"
#define preference_cred_bypass_gpio_low (char*)"bypassLow"
// CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT
#define preference_find_best_rssi (char*)"nwbestrssi"
@@ -237,6 +240,7 @@ inline void initPreferences(Preferences* preferences)
preferences->putBool(preference_enable_debug_mode, false);
preferences->putBool(preference_cred_duo_enabled, false);
preferences->putBool(preference_cred_duo_approval, false);
preferences->putBool(preference_cred_bypass_boot_btn_enabled, false);
preferences->putInt(preference_mqtt_broker_port, 1883);
preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
@@ -260,6 +264,8 @@ inline void initPreferences(Preferences* preferences)
preferences->putInt(preference_cred_session_lifetime_remember, 720);
preferences->putInt(preference_cred_session_lifetime_duo, 3600);
preferences->putInt(preference_cred_session_lifetime_duo_remember, 720);
preferences->putInt(preference_cred_bypass_gpio_high, -1);
preferences->putInt(preference_cred_bypass_gpio_low, -1);
#ifndef CONFIG_IDF_TARGET_ESP32H2
WiFi.begin();
@@ -519,7 +525,7 @@ private:
preference_lock_force_id, preference_lock_force_doorsensor, preference_lock_force_keypad, preference_opener_force_id, preference_opener_force_keypad, preference_nukihub_id,
preference_cred_duo_host, preference_cred_duo_ikey, preference_cred_duo_skey, preference_cred_duo_user, preference_cred_duo_enabled, preference_https_fqdn, preference_bypass_proxy,
preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember,
preference_cred_duo_approval
preference_cred_duo_approval, preference_cred_bypass_boot_btn_enabled, preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low
};
std::vector<char*> _redact =
{
@@ -535,7 +541,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_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi,
preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_find_best_rssi, preference_cred_bypass_boot_btn_enabled,
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, preference_cred_duo_enabled, preference_cred_duo_approval
@@ -556,7 +562,8 @@ private:
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_http_auth_type,
preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember
preference_cred_session_lifetime, preference_cred_session_lifetime_remember, preference_cred_session_lifetime_duo, preference_cred_session_lifetime_duo_remember,
preference_cred_bypass_gpio_high, preference_cred_bypass_gpio_low
};
std::vector<char*> _uintPrefs =
{

View File

@@ -16,6 +16,7 @@
#endif
#include <Update.h>
#include <DuoAuthLib.h>
#include "driver/gpio.h"
extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_bundle_start");
extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end");
@@ -60,6 +61,15 @@ WebCfgServer::WebCfgServer(NukiNetwork* network, Preferences* preferences, bool
{
_duoEnabled = false;
}
else if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false) || _preferences->getInt(preference_cred_bypass_gpio_high, -1) > -1 || _preferences->getInt(preference_cred_bypass_gpio_low, -1) > -1)
{
if (_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false))
{
_bypassGPIO = true;
}
_bypassGPIOHigh = _preferences->getInt(preference_cred_bypass_gpio_high, -1);
_bypassGPIOLow = _preferences->getInt(preference_cred_bypass_gpio_low, -1);
}
}
if(str.length() > 0)
@@ -288,6 +298,30 @@ int WebCfgServer::doAuthentication(PsychicRequest *request)
}
else if (_duoEnabled && !isAuthenticated(request, true))
{
if (_bypassGPIO)
{
if (digitalRead(BOOT_BUTTON_GPIO) == LOW)
{
Log->print("Duo bypassed because boot button pressed");
return 4;
}
}
if (_bypassGPIOHigh > -1)
{
if (digitalRead(_bypassGPIOHigh) == HIGH)
{
Log->print("Duo bypassed because bypass GPIO pin pulled high");
return 4;
}
}
if (_bypassGPIOLow > -1)
{
if (digitalRead(_bypassGPIOLow) == LOW)
{
Log->print("Duo bypassed because bypass GPIO pin pulled low");
return 4;
}
}
return 3;
}
}
@@ -299,6 +333,30 @@ int WebCfgServer::doAuthentication(PsychicRequest *request)
}
else if (_duoEnabled && !isAuthenticated(request, true))
{
if (_bypassGPIO)
{
if (digitalRead(BOOT_BUTTON_GPIO) == LOW)
{
Log->print("Duo bypassed because boot button pressed");
return 4;
}
}
if (_bypassGPIOHigh > -1)
{
if (digitalRead(_bypassGPIOHigh) == HIGH)
{
Log->print("Duo bypassed because bypass GPIO pin pulled high");
return 4;
}
}
if (_bypassGPIOLow > -1)
{
if (digitalRead(_bypassGPIOLow) == LOW)
{
Log->print("Duo bypassed because bypass GPIO pin pulled low");
return 4;
}
}
return 3;
}
}
@@ -307,7 +365,7 @@ int WebCfgServer::doAuthentication(PsychicRequest *request)
return 4;
}
bool WebCfgServer::startDuoAuth()
bool WebCfgServer::startDuoAuth(char* pushType)
{
int64_t timeout = esp_timer_get_time() - (30 * 1000 * 1000L);
if(!_duoActiveRequest || timeout > _duoRequestTS)
@@ -320,6 +378,7 @@ bool WebCfgServer::startDuoAuth()
DuoAuthLib duoAuth;
bool duoRequestResult;
duoAuth.begin(duo_host, duo_ikey, duo_skey, &timeinfo);
duoAuth.setPushType(pushType);
duoRequestResult = duoAuth.pushAuth((char*)duo_user, true);
if(duoRequestResult == true)
@@ -345,25 +404,10 @@ int WebCfgServer::checkDuoAuth(PsychicRequest *request)
const char* duo_ikey = _duoIkey.c_str();
const char* duo_skey = _duoSkey.c_str();
const char* duo_user = _duoUser.c_str();
Log->println("Checking Duo auth");
if (request->hasParam("id")) {
Log->println("Found Duo ID");
const PsychicWebParameter* p = request->getParam("id");
String cookie2 = p->value();
Log->print("_duoActiveRequest: ");
Log->println(_duoActiveRequest ? "Yes" : "No");
Log->print("_duoCheckIP: ");
Log->println(_duoCheckIP);
Log->print("clientIP: ");
Log->println(request->client()->localIP().toString());
Log->print("cookie2: ");
Log->println(cookie2);
Log->print("_duoCheckId: ");
Log->println(_duoCheckId);
DuoAuthLib duoAuth;
if(_duoActiveRequest && _duoCheckIP == request->client()->localIP().toString() && cookie2 == _duoCheckId)
{
@@ -642,6 +686,10 @@ void WebCfgServer::initialize()
{
return buildDuoCheckHtml(request, resp);
}
else if (value == "coredump")
{
return buildCoredumpHtml(request, resp);
}
else if (value == "reboot")
{
String value = "";
@@ -686,6 +734,26 @@ void WebCfgServer::initialize()
}
else if (value == "export")
{
if(_preferences->getBool(preference_cred_duo_approval, false))
{
if (startDuoAuth((char*)"Approve Nuki Hub export"))
{
int duoResult = 2;
while (duoResult == 2)
{
duoResult = checkDuoApprove();
delay(2000);
esp_task_wdt_reset();
}
if (duoResult != 1)
{
return buildConfirmHtml(request, resp, "Duo approval failed, redirecting to main menu", 3, true);
}
}
}
return sendSettings(request, resp);
}
else if (value == "impexpcfg")
@@ -881,22 +949,20 @@ void WebCfgServer::initialize()
if(_preferences->getBool(preference_cred_duo_approval, false))
{
if (startDuoAuth())
if (startDuoAuth((char*)"Approve Nuki Hub setting change"))
{
int duoResult = 2;
while (duoResult == 2)
{
duoResult = checkDuoApprove();
delay(2000);
esp_task_wdt_reset();
}
if (duoResult != 1)
{
resp->setCode(302);
resp->addHeader("Cache-Control", "no-cache");
return resp->redirect("/");
return buildConfirmHtml(request, resp, "Duo approval failed, redirecting to main menu", 3, true);
}
}
}
@@ -1856,9 +1922,38 @@ esp_err_t WebCfgServer::buildDuoCheckHtml(PsychicRequest *request, PsychicRespon
return resp->send();
}
esp_err_t WebCfgServer::buildCoredumpHtml(PsychicRequest *request, PsychicResponse* resp)
{
if (!SPIFFS.begin(true))
{
Log->println("SPIFFS Mount Failed");
}
else
{
File file = SPIFFS.open("/coredump.hex", "r");
if (!file || file.isDirectory()) {
Log->println("coredump.hex not found");
}
else
{
PsychicFileResponse response(resp, file, "coredump.hex");
String name = "coredump.txt";
char buf[26 + name.length()];
snprintf(buf, sizeof(buf), "attachment; filename=\"%s\"", name.c_str());
response.addHeader("Content-Disposition", buf);
return response.send();
}
}
resp->setCode(302);
resp->addHeader("Cache-Control", "no-cache");
return resp->redirect("/");
}
esp_err_t WebCfgServer::buildDuoHtml(PsychicRequest *request, PsychicResponse* resp)
{
bool duo = startDuoAuth();
bool duo = startDuoAuth((char*)"Approve Nuki Hub login");
if (!duo)
{
@@ -1891,14 +1986,14 @@ esp_err_t WebCfgServer::buildDuoHtml(PsychicRequest *request, PsychicResponse* r
_duoCheckIP = request->client()->localIP().toString();
_duoCheckId = buffer;
response.beginSend();
response.print("<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
response.print("<style>.container{border:3px solid #f1f1f1; max-width: 400px; padding:16px}</style>");
response.print((String)"<script>let intervalId; window.onload = function() { updateInfo(); intervalId = setInterval(updateInfo, 2000); }; function updateInfo() { var request = new XMLHttpRequest(); request.open('GET', '/get?page=duocheck&id=" + _duoCheckId + "', true); request.onload = () => { const obj = request.responseText; if (obj == \"1\" || obj == \"0\") { clearInterval(intervalId); window.location.href = \"/\"; } }; request.send(); }</script>");
response.print((String)"<script>let intervalId; window.onload = function() { updateInfo(); intervalId = setInterval(updateInfo, 2000); }; function updateInfo() { var request = new XMLHttpRequest(); request.open('GET', '/get?page=duocheck&id=" + _duoCheckId + "', true); request.onload = () => { const obj = request.responseText; if (obj == \"1\" || obj == \"0\") { clearInterval(intervalId); if (obj == \"1\") { document.getElementById('duoresult').innerHTML = 'Login approved<br>Redirecting...'; setTimeout(function() { window.location.href = \"/\"; }, 2000); } else { document.getElementById('duoresult').innerHTML = 'Login failed<br>Refresh to retry'; } } }; request.send(); }</script>");
response.print("</head><body><center><h2>Nuki Hub login</h2>");
response.print("<div class=\"container\">Duo Push sent<br><br>");
response.print("Please confirm login in the Duo app<br><br></div>");
response.print("Please confirm login in the Duo app<br><br><div id=\"duoresult\"></div></div>");
response.print("</div>");
response.print("</center></body></html>");
@@ -2847,6 +2942,36 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S
newMFA = true;
}
}
else if(key == "DUOBYPASS")
{
if(_preferences->getBool(preference_cred_bypass_boot_btn_enabled, false) != (value == "1"))
{
_preferences->putBool(preference_cred_bypass_boot_btn_enabled, (value == "1"));
Log->print(("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "DUOBYPASSHIGH")
{
if(_preferences->getInt(preference_cred_bypass_gpio_high, -1) != value.toInt())
{
_preferences->putInt(preference_cred_bypass_gpio_high, value.toInt());
Log->print(("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "DUOBYPASSLOW")
{
if(_preferences->getInt(preference_cred_bypass_gpio_low, -1) != value.toInt())
{
_preferences->putInt(preference_cred_bypass_gpio_low, value.toInt());
Log->print(("Setting changed: "));
Log->println(key);
configChanged = true;
}
}
else if(key == "DUOAPPROVAL")
{
if(_preferences->getBool(preference_cred_duo_approval, false) != (value == "1"))
@@ -4761,6 +4886,7 @@ esp_err_t WebCfgServer::buildImportExportHtml(PsychicRequest *request, PsychicRe
}
#endif
response.print("<br><br><button title=\"Export MQTT SSL CA, client certificate and client key\" onclick=\" window.open('/get?page=export&type=mqtts'); return false;\">Export MQTT SSL CA, client certificate and client key</button>");
response.print("<br><br><button title=\"Export Coredump\" onclick=\" window.open('/get?page=coredump'); return false;\">Export Coredump</button>");
response.print("</div></body></html>");
return response.endSend();
}
@@ -4919,6 +5045,9 @@ esp_err_t WebCfgServer::buildCredHtml(PsychicRequest *request, PsychicResponse*
printInputField(&response, "CREDTRUSTPROXY", "Bypass authentication for reverse proxy with IP", _preferences->getString(preference_bypass_proxy, "").c_str(), 255, "");
printCheckBox(&response, "DUOENA", "Duo Push authentication enabled", _preferences->getBool(preference_cred_duo_enabled, false), "");
printCheckBox(&response, "DUOAPPROVAL", "Require Duo Push authentication for all sensitive Nuki Hub operations (changing/exporting settings)", _preferences->getBool(preference_cred_duo_approval, false), "");
printCheckBox(&response, "DUOBYPASS", "Bypass Duo Push authentication by pressing the BOOT button while logging in", _preferences->getBool(preference_cred_bypass_boot_btn_enabled, false), "");
printInputField(&response, "DUOBYPASSHIGH", "Bypass Duo Push authentication by pulling GPIO High", _preferences->getInt(preference_cred_bypass_gpio_high, -1), 2, "");
printInputField(&response, "DUOBYPASSLOW", "Bypass Duo Push authentication by pulling GPIO Low", _preferences->getInt(preference_cred_bypass_gpio_low, -1), 2, "");
printInputField(&response, "DUOHOST", "Duo API hostname", "*", 255, "", true, false);
printInputField(&response, "DUOIKEY", "Duo integration key", "*", 255, "", true, false);
printInputField(&response, "DUOSKEY", "Duo secret key", "*", 255, "", true, false);

View File

@@ -103,7 +103,7 @@ private:
int checkDuoAuth(PsychicRequest *request);
int checkDuoApprove();
bool startDuoAuth();
bool startDuoAuth(char* pushType = (char*)"");
void saveSessions(bool duo = false);
void loadSessions(bool duo = false);
void clearSessions();
@@ -111,6 +111,7 @@ private:
bool isAuthenticated(PsychicRequest *request, bool duo = false);
bool processLogin(PsychicRequest *request, PsychicResponse* resp);
int doAuthentication(PsychicRequest *request);
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);
@@ -149,6 +150,9 @@ private:
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;

View File

@@ -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,7 @@ RTC_NOINIT_ATTR bool forceEnableWebServer;
RTC_NOINIT_ATTR bool disableNetwork;
RTC_NOINIT_ATTR bool wifiFallback;
RTC_NOINIT_ATTR bool ethCriticalFailure;
bool coredumpPrinted = true;
int lastHTTPeventId = -1;
bool doOta = false;
@@ -507,6 +509,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 +618,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)
{
@@ -629,7 +726,7 @@ void setup()
response->setCode(301);
response->addHeader("Cache-Control", "no-cache");
return response->redirect(url.c_str());
return response->redirect(url.c_str());
});
psychicServer->begin();
psychicSSLServer = new PsychicHttpsServer;
@@ -805,7 +902,7 @@ void setup()
response->setCode(301);
response->addHeader("Cache-Control", "no-cache");
return response->redirect(url.c_str());
return response->redirect(url.c_str());
});
psychicServer->begin();
psychicSSLServer = new PsychicHttpsServer;