Просмотр исходного кода

Add Web Interface and REST auth (#3436)

* Ported https://github.com/jomjol/AI-on-the-edge-device/pull/2241 to latest main and extended it for all REST APIs

* .

* fix compile errors

* .

* .

* Update Changelog.md

* Update Changelog.md

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: michael <Heinrich-Tuning@web.de>
CaCO3 1 год назад
Родитель
Сommit
2986c6122d

+ 21 - 2
Changelog.md

@@ -1,3 +1,22 @@
+## [16.0.0-RC6] - 2024-xx-xx
+
+For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0)
+
+#### Known issues
+Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
+[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
+
+#### Core Changes
+Only changes since RC5 are listed:
+- Added basic authentification of the Web Interface and the REST API, see https://jomjol.github.io/AI-on-the-edge-device-docs/Password-Protection/
+- xxx
+
+  **:warning: Please check your Homeassistant instance to make sure it is handled correctly!**
+
+#### Bug Fixes
+Only changes since RC5 are listed:
+ - xxx
+
 ## [16.0.0-RC5] - 2024-12-05
 
 For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0)
@@ -22,11 +41,11 @@ Only changes since RC4 are listed:
   **:warning: Please check your Homeassistant instance to make sure it is handled correctly!**
 
 #### Bug Fixes
-Only changes since RC3 are listed:
+Only changes since RC4 are listed:
  - Added fix for ledintensity (#3418)
  - Added fix for OV2640 brightness contrast saturation (#3417)
  - Added fix for 'AnalogToDigitTransitionStart' always using 9.2 regardless of the configured value (#3393)
- - Addef fix for HA menu entry (#3342)
+ - Added fix for HA menu entry (#3342)
 
 
 ## [16.0.0-RC4] - 2024-10-06

+ 2 - 1
code/components/jomjol_controlGPIO/server_GPIO.cpp

@@ -25,6 +25,7 @@
 #include "server_mqtt.h"
 #endif //ENABLE_MQTT
 
+#include "basic_auth.h"
 
 static const char *TAG = "GPIO";
 QueueHandle_t gpio_queue_handle = NULL;
@@ -458,7 +459,7 @@ void GpioHandler::registerGpioUri()
     httpd_uri_t camuri = { };
     camuri.method    = HTTP_GET;
     camuri.uri       = "/GPIO";
-    camuri.handler   = callHandleHttpRequest;
+    camuri.handler   = APPLY_BASIC_AUTH_FILTER(callHandleHttpRequest);
     camuri.user_ctx  = (void*)this;    
     httpd_register_uri_handler(_httpServer, &camuri);
 }

+ 7 - 5
code/components/jomjol_controlcamera/server_camera.cpp

@@ -10,6 +10,8 @@
 #include "ClassLogFile.h"
 #include "esp_log.h"
 
+#include "basic_auth.h"
+
 #include "../../include/defines.h"
 
 static const char *TAG = "server_cam";
@@ -280,27 +282,27 @@ void register_server_camera_uri(httpd_handle_t server)
     camuri.method = HTTP_GET;
 
     camuri.uri = "/lighton";
-    camuri.handler = handler_lightOn;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_lightOn);
     camuri.user_ctx = (void *)"Light On";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/lightoff";
-    camuri.handler = handler_lightOff;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_lightOff);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/capture";
-    camuri.handler = handler_capture;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture);
     camuri.user_ctx = NULL;
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/capture_with_flashlight";
-    camuri.handler = handler_capture_with_light;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture_with_light);
     camuri.user_ctx = NULL;
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/save";
-    camuri.handler = handler_capture_save_to_file;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_capture_save_to_file);
     camuri.user_ctx = NULL;
     httpd_register_uri_handler(server, &camuri);
 }

+ 8 - 7
code/components/jomjol_fileserver_ota/server_file.cpp

@@ -46,6 +46,7 @@ extern "C" {
 
 #include "Helper.h"
 #include "miniz.h"
+#include "basic_auth.h"
 
 static const char *TAG = "OTA FILE";
 
@@ -1174,7 +1175,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_download = {
         .uri       = "/fileserver*",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = download_get_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(download_get_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_download);
@@ -1183,7 +1184,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_datafileact = {
         .uri       = "/datafileact",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = datafileact_get_full_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(datafileact_get_full_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_datafileact);
@@ -1192,7 +1193,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_datafile_last_part_handle = {
         .uri       = "/data",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = datafileact_get_last_part_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(datafileact_get_last_part_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_datafile_last_part_handle);
@@ -1200,7 +1201,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_logfileact = {
         .uri       = "/logfileact",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = logfileact_get_full_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(logfileact_get_full_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_logfileact);
@@ -1209,7 +1210,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_logfile_last_part_handle = {
         .uri       = "/log",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = logfileact_get_last_part_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(logfileact_get_last_part_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_logfile_last_part_handle);
@@ -1219,7 +1220,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_upload = {
         .uri       = "/upload/*",   // Match all URIs of type /upload/path/to/file
         .method    = HTTP_POST,
-        .handler   = upload_post_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(upload_post_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_upload);
@@ -1228,7 +1229,7 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t file_delete = {
         .uri       = "/delete/*",   // Match all URIs of type /delete/path/to/file
         .method    = HTTP_POST,
-        .handler   = delete_post_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(delete_post_handler),
         .user_ctx  = server_data    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_delete);

+ 3 - 2
code/components/jomjol_fileserver_ota/server_ota.cpp

@@ -42,6 +42,7 @@ https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/rel
 
 #include "Helper.h"
 #include "statusled.h"
+#include "basic_auth.h"
 #include "../../include/defines.h"
 
 /*an ota data write buffer ready to write to the flash*/
@@ -690,13 +691,13 @@ void register_server_ota_sdcard_uri(httpd_handle_t server)
     httpd_uri_t camuri = { };
     camuri.method    = HTTP_GET;
     camuri.uri       = "/ota";
-    camuri.handler   = handler_ota_update;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_ota_update);
     camuri.user_ctx  = (void*) "Do OTA";    
     httpd_register_uri_handler(server, &camuri);
 
     camuri.method    = HTTP_GET;
     camuri.uri       = "/reboot";
-    camuri.handler   = handler_reboot;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_reboot);
     camuri.user_ctx  = (void*) "Reboot";    
     httpd_register_uri_handler(server, &camuri);
 

+ 1 - 0
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -26,6 +26,7 @@ extern "C" {
 
 #include "server_help.h"
 #include "MainFlowControl.h"
+#include "basic_auth.h"
 #include "../../include/defines.h"
 
 static const char* TAG = "FLOWCTRL";

+ 21 - 20
code/components/jomjol_flowcontroll/MainFlowControl.cpp

@@ -27,6 +27,7 @@
 #include "read_wlanini.h"
 #include "connect_wlan.h"
 #include "psram.h"
+#include "basic_auth.h"
 
 // support IDF 5.x
 #ifndef portTICK_RATE_MS
@@ -1782,108 +1783,108 @@ void register_server_main_flow_task_uri(httpd_handle_t server)
     camuri.method = HTTP_GET;
 
     camuri.uri = "/doinit";
-    camuri.handler = handler_init;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_init);
     camuri.user_ctx = (void *)"Light On";
     httpd_register_uri_handler(server, &camuri);
 
     // Legacy API => New: "/setPreValue"
     camuri.uri = "/setPreValue.html";
-    camuri.handler = handler_prevalue;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_prevalue);
     camuri.user_ctx = (void *)"Prevalue";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/setPreValue";
-    camuri.handler = handler_prevalue;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_prevalue);
     camuri.user_ctx = (void *)"Prevalue";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/flow_start";
-    camuri.handler = handler_flow_start;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_flow_start);
     camuri.user_ctx = (void *)"Flow Start";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/statusflow.html";
-    camuri.handler = handler_statusflow;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_statusflow);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/statusflow";
-    camuri.handler = handler_statusflow;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_statusflow);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     // Legacy API => New: "/cpu_temperature"
     camuri.uri = "/cputemp.html";
-    camuri.handler = handler_cputemp;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_cputemp);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/cpu_temperature";
-    camuri.handler = handler_cputemp;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_cputemp);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     // Legacy API => New: "/rssi"
     camuri.uri = "/rssi.html";
-    camuri.handler = handler_rssi;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_rssi);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/rssi";
-    camuri.handler = handler_rssi;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_rssi);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/date";
-    camuri.handler = handler_current_date;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_current_date);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/uptime";
-    camuri.handler = handler_uptime;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_uptime);
     camuri.user_ctx = (void *)"Light Off";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/editflow";
-    camuri.handler = handler_editflow;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_editflow);
     camuri.user_ctx = (void *)"EditFlow";
     httpd_register_uri_handler(server, &camuri);
 
     // Legacy API => New: "/value"
     camuri.uri = "/value.html";
-    camuri.handler = handler_wasserzaehler;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
     camuri.user_ctx = (void *)"Value";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/value";
-    camuri.handler = handler_wasserzaehler;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
     camuri.user_ctx = (void *)"Value";
     httpd_register_uri_handler(server, &camuri);
 
     // Legacy API => New: "/value"
     camuri.uri = "/wasserzaehler.html";
-    camuri.handler = handler_wasserzaehler;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_wasserzaehler);
     camuri.user_ctx = (void *)"Wasserzaehler";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/json";
-    camuri.handler = handler_json;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_json);
     camuri.user_ctx = (void *)"JSON";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/heap";
-    camuri.handler = handler_get_heap;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_get_heap);
     camuri.user_ctx = (void *)"Heap";
     httpd_register_uri_handler(server, &camuri);
 
     camuri.uri = "/stream";
-    camuri.handler = handler_stream;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_stream);
     camuri.user_ctx = (void *)"stream";
     httpd_register_uri_handler(server, &camuri);
 
     /** will handle metrics requests */
     camuri.uri = "/metrics";
-    camuri.handler = handler_openmetrics;
+    camuri.handler = APPLY_BASIC_AUTH_FILTER(handler_openmetrics);
     camuri.user_ctx = (void *)"metrics";
     httpd_register_uri_handler(server, &camuri);
 

+ 2 - 1
code/components/jomjol_mqtt/server_mqtt.cpp

@@ -12,6 +12,7 @@
 #include "interface_mqtt.h"
 #include "time_sntp.h"
 #include "../../include/defines.h"
+#include "basic_auth.h"
 
 
 
@@ -347,7 +348,7 @@ void register_server_mqtt_uri(httpd_handle_t server) {
     uri.method    = HTTP_GET;
 
     uri.uri       = "/mqtt_publish_discovery";
-    uri.handler   = scheduleSendingDiscovery_and_static_Topics;
+    uri.handler = APPLY_BASIC_AUTH_FILTER(scheduleSendingDiscovery_and_static_Topics);
     uri.user_ctx  = (void*) "";    
     httpd_register_uri_handler(server, &uri); 
 }

+ 107 - 0
code/components/jomjol_wlan/basic_auth.cpp

@@ -0,0 +1,107 @@
+#include "basic_auth.h"
+#include "read_wlanini.h"
+#include <esp_tls_crypto.h>
+#include <esp_log.h>
+
+
+#define HTTPD_401 "401 UNAUTHORIZED"
+
+static const char *TAG = "HTTPAUTH";
+
+typedef struct {
+    const char *username;
+    const char *password;
+} basic_auth_info_t;
+
+basic_auth_info_t basic_auth_info = { NULL, NULL };
+
+void init_basic_auth() {
+    if (!wlan_config.http_username.empty() && !wlan_config.http_password.empty()) {
+        basic_auth_info.username = wlan_config.http_username.c_str();
+        basic_auth_info.password = wlan_config.http_password.c_str();
+    }
+}
+
+static char *http_auth_basic(const char *username, const char *password)
+{
+    int out;
+    char *user_info = NULL;
+    char *digest = NULL;
+    size_t n = 0;
+    asprintf(&user_info, "%s:%s", username, password);
+    if (!user_info) {
+        ESP_LOGE(TAG, "No enough memory for user information");
+        return NULL;
+    }
+    esp_crypto_base64_encode(NULL, 0, &n, (const unsigned char *)user_info, strlen(user_info));
+
+    /* 6: The length of the "Basic " string
+     * n: Number of bytes for a base64 encode format
+     * 1: Number of bytes for a reserved which be used to fill zero
+    */
+    digest = static_cast<char*>(calloc(1, 6 + n + 1));
+    if (digest) {
+        strcpy(digest, "Basic ");
+        esp_crypto_base64_encode((unsigned char *)digest + 6, n, (size_t *)&out, (const unsigned char *)user_info, strlen(user_info));
+    }
+    free(user_info);
+    return digest;
+}
+
+esp_err_t basic_auth_request_filter(httpd_req_t *req, esp_err_t original_handler(httpd_req_t *))
+{
+    char *buf = NULL;
+    size_t buf_len = 0;
+    esp_err_t ret = ESP_OK;
+
+    char unauthorized[] = "You are not authorized to use this website!";
+
+    if (basic_auth_info.username == NULL || basic_auth_info.password == NULL) {
+        ret = original_handler(req);
+    } else {
+        buf_len = httpd_req_get_hdr_value_len(req, "Authorization") + 1;
+        if (buf_len > 1) {
+            buf = static_cast<char*>(calloc(1, buf_len));
+            if (!buf) {
+                ESP_LOGE(TAG, "No enough memory for basic authorization");
+                return ESP_ERR_NO_MEM;
+            }
+
+            if (httpd_req_get_hdr_value_str(req, "Authorization", buf, buf_len) == ESP_OK) {
+                ESP_LOGI(TAG, "Found header => Authorization: %s", buf);
+            } else {
+                ESP_LOGE(TAG, "No auth value received");
+            }
+
+            char *auth_credentials = http_auth_basic(basic_auth_info.username, basic_auth_info.password);
+            if (!auth_credentials) {
+                ESP_LOGE(TAG, "No enough memory for basic authorization credentials");
+                free(buf);
+                return ESP_ERR_NO_MEM;
+            }
+
+            if (strncmp(auth_credentials, buf, buf_len)) {
+                ESP_LOGE(TAG, "Not authenticated");
+                httpd_resp_set_status(req, HTTPD_401);
+                httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
+                httpd_resp_set_hdr(req, "Connection", "keep-alive");
+                httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"AIOTED\"");
+                httpd_resp_send(req, unauthorized, strlen(unauthorized));
+            } else {
+                ESP_LOGI(TAG, "Authenticated calling http handler now!");
+                ret=original_handler(req);
+            }
+            free(auth_credentials);
+            free(buf);
+        } else {
+            ESP_LOGE(TAG, "No auth header received");
+            httpd_resp_set_status(req, HTTPD_401);
+            httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
+            httpd_resp_set_hdr(req, "Connection", "keep-alive");
+            httpd_resp_set_hdr(req, "WWW-Authenticate", "Basic realm=\"AIOTED\"");
+            httpd_resp_send(req, unauthorized, strlen(unauthorized));
+        }
+    }
+
+    return ret;
+}

+ 8 - 0
code/components/jomjol_wlan/basic_auth.h

@@ -0,0 +1,8 @@
+#pragma once
+
+#include <esp_http_server.h>
+
+void init_basic_auth();
+esp_err_t basic_auth_request_filter(httpd_req_t *req, esp_err_t original_handler(httpd_req_t *));
+
+#define APPLY_BASIC_AUTH_FILTER(method) [](httpd_req_t *req){ return basic_auth_request_filter(req, method); }

+ 23 - 0
code/components/jomjol_wlan/read_wlanini.cpp

@@ -145,6 +145,29 @@ int LoadWlanFromFile(std::string fn)
                 wlan_config.dns = tmp;
                 LogFile.WriteToFile(ESP_LOG_INFO, TAG, "DNS: " + wlan_config.dns);
             }
+
+            else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HTTP_USERNAME")){
+                tmp = splitted[1];
+                if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){
+                    tmp = tmp.substr(1, tmp.length()-2);
+                }
+                wlan_config.http_username = tmp;
+                LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_USERNAME: " + wlan_config.http_username);
+            }
+
+            else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HTTP_PASSWORD")){
+                tmp = splitted[1];
+                if ((tmp[0] == '"') && (tmp[tmp.length()-1] == '"')){
+                    tmp = tmp.substr(1, tmp.length()-2);
+                }
+                wlan_config.http_password = tmp;
+                #ifndef __HIDE_PASSWORD
+                LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_PASSWORD: " + wlan_config.http_password);
+                #else
+                LogFile.WriteToFile(ESP_LOG_INFO, TAG, "HTTP_PASSWORD: XXXXXXXX");
+                #endif
+            }
+
             #if (defined WLAN_USE_ROAMING_BY_SCANNING || (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES))
             else if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHRESHOLD")){
                 tmp = trim(splitted[1]);

+ 2 - 0
code/components/jomjol_wlan/read_wlanini.h

@@ -13,6 +13,8 @@ struct wlan_config {
     std::string gateway = "";
     std::string netmask = "";
     std::string dns = "";
+    std::string http_username = "";
+    std::string http_password = "";
     int rssi_threshold = 0;                 // Default: 0 -> ROAMING disabled
 };
 extern struct wlan_config wlan_config;

+ 4 - 0
code/main/main.cpp

@@ -33,6 +33,8 @@
 #include "configFile.h"
 #include "server_main.h"
 #include "server_camera.h"
+#include "basic_auth.h"
+
 #ifdef ENABLE_MQTT
     #include "server_mqtt.h"
 #endif //ENABLE_MQTT
@@ -429,6 +431,8 @@ extern "C" void app_main(void)
             StatusLED(WLAN_INIT, 3, true);
             return;
         }
+
+        init_basic_auth();
     }
     else if (iWLANStatus == -1) {  // wlan.ini not available, potentially empty or content not readable
         StatusLED(WLAN_INIT, 1, true);

+ 6 - 5
code/main/server_main.cpp

@@ -17,6 +17,7 @@
 
 #include "MainFlowControl.h"
 #include "esp_log.h"
+#include "basic_auth.h"
 #include "esp_chip_info.h"
 
 #include <stdio.h>
@@ -408,7 +409,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t info_get_handle = {
         .uri       = "/info",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = info_get_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(info_get_handler),
         .user_ctx  = (void*) base_path    // Pass server data as context
     };
     httpd_register_uri_handler(server, &info_get_handle);
@@ -416,7 +417,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t sysinfo_handle = {
         .uri       = "/sysinfo",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = sysinfo_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(sysinfo_handler),
         .user_ctx  = (void*) base_path    // Pass server data as context
     };
     httpd_register_uri_handler(server, &sysinfo_handle);
@@ -424,7 +425,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t starttime_tmp_handle = {
         .uri       = "/starttime",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = starttime_get_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(starttime_get_handler),
         .user_ctx  = NULL    // Pass server data as context
     };
     httpd_register_uri_handler(server, &starttime_tmp_handle);
@@ -432,7 +433,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t img_tmp_handle = {
         .uri       = "/img_tmp/*",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = img_tmp_virtual_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(img_tmp_virtual_handler),
         .user_ctx  = (void*) base_path    // Pass server data as context
     };
     httpd_register_uri_handler(server, &img_tmp_handle);
@@ -440,7 +441,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
     httpd_uri_t main_rest_handle = {
         .uri       = "/*",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = hello_main_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(hello_main_handler),
         .user_ctx  = (void*) base_path    // Pass server data as context
     };
     httpd_register_uri_handler(server, &main_rest_handle);

+ 5 - 4
code/main/softAP.cpp

@@ -29,6 +29,7 @@
 #include "Helper.h"
 #include "statusled.h"
 #include "server_ota.h"
+#include "basic_auth.h"
 
 #include "lwip/err.h"
 #include "lwip/sys.h"
@@ -468,7 +469,7 @@ httpd_handle_t start_webserverAP(void)
     httpd_uri_t reboot_handle = {
         .uri       = "/reboot",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = reboot_handlerAP,
+        .handler = APPLY_BASIC_AUTH_FILTER(reboot_handlerAP),
         .user_ctx  = NULL    // Pass server data as context
     };
     httpd_register_uri_handler(server, &reboot_handle);
@@ -476,7 +477,7 @@ httpd_handle_t start_webserverAP(void)
     httpd_uri_t config_ini_handle = {
         .uri       = "/config",  // Match all URIs of type /path/to/file
         .method    = HTTP_GET,
-        .handler   = config_ini_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(config_ini_handler),
         .user_ctx  = NULL    // Pass server data as context
     };
     httpd_register_uri_handler(server, &config_ini_handle);
@@ -485,7 +486,7 @@ httpd_handle_t start_webserverAP(void)
     httpd_uri_t file_uploadAP = {
         .uri       = "/upload/*",   // Match all URIs of type /upload/path/to/file
         .method    = HTTP_POST,
-        .handler   = upload_post_handlerAP,
+        .handler = APPLY_BASIC_AUTH_FILTER(upload_post_handlerAP),
         .user_ctx  = NULL    // Pass server data as context
     };
     httpd_register_uri_handler(server, &file_uploadAP);
@@ -493,7 +494,7 @@ httpd_handle_t start_webserverAP(void)
     httpd_uri_t test_uri = {
         .uri      = "*",
         .method   = HTTP_GET,
-        .handler  = test_handler,
+        .handler = APPLY_BASIC_AUTH_FILTER(test_handler),
         .user_ctx = NULL
     };
     httpd_register_uri_handler(server, &test_uri);

+ 11 - 0
sd-card/wlan.ini

@@ -36,3 +36,14 @@ password = ""
 ; Default: 0 = Disable client requested roaming query
 
 RSSIThreshold = 0
+
+;++++++++++++++++++++++++++++++++++
+; Password Protection of the Web Interface and the REST API
+; When those parameters are active, the Web Interface and the REST API are protected by a username and password.
+; Note: This is be a WEAK and INSECURE way to protect the Web Interface and the REST API.
+;       There was no audit nor a security review to check the correct implementation of the protection!
+;       The password gets transmitted unencrypted (plain text), this means it is very easy to extract it
+;       for somebody who has access to your WIFI!
+;       USE AT YOUR OWN RISK!
+;http_username = "myusername"
+;http_password = "mypassword"