diff --git a/platformio.ini b/platformio.ini index 08f6a64..3d6a646 100644 --- a/platformio.ini +++ b/platformio.ini @@ -32,9 +32,6 @@ build_unflags = -Wall build_flags = -fexceptions - -DTLS_CA_MAX_SIZE=2200 - -DTLS_CERT_MAX_SIZE=2200 - -DTLS_KEY_MAX_SIZE=2200 -DESP_PLATFORM -DESP32 -DARDUINO_ARCH_ESP32 diff --git a/sdkconfig.defaults b/sdkconfig.defaults index 7a29d2b..d5bbbbe 100644 --- a/sdkconfig.defaults +++ b/sdkconfig.defaults @@ -22,7 +22,7 @@ CONFIG_BT_NIMBLE_PINNED_TO_CORE_0=y CONFIG_BT_NIMBLE_PINNED_TO_CORE=0 CONFIG_BT_NIMBLE_HOST_TASK_STACK_SIZE=8192 CONFIG_BT_NIMBLE_ROLE_CENTRAL=y -CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=y +CONFIG_BT_NIMBLE_ROLE_PERIPHERAL=n CONFIG_BT_NIMBLE_ROLE_BROADCASTER=y CONFIG_BT_NIMBLE_ROLE_OBSERVER=y CONFIG_BT_NIMBLE_SM_LEGACY=y diff --git a/src/Config.h b/src/Config.h index 48f590a..cca0fb8 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.07" #define NUKI_HUB_VERSION_INT (uint32_t)907 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2025-01-02" +#define NUKI_HUB_DATE "2025-01-03" #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 f2c744a..2996690 100644 --- a/src/PreferencesKeys.h +++ b/src/PreferencesKeys.h @@ -3,6 +3,9 @@ #include #include "Config.h" #include "Logger.h" +#include "FS.h" +#include "SPIFFS.h" +#include "RestartReason.h" #ifndef CONFIG_IDF_TARGET_ESP32H2 #include @@ -69,6 +72,7 @@ #define preference_connect_mode (char*)"nukiConnMode" #define preference_http_auth_type (char*)"httpdAuthType" #define preference_update_time (char*)"updateTime" +#define preference_mqtt_ssl_enabled (char*)"mqttSSLena" // CHANGE DOES NOT REQUIRE REBOOT TO TAKE EFFECT #define preference_find_best_rssi (char*)"nwbestrssi" @@ -199,6 +203,7 @@ inline void initPreferences(Preferences* preferences) preferences->putBool(preference_publish_authdata, false); preferences->putBool(preference_register_as_app, false); preferences->putBool(preference_register_opener_as_app, false); + preferences->putBool(preference_mqtt_ssl_enabled, false); preferences->putInt(preference_mqtt_broker_port, 1883); preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE); @@ -226,7 +231,6 @@ inline void initPreferences(Preferences* preferences) preferences->putBool(preference_connect_mode, true); preferences->putBool(preference_http_auth_type, false); preferences->putBool(preference_retain_gpio, false); - #ifndef CONFIG_IDF_TARGET_ESP32H2 WiFi.begin(); @@ -236,6 +240,7 @@ inline void initPreferences(Preferences* preferences) else { int lastConfigVer = preferences->getInt(preference_config_version); + bool rebootOnMigrate = false; Log->print("Last config version: "); Log->println(lastConfigVer); @@ -357,7 +362,100 @@ inline void initPreferences(Preferences* preferences) Log->println("Migration 9.02"); preferences->putBool(preference_reset_mqtt_topics, true); } + if (lastConfigVer < 907) + { + Log->println("Migration 9.07"); + + char ca[2200] = {0}; + char cert[2200] = {0}; + char key[2200] = {0}; + + size_t caLength = preferences->getString(preference_mqtt_ca, ca, 2200); + size_t crtLength = preferences->getString(preference_mqtt_crt, cert, 2200); + size_t keyLength = preferences->getString(preference_mqtt_key, key, 2200); + + if (caLength > 1) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.ca", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.ca for writing"); + } + else + { + if (!file.print(ca)) + { + Log->println("Failed to write /mqtt_ssl.ca"); + } + file.close(); + } + } + + rebootOnMigrate = true; + preferences->putBool(preference_mqtt_ssl_enabled, true); + preferences->putString(preference_mqtt_ca, ""); + } + + if (crtLength > 1) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.crt", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.crt for writing"); + } + else + { + if (!file.print(cert)) + { + Log->println("Failed to write /mqtt_ssl.crt"); + } + file.close(); + } + } + + rebootOnMigrate = true; + preferences->putString(preference_mqtt_crt, ""); + } + + if (keyLength > 1) + { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.key", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.key for writing"); + } + else + { + if (!file.print(key)) + { + Log->println("Failed to write /mqtt_ssl.key"); + } + file.close(); + } + } + + rebootOnMigrate = true; + preferences->putString(preference_mqtt_key, ""); + } + } preferences->putInt(preference_config_version, NUKI_HUB_VERSION_INT); + + if (rebootOnMigrate) + { + restartEsp(RestartReason::OTACompleted); + } } #endif } @@ -367,29 +465,29 @@ class DebugPreferences private: std::vector _keys = { - preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, - preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates, - preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status, - preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time, - preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt, - preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address, - preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type, - preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, - preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, - preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, - preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled, - preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, - preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info, - preference_official_hybrid_enabled, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry, - preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries, - preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_webserial_enabled, preference_find_best_rssi, - 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_ntw_reconfigure, preference_lock_max_auth_entry_count, preference_opener_max_auth_entry_count, - preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass, - preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_mqtt_hass_enabled, preference_hass_device_discovery, preference_retain_gpio, - 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_nukihub_id + preference_started_before, preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, + preference_mqtt_broker, preference_mqtt_broker_port, preference_mqtt_user, preference_mqtt_password, preference_mqtt_log_enabled, preference_check_updates, + preference_webserver_enabled, preference_lock_enabled, preference_lock_pin_status, preference_mqtt_lock_path, preference_opener_enabled, preference_opener_pin_status, + preference_opener_continuous_mode, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, preference_update_time, + preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_enable_bootloop_reset, preference_mqtt_ca, preference_mqtt_crt, + preference_mqtt_key, preference_mqtt_hass_discovery, preference_mqtt_hass_cu_url, preference_buffer_size, preference_ip_dhcp_enabled, preference_ip_address, + preference_ip_subnet, preference_ip_gateway, preference_ip_dns_server, preference_network_hardware, preference_http_auth_type, + preference_rssi_publish_interval, preference_hostname, preference_network_timeout, preference_restart_on_disconnect, + preference_restart_ble_beacon_lost, preference_query_interval_lockstate, preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, + preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_keypad_control_enabled, + preference_keypad_info_enabled, preference_keypad_publish_code, preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_conf_info_enabled, + preference_register_as_app, preference_register_opener_as_app, preference_command_nr_of_retries, preference_command_retry_delay, preference_cred_user, + preference_cred_password, preference_disable_non_json, preference_publish_authdata, preference_publish_debug_info, preference_mqtt_ssl_enabled, + preference_official_hybrid_enabled, preference_query_interval_hybrid_lockstate, preference_official_hybrid_actions, preference_official_hybrid_retry, + preference_task_size_network, preference_task_size_nuki, preference_authlog_max_entries, preference_keypad_max_entries, preference_timecontrol_max_entries, + preference_update_from_mqtt, preference_show_secrets, preference_ble_tx_power, preference_webserial_enabled, preference_find_best_rssi, + 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_ntw_reconfigure, preference_lock_max_auth_entry_count, preference_opener_max_auth_entry_count, + preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass, + preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_mqtt_hass_enabled, preference_hass_device_discovery, preference_retain_gpio, + 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_nukihub_id }; std::vector _redact = { @@ -398,34 +496,34 @@ private: }; std::vector _boolPrefs = { - preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode, - preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_update_time, - preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets, - preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled, - 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_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_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode, + preference_timecontrol_topic_per_entry, preference_keypad_topic_per_entry, preference_enable_bootloop_reset, preference_webserver_enabled, preference_update_time, + preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled, preference_keypad_publish_code, preference_show_secrets, + preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled, + 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_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 }; std::vector _bytePrefs = { - preference_acl, preference_conf_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, - preference_conf_opener_advanced_acl, preference_gpio_configuration + preference_acl, preference_conf_info_enabled, preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, + preference_conf_opener_advanced_acl, preference_gpio_configuration }; std::vector _intPrefs = { - preference_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker_port, - preference_lock_pin_status, preference_opener_pin_status, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, - preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_buffer_size, preference_network_hardware, - preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, - preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries, - preference_command_retry_delay, preference_query_interval_hybrid_lockstate, - 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_config_version, preference_device_id_lock, preference_device_id_opener, preference_nuki_id_lock, preference_nuki_id_opener, preference_mqtt_broker_port, + preference_lock_pin_status, preference_opener_pin_status, preference_lock_max_keypad_code_count, preference_opener_max_keypad_code_count, + preference_lock_max_timecontrol_entry_count, preference_opener_max_timecontrol_entry_count, preference_buffer_size, preference_network_hardware, + preference_rssi_publish_interval, preference_network_timeout, preference_restart_ble_beacon_lost, preference_query_interval_lockstate, + preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad, preference_command_nr_of_retries, + preference_command_retry_delay, preference_query_interval_hybrid_lockstate, + 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 }; public: const std::vector getPreferencesKeys() diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 94b84e9..1746de4 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -4,10 +4,10 @@ #include "Logger.h" #include "RestartReason.h" #include -#ifdef CONFIG_SOC_SPIRAM_SUPPORTED -#include "esp_psram.h" #include "FS.h" #include "SPIFFS.h" +#ifdef CONFIG_SOC_SPIRAM_SUPPORTED +#include "esp_psram.h" #endif #ifndef CONFIG_IDF_TARGET_ESP32H2 #include @@ -112,20 +112,10 @@ void WebCfgServer::initialize() }); _psychicServer->on("/style.css", 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 sendCss(request, resp); }); _psychicServer->on("/favicon.ico", 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 sendFavicon(request, resp); }); @@ -1269,206 +1259,335 @@ void WebCfgServer::printInputField(PsychicStreamResponse *response, #ifndef NUKI_HUB_UPDATER esp_err_t WebCfgServer::sendSettings(PsychicRequest *request, PsychicResponse* resp) { - bool redacted = false; - bool pairing = false; - - if(request->hasParam("redacted")) - { - const PsychicWebParameter* p = request->getParam("redacted"); - if(p->value() == "1") - { - redacted = true; - } - } - if(request->hasParam("pairing")) - { - const PsychicWebParameter* p = request->getParam("pairing"); - if(p->value() == "1") - { - pairing = true; - } - } - JsonDocument json; String jsonPretty; + String name; - DebugPreferences debugPreferences; - - const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); - const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); - const std::vector redactedPrefs = debugPreferences.getPreferencesRedactedKeys(); - const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); - - for(const auto& key : keysPrefs) + if(request->hasParam("type")) { - if(strcmp(key, preference_show_secrets) == 0) + name = "nuki_hub_http_ssl.json"; + const PsychicWebParameter* p = request->getParam("type"); + if(p->value() == "https") { - continue; - } - if(strcmp(key, preference_latest_version) == 0) - { - continue; - } - if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end()) - { - continue; + name = "nuki_hub_http_ssl.json"; + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/http_ssl.crt"); + if (!file || file.isDirectory()) { + Log->println("http_ssl.crt not found"); + } + else + { + Log->println("Reading http_ssl.crt"); + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); + file.close(); + cert[filesize] = '\0'; + json["http_ssl.crt"] = cert; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/http_ssl.key"); + if (!file || file.isDirectory()) { + Log->println("http_ssl.key not found"); + } + else + { + Log->println("Reading http_ssl.key"); + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); + file.close(); + key[filesize] = '\0'; + json["http_ssl.key"] = key; + } } - if(!_preferences->isKey(key)) - { - json[key] = ""; - } - else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) - { - json[key] = _preferences->getBool(key) ? "1" : "0"; } else { - switch(_preferences->getType(key)) + name = "nuki_hub_mqtt_ssl.json"; + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else { - case PT_I8: - json[key] = String(_preferences->getChar(key)); - break; - case PT_I16: - json[key] = String(_preferences->getShort(key)); - break; - case PT_I32: - json[key] = String(_preferences->getInt(key)); - break; - case PT_I64: - json[key] = String(_preferences->getLong64(key)); - break; - case PT_U8: - json[key] = String(_preferences->getUChar(key)); - break; - case PT_U16: - json[key] = String(_preferences->getUShort(key)); - break; - case PT_U32: - json[key] = String(_preferences->getUInt(key)); - break; - case PT_U64: - json[key] = String(_preferences->getULong64(key)); - break; - case PT_STR: - json[key] = _preferences->getString(key); - break; - default: - json[key] = _preferences->getString(key); - break; + File file = SPIFFS.open("/mqtt_ssl.ca"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.ca not found"); + } + else + { + Log->println("Reading mqtt_ssl.ca"); + size_t filesize = file.size(); + char ca[filesize + 1]; + + file.read((uint8_t *)ca, sizeof(ca)); + file.close(); + ca[filesize] = '\0'; + json["mqtt_ssl.ca"] = ca; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.crt"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.crt not found"); + } + else + { + Log->println("Reading mqtt_ssl.crt"); + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); + file.close(); + cert[filesize] = '\0'; + json["mqtt_ssl.crt"] = cert; + } + } + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.key"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.key not found"); + } + else + { + Log->println("Reading mqtt_ssl.key"); + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); + file.close(); + key[filesize] = '\0'; + json["mqtt_ssl.key"] = key; + } } } } - - if(pairing) + else { - if(_nuki != nullptr) + name = "nuki_hub_settings.json"; + bool redacted = false; + bool pairing = false; + + if(request->hasParam("redacted")) { - unsigned char currentBleAddress[6]; - unsigned char authorizationId[4] = {0x00}; - unsigned char secretKeyK[32] = {0x00}; - uint16_t storedPincode = 0000; - Preferences nukiBlePref; - nukiBlePref.begin("NukiHub", false); - nukiBlePref.getBytes("bleAddress", currentBleAddress, 6); - nukiBlePref.getBytes("secretKeyK", secretKeyK, 32); - nukiBlePref.getBytes("authorizationId", authorizationId, 4); - nukiBlePref.getBytes("securityPinCode", &storedPincode, 2); - nukiBlePref.end(); + const PsychicWebParameter* p = request->getParam("redacted"); + if(p->value() == "1") + { + redacted = true; + } + } + if(request->hasParam("pairing")) + { + const PsychicWebParameter* p = request->getParam("pairing"); + if(p->value() == "1") + { + pairing = true; + } + } + + DebugPreferences debugPreferences; + + const std::vector keysPrefs = debugPreferences.getPreferencesKeys(); + const std::vector boolPrefs = debugPreferences.getPreferencesBoolKeys(); + const std::vector redactedPrefs = debugPreferences.getPreferencesRedactedKeys(); + const std::vector bytePrefs = debugPreferences.getPreferencesByteKeys(); + + for(const auto& key : keysPrefs) + { + if(strcmp(key, preference_show_secrets) == 0) + { + continue; + } + if(strcmp(key, preference_latest_version) == 0) + { + continue; + } + if(!redacted) if(std::find(redactedPrefs.begin(), redactedPrefs.end(), key) != redactedPrefs.end()) + { + continue; + } + if(!_preferences->isKey(key)) + { + json[key] = ""; + } + else if(std::find(boolPrefs.begin(), boolPrefs.end(), key) != boolPrefs.end()) + { + json[key] = _preferences->getBool(key) ? "1" : "0"; + } + else + { + switch(_preferences->getType(key)) + { + case PT_I8: + json[key] = String(_preferences->getChar(key)); + break; + case PT_I16: + json[key] = String(_preferences->getShort(key)); + break; + case PT_I32: + json[key] = String(_preferences->getInt(key)); + break; + case PT_I64: + json[key] = String(_preferences->getLong64(key)); + break; + case PT_U8: + json[key] = String(_preferences->getUChar(key)); + break; + case PT_U16: + json[key] = String(_preferences->getUShort(key)); + break; + case PT_U32: + json[key] = String(_preferences->getUInt(key)); + break; + case PT_U64: + json[key] = String(_preferences->getULong64(key)); + break; + case PT_STR: + json[key] = _preferences->getString(key); + break; + default: + json[key] = _preferences->getString(key); + break; + } + } + } + + if(pairing) + { + if(_nuki != nullptr) + { + unsigned char currentBleAddress[6]; + unsigned char authorizationId[4] = {0x00}; + unsigned char secretKeyK[32] = {0x00}; + uint16_t storedPincode = 0000; + Preferences nukiBlePref; + nukiBlePref.begin("NukiHub", false); + nukiBlePref.getBytes("bleAddress", currentBleAddress, 6); + nukiBlePref.getBytes("secretKeyK", secretKeyK, 32); + nukiBlePref.getBytes("authorizationId", authorizationId, 4); + nukiBlePref.getBytes("securityPinCode", &storedPincode, 2); + nukiBlePref.end(); + char text[255]; + text[0] = '\0'; + for(int i = 0 ; i < 6 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", currentBleAddress[i]); + } + json["bleAddressLock"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 32 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", secretKeyK[i]); + } + json["secretKeyKLock"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 4 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", authorizationId[i]); + } + json["authorizationIdLock"] = text; + memset(text, 0, sizeof(text)); + json["securityPinCodeLock"] = storedPincode; + } + if(_nukiOpener != nullptr) + { + unsigned char currentBleAddressOpn[6]; + unsigned char authorizationIdOpn[4] = {0x00}; + unsigned char secretKeyKOpn[32] = {0x00}; + uint16_t storedPincodeOpn = 0000; + Preferences nukiBlePref; + nukiBlePref.begin("NukiHubopener", false); + nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6); + nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32); + nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4); + nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2); + nukiBlePref.end(); + char text[255]; + text[0] = '\0'; + for(int i = 0 ; i < 6 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]); + } + json["bleAddressOpener"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 32 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]); + } + json["secretKeyKOpener"] = text; + memset(text, 0, sizeof(text)); + text[0] = '\0'; + for(int i = 0 ; i < 4 ; i++) + { + size_t offset = strlen(text); + sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]); + } + json["authorizationIdOpener"] = text; + memset(text, 0, sizeof(text)); + json["securityPinCodeOpener"] = storedPincodeOpn; + } + } + + for(const auto& key : bytePrefs) + { + size_t storedLength = _preferences->getBytesLength(key); + if(storedLength == 0) + { + continue; + } + uint8_t serialized[storedLength]; + memset(serialized, 0, sizeof(serialized)); + size_t size = _preferences->getBytes(key, serialized, sizeof(serialized)); + if(size == 0) + { + continue; + } char text[255]; text[0] = '\0'; - for(int i = 0 ; i < 6 ; i++) + for(int i = 0 ; i < size ; i++) { size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", currentBleAddress[i]); + sprintf(&(text[offset]), "%02x", serialized[i]); } - json["bleAddressLock"] = text; + json[key] = text; memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 32 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", secretKeyK[i]); - } - json["secretKeyKLock"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 4 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", authorizationId[i]); - } - json["authorizationIdLock"] = text; - memset(text, 0, sizeof(text)); - json["securityPinCodeLock"] = storedPincode; } - if(_nukiOpener != nullptr) - { - unsigned char currentBleAddressOpn[6]; - unsigned char authorizationIdOpn[4] = {0x00}; - unsigned char secretKeyKOpn[32] = {0x00}; - uint16_t storedPincodeOpn = 0000; - Preferences nukiBlePref; - nukiBlePref.begin("NukiHubopener", false); - nukiBlePref.getBytes("bleAddress", currentBleAddressOpn, 6); - nukiBlePref.getBytes("secretKeyK", secretKeyKOpn, 32); - nukiBlePref.getBytes("authorizationId", authorizationIdOpn, 4); - nukiBlePref.getBytes("securityPinCode", &storedPincodeOpn, 2); - nukiBlePref.end(); - char text[255]; - text[0] = '\0'; - for(int i = 0 ; i < 6 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", currentBleAddressOpn[i]); - } - json["bleAddressOpener"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 32 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", secretKeyKOpn[i]); - } - json["secretKeyKOpener"] = text; - memset(text, 0, sizeof(text)); - text[0] = '\0'; - for(int i = 0 ; i < 4 ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", authorizationIdOpn[i]); - } - json["authorizationIdOpener"] = text; - memset(text, 0, sizeof(text)); - json["securityPinCodeOpener"] = storedPincodeOpn; - } - } - - for(const auto& key : bytePrefs) - { - size_t storedLength = _preferences->getBytesLength(key); - if(storedLength == 0) - { - continue; - } - uint8_t serialized[storedLength]; - memset(serialized, 0, sizeof(serialized)); - size_t size = _preferences->getBytes(key, serialized, sizeof(serialized)); - if(size == 0) - { - continue; - } - char text[255]; - text[0] = '\0'; - for(int i = 0 ; i < size ; i++) - { - size_t offset = strlen(text); - sprintf(&(text[offset]), "%02x", serialized[i]); - } - json[key] = text; - memset(text, 0, sizeof(text)); } serializeJsonPretty(json, jsonPretty); + char buf[26 + name.length()]; + snprintf(buf, sizeof(buf), "attachment; filename=\"%s\"", name.c_str()); + resp->addHeader("Content-Disposition", buf); resp->setCode(200); resp->setContentType("application/json"); resp->setContent(jsonPretty.c_str()); @@ -1580,9 +1699,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } else if(key == "MQTTCA") { - if(_preferences->getString(preference_mqtt_ca, "") != value) + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else { - _preferences->putString(preference_mqtt_ca, value); + if(value != "") + { + File file = SPIFFS.open("/mqtt_ssl.ca", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.ca for writing"); + } + else + { + if (!file.print(value)) + { + Log->println("Failed to write /mqtt_ssl.ca"); + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.ca")) { + Serial.println("Failed to delete /mqtt_ssl.ca"); + } + } Log->print(F("Setting changed: ")); Log->println(key); configChanged = true; @@ -1590,9 +1732,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } else if(key == "MQTTCRT") { - if(_preferences->getString(preference_mqtt_crt, "") != value) + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else { - _preferences->putString(preference_mqtt_crt, value); + if(value != "") + { + File file = SPIFFS.open("/mqtt_ssl.crt", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.crt for writing"); + } + else + { + if (!file.print(value)) + { + Log->println("Failed to write /mqtt_ssl.crt"); + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.crt")) { + Serial.println("Failed to delete /mqtt_ssl.crt"); + } + } Log->print(F("Setting changed: ")); Log->println(key); configChanged = true; @@ -1600,9 +1765,32 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S } else if(key == "MQTTKEY") { - if(_preferences->getString(preference_mqtt_key, "") != value) + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else { - _preferences->putString(preference_mqtt_key, value); + if(value != "") + { + File file = SPIFFS.open("/mqtt_ssl.key", FILE_WRITE); + if (!file) { + Log->println("Failed to open /mqtt_ssl.key for writing"); + } + else + { + if (!file.print(value)) + { + Log->println("Failed to write /mqtt_ssl.key"); + } + file.close(); + } + } + else + { + if (!SPIFFS.remove("/mqtt_ssl.key")) { + Serial.println("Failed to delete /mqtt_ssl.key"); + } + } Log->print(F("Setting changed: ")); Log->println(key); configChanged = true; @@ -1959,6 +2147,16 @@ bool WebCfgServer::processArgs(PsychicRequest *request, PsychicResponse* resp, S configChanged = true; } } + else if(key == "MQTTSENA") + { + if(_preferences->getBool(preference_mqtt_ssl_enabled, false) != (value == "1")) + { + _preferences->putBool(preference_mqtt_ssl_enabled, (value == "1")); + Log->print(F("Setting changed: ")); + Log->println(key); + configChanged = true; + } + } else if(key == "WEBLOG") { if(_preferences->getBool(preference_webserial_enabled, false) != (value == "1")) @@ -3541,6 +3739,13 @@ esp_err_t WebCfgServer::buildImportExportHtml(PsychicRequest *request, PsychicRe response.print(""); response.print("

"); response.print("

"); + #ifdef CONFIG_SOC_SPIRAM_SUPPORTED + if(esp_psram_get_size() > 0) + { + response.print("

"); + } + #endif + response.print("

"); response.print(""); return response.endSend(); } @@ -3783,7 +3988,7 @@ esp_err_t WebCfgServer::buildNetworkConfigHtml(PsychicRequest *request, PsychicR if(esp_psram_get_size() > 0) { response.print("Set HTTP SSL Certificate"); - response.print("Set HTTP SSL Key"); + response.print("Set HTTP SSL Key"); } #endif response.print(""); @@ -3826,6 +4031,7 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request, PsychicResp { printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), ""); } + printCheckBox(&response, "MQTTSENA", "Enable MQTT SSL", _preferences->getBool(preference_mqtt_ssl_enabled, false), ""); response.print("Set MQTT SSL CA Certificate"); response.print("Set MQTT SSL Client Certificate"); response.print("Set MQTT SSL Client Key"); @@ -3860,15 +4066,102 @@ esp_err_t WebCfgServer::buildMqttSSLConfigHtml(PsychicRequest *request, PsychicR if (type == 0) { - printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, true, true); + bool found = false; + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.ca"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.ca not found"); + } + else + { + Log->println("Reading mqtt_ssl.ca"); + size_t filesize = file.size(); + char ca[filesize + 1]; + + file.read((uint8_t *)ca, sizeof(ca)); + file.close(); + ca[filesize] = '\0'; + + printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", ca, 2200, true, true); + found = true; + } + } + + if (!found) + { + printTextarea(&response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", "", 2200, true, true); + } } else if (type == 1) { - printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, true, true); + bool found = false; + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.crt"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.crt not found"); + } + else + { + Log->println("Reading mqtt_ssl.crt"); + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); + file.close(); + cert[filesize] = '\0'; + + printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", cert, 2200, true, true); + found = true; + } + } + + if (!found) + { + printTextarea(&response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", "", 2200, true, true); + } } else { - printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, true, true); + bool found = false; + + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.key"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.key not found"); + } + else + { + Log->println("Reading mqtt_ssl.key"); + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); + file.close(); + key[filesize] = '\0'; + + printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", key, 2200, true, true); + found = true; + } + } + + if (!found) + { + printTextarea(&response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", "", 2200, true, true); + } } response.print(""); response.print("
"); @@ -3891,8 +4184,8 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR if (type == 1) { - char cert[4400] = {0}; - + bool found = false; + #ifdef CONFIG_SOC_SPIRAM_SUPPORTED if (!SPIFFS.begin(true)) { Log->println("SPIFFS Mount Failed"); @@ -3906,21 +4199,27 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR else { Log->println("Reading http_ssl.crt"); - uint32_t i = 0; - while(file.available()){ - cert[i] = file.read(); - i++; - } + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); file.close(); + cert[filesize] = '\0'; + + printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", cert, 4400, true, true); + found = true; } } #endif - printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", cert, 4400, true, true); + if (!found) + { + printTextarea(&response, "HTTPCRT", "HTTP SSL Certificate (*, optional)", "", 4400, true, true); + } } else { - char key[2200] = {0}; - + bool found = false; + #ifdef CONFIG_SOC_SPIRAM_SUPPORTED if (!SPIFFS.begin(true)) { Log->println("SPIFFS Mount Failed"); @@ -3934,16 +4233,22 @@ esp_err_t WebCfgServer::buildHttpSSLConfigHtml(PsychicRequest *request, PsychicR else { Log->println("Reading http_ssl.key"); - uint32_t i = 0; - while(file.available()){ - key[i] = file.read(); - i++; - } + size_t filesize = file.size(); + char key[filesize + 1]; + + file.read((uint8_t *)key, sizeof(key)); file.close(); + key[filesize] = '\0'; + + printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", key, 2200, true, true); + found = true; } } #endif - printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", key, 2200, true, true); + if (!found) + { + printTextarea(&response, "HTTPKEY", "HTTP SSL Key (*, optional)", "", 2200, true, true); + } } response.print(""); response.print("
"); @@ -4528,10 +4833,29 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse* response.print(_preferences->getString(preference_cred_password, "").length() > 0 ? "***" : "Not set"); response.print("\nWeb configurator enabled: "); response.print(_preferences->getBool(preference_webserver_enabled, true) ? "Yes" : "No"); - //response.print("\nHTTP SSL CRT: "); - //response.print(_preferences->getString(preference_http_crt, "").length() > 0 ? "***" : "Not set"); - //response.print("\nHTTP SSL Key: "); - //response.print(_preferences->getString(preference_http_key, "").length() > 0 ? "***" : "Not set"); + response.print("\nHTTP SSL: "); + #ifdef CONFIG_SOC_SPIRAM_SUPPORTED + if(esp_psram_get_size() > 0) + { + if (!SPIFFS.begin(true)) { + response.print("Disabled"); + } + else + { + File file = SPIFFS.open("/http_ssl.crt"); + File file2 = SPIFFS.open("/http_ssl.key"); + response.print((!file || file.isDirectory() || !file2 || file2.isDirectory()) ? "Disabled" : "Enabled"); + file.close(); + file2.close(); + } + } + else + { + response.print("Disabled"); + } + #else + response.print("Disabled"); + #endif response.print("\nPublish debug information enabled: "); response.print(_preferences->getBool(preference_publish_debug_info, false) ? "Yes" : "No"); response.print("\nMQTT log enabled: "); @@ -4628,12 +4952,38 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request, PsychicResponse* response.print(_preferences->getString(preference_mqtt_password, "").length() > 0 ? "***" : "Not set"); response.print("\nMQTT base topic: "); response.print(_preferences->getString(preference_mqtt_lock_path, "")); - response.print("\nMQTT SSL CA: "); - response.print(_preferences->getString(preference_mqtt_ca, "").length() > 0 ? "***" : "Not set"); - response.print("\nMQTT SSL CRT: "); - response.print(_preferences->getString(preference_mqtt_crt, "").length() > 0 ? "***" : "Not set"); - response.print("\nMQTT SSL Key: "); - response.print(_preferences->getString(preference_mqtt_key, "").length() > 0 ? "***" : "Not set"); + response.print("\nMQTT SSL: "); + if(_preferences->getBool(preference_mqtt_ssl_enabled, false)) + { + if (!SPIFFS.begin(true)) { + response.print("Disabled"); + } + else + { + File file = SPIFFS.open("/mqtt_ssl.ca"); + if (!file || file.isDirectory()) { + response.print("Disabled"); + } + else + { + response.print("Enabled"); + response.print("\nMQTT SSL CA: ***"); + File file2 = SPIFFS.open("/mqtt_ssl.crt"); + File file3 = SPIFFS.open("/mqtt_ssl.key"); + response.print("\nMQTT SSL CRT: "); + response.print((!file2 || file2.isDirectory()) ? "Not set" : "***"); + response.print("\nMQTT SSL Key: "); + response.print((!file3 || file3.isDirectory()) ? "Not set" : "***"); + file2.close(); + file3.close(); + } + file.close(); + } + } + else + { + response.print("Disabled"); + } response.print("\n\n------------ BLUETOOTH ------------"); response.print("\nBluetooth TX power (dB): "); response.print(_preferences->getInt(preference_ble_tx_power, 9)); diff --git a/src/main.cpp b/src/main.cpp index 2961335..0030497 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -249,6 +249,19 @@ void networkTask(void *pvParameters) #ifndef NUKI_HUB_UPDATER void nukiTask(void *pvParameters) { + if (preferences->getBool(preference_mqtt_ssl_enabled, false)) + { + #ifdef CONFIG_SOC_SPIRAM_SUPPORTED + if (esp_psram_get_size() <= 0) + { + Log->println("Waiting 20 seconds to start BLE because of MQTT SSL"); + delay(20000); + } + #else + Log->println("Waiting 20 seconds to start BLE because of MQTT SSL"); + delay(20000); + #endif + } int64_t nukiLoopTs = 0; bool whiteListed = false; while(true) @@ -572,15 +585,13 @@ void setup() } else { - char cert[4400] = {0}; - Log->println("Reading http_ssl.crt"); - uint32_t i = 0; - while(file.available()){ - cert[i] = file.read(); - i++; - } + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); file.close(); + cert[filesize] = '\0'; File file2 = SPIFFS.open("/http_ssl.key"); if (!file2 || file2.isDirectory()) { @@ -589,15 +600,13 @@ void setup() } else { - char key[2200] = {0}; - Log->println("Reading http_ssl.key"); - i = 0; - while(file2.available()){ - key[i] = file2.read(); - i++; - } + size_t filesize2 = file2.size(); + char key[filesize2 + 1]; + + file2.read((uint8_t *)key, sizeof(key)); file2.close(); + key[filesize2] = '\0'; psychicSSLServer = new PsychicHttpsServer; psychicSSLServer->ssl_config.httpd.max_open_sockets = 8; @@ -738,15 +747,13 @@ void setup() } else { - char cert[4400] = {0}; - Log->println("Reading http_ssl.crt"); - uint32_t i = 0; - while(file.available()){ - cert[i] = file.read(); - i++; - } + size_t filesize = file.size(); + char cert[filesize + 1]; + + file.read((uint8_t *)cert, sizeof(cert)); file.close(); + cert[filesize] = '\0'; File file2 = SPIFFS.open("/http_ssl.key"); if (!file2 || file2.isDirectory()) { @@ -755,15 +762,13 @@ void setup() } else { - char key[2200] = {0}; - Log->println("Reading http_ssl.key"); - i = 0; - while(file2.available()){ - key[i] = file2.read(); - i++; - } + size_t filesize2 = file2.size(); + char key[filesize2 + 1]; + + file2.read((uint8_t *)key, sizeof(key)); file2.close(); + key[filesize2] = '\0'; psychicSSLServer = new PsychicHttpsServer; psychicSSLServer->ssl_config.httpd.max_open_sockets = 8; diff --git a/src/networkDevices/NetworkDevice.cpp b/src/networkDevices/NetworkDevice.cpp index 36d1e48..feaf87a 100644 --- a/src/networkDevices/NetworkDevice.cpp +++ b/src/networkDevices/NetworkDevice.cpp @@ -3,30 +3,71 @@ #include "../Logger.h" #ifndef NUKI_HUB_UPDATER +#include "FS.h" +#include "SPIFFS.h" #include "../MqttTopics.h" #include "PreferencesKeys.h" void NetworkDevice::init() { - size_t caLength = _preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE); - size_t crtLength = _preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE); - size_t keyLength = _preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE); - - _useEncryption = caLength > 1; // length is 1 when empty - - if(_useEncryption) - { - Log->println(F("MQTT over TLS.")); - _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO); - _mqttClientSecure->setCACert(_ca); - if(crtLength > 1 && keyLength > 1) // length is 1 when empty + if(_preferences->getBool(preference_mqtt_ssl_enabled, false)) { + if (!SPIFFS.begin(true)) { + Log->println("SPIFFS Mount Failed"); + } + else { - Log->println(F("MQTT with client certificate.")); - _mqttClientSecure->setCertificate(_cert); - _mqttClientSecure->setPrivateKey(_key); + File file = SPIFFS.open("/mqtt_ssl.ca"); + if (!file || file.isDirectory()) { + Log->println("mqtt_ssl.ca not found"); + } + else + { + Log->println("Reading mqtt_ssl.ca"); + String ca_cert = file.readString(); + file.close(); + char* caDest; + caDest = (char *)malloc(sizeof(char) * (ca_cert.length()+1)); + strcpy(caDest, ca_cert.c_str()); + + if(ca_cert.length() > 1) + { + _useEncryption = true; + Log->println(F("MQTT over TLS.")); + _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO); + _mqttClientSecure->setCACert(caDest); + + File file2 = SPIFFS.open("/mqtt_ssl.crt"); + File file3 = SPIFFS.open("/mqtt_ssl.key"); + if (!file2 || file2.isDirectory() || !file3 || file3.isDirectory()) { + Log->println("mqtt_ssl.crt or mqtt_ssl.key not found"); + } + else + { + String cert = file2.readString(); + file2.close(); + char* certDest; + certDest = (char *)malloc(sizeof(char) * (cert.length()+1)); + strcpy(certDest, cert.c_str()); + + String key = file3.readString(); + file3.close(); + char* keyDest; + keyDest = (char *)malloc(sizeof(char) * (key.length()+1)); + strcpy(keyDest, key.c_str()); + + if(cert.length() > 1 && key.length() > 1) + { + Log->println(F("MQTT with client certificate.")); + _mqttClientSecure->setCertificate(certDest); + _mqttClientSecure->setPrivateKey(keyDest); + } + } + } + } } } - else + + if (!_useEncryption) { Log->println(F("MQTT without TLS.")); _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO); diff --git a/src/networkDevices/NetworkDevice.h b/src/networkDevices/NetworkDevice.h index 7e99eef..d2d19a3 100644 --- a/src/networkDevices/NetworkDevice.h +++ b/src/networkDevices/NetworkDevice.h @@ -64,9 +64,6 @@ protected: bool _useEncryption = false; bool _mqttEnabled = true; char* _path; - char _ca[TLS_CA_MAX_SIZE] = {0}; - char _cert[TLS_CERT_MAX_SIZE] = {0}; - char _key[TLS_KEY_MAX_SIZE] = {0}; #endif const String _hostname;