Coredump and Duo Auth
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
30
src/Gpio.cpp
30
src/Gpio.cpp
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 =
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
109
src/main.cpp
109
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,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;
|
||||
|
||||
Reference in New Issue
Block a user