Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reset of configuration if http auth fails ("forgotten paswword") #1240

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 25 additions & 9 deletions src/httpserver/http_basic_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@
#include "../new_cfg.h"

#define LOG_FEATURE LOG_FEATURE_HTTP
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
int g_auth_fail = 0;
#endif

int http_basic_auth_unauth(http_request_t* request) {
poststr(request, "HTTP/1.1 401 Unauthorized\r\n");
poststr(request, "Connection: close");
poststr(request, "\r\n");
poststr(request, "WWW-Authenticate: Basic realm=\"OpenBeken HTTP Server\"");
poststr(request, "\r\n");
poststr(request, "\r\n");
poststr(request, NULL);
return 0;
}

int http_basic_auth_eval(http_request_t *request) {
#if ALLOW_WEB_PASSWORD
Expand Down Expand Up @@ -40,17 +54,19 @@ int http_basic_auth_eval(http_request_t *request) {
return HTTP_BASIC_AUTH_OK;
#endif
}

int http_basic_auth_run(http_request_t *request) {
int result = http_basic_auth_eval(request);
if (result == HTTP_BASIC_AUTH_FAIL) {
poststr(request, "HTTP/1.1 401 Unauthorized\r\n");
poststr(request, "Connection: close");
poststr(request, "\r\n");
poststr(request, "WWW-Authenticate: Basic realm=\"OpenBeken HTTP Server\"");
poststr(request, "\r\n");
poststr(request, "\r\n");
poststr(request, NULL);
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
if (CFG_HasFlag(OBK_FLAG_RESETCFG_DISABLED)!=1){
if (g_auth_fail > -99) g_auth_fail++; // just in case there are further attemps after enabling reset, don't overwrite "magic"
if (g_auth_fail > FAILED_AUTH_ATTEMPTS && g_secondsElapsed < TIME_TO_RESET_CFG_AFTER_STARTUP){
g_auth_fail=-99; // "magic" to allow cfg reset
return result;
}
}
#endif
http_basic_auth_unauth(request);
}
return result;
}
}
7 changes: 5 additions & 2 deletions src/httpserver/http_basic_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@

int http_basic_auth_eval(http_request_t *request);
int http_basic_auth_run(http_request_t *request);

#endif
int http_basic_auth_unauth(http_request_t* request);
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
extern int g_auth_fail; // count number of auth failures, set to -99 as a magic to allow config reset
#endif
#endif
53 changes: 48 additions & 5 deletions src/httpserver/http_fns.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,27 @@ int http_fn_testmsg(http_request_t* request) {

}

#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
int http_fn_reset_cfg(http_request_t* request) {
if (g_secondsElapsed > TIME_TO_RESET_CFG_AFTER_STARTUP) return 0; // just to be safe
http_setup(request, httpMimeTypeHTML);
http_html_start(request, "Restore factory defaults");
poststr_h2(request, "Do you want to reset your device to factory defaults?");
hprintf255(request,"<h5>If you lost your password, you can reset your device to factory defaults</h5>");
extern int g_auth_fail; // defined in http_basic_auth
g_auth_fail=-1*(rand() % 10000 + 100 ); // we want a negative number from -10000 to -100 (as a simple security measure)
hprintf255(request, "<form action=\"\" onsubmit=\"return prompt('To erase the configuration and restart your enter YES','no')=='YES';\">");
hprintf255(request, "<input type=\"hidden\" name=\"resetmagic\" value=\"%i\"/>", g_auth_fail);
hprintf255(request, "<input type=\"submit\" value=\"Reset module settings to defaults\"/></form>");
hprintf255(request, "<form action=\"\">");
hprintf255(request, "<input type=\"hidden\" name=\"authfailcont\" value=\"%i\"/>", g_auth_fail);
hprintf255(request, "<input type=\"submit\" value=\"Just retry - I know the password\"/></form>");
poststr(request, htmlBodyEnd); // don't use html_end, this will reload page after some seconds making this page at least hard to use ...
poststr(request, NULL);
return 0;
}
#endif

// bit mask telling which channels are hidden from HTTP
// If given bit is set, then given channel is hidden
extern int g_hiddenChannels;
Expand Down Expand Up @@ -1247,7 +1268,18 @@ int http_fn_cfg_wifi(http_request_t* request) {
poststr_h2(request, "Web Authentication");
poststr(request, "<p>Enabling web authentication will protect this web interface and API using basic HTTP authentication. Username is always <b>admin</b>.</p>");
hprintf255(request, "<div><input type=\"checkbox\" name=\"web_admin_password_enabled\" id=\"web_admin_password_enabled\" value=\"1\"%s>", (web_password_enabled > 0 ? " checked" : ""));
poststr(request, "<label for=\"web_admin_password_enabled\">Enable web authentication</label></div>");
poststr(request, "<label for=\"web_admin_password_enabled\">Enable web authentication</label>");
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
poststr(request, "<span style=\"float:right;\">");
poststr(request, "<input type=\"checkbox\" name=\"resetDis\" id=\"resetDis\" ");
// this checkbos is probaly hard to understand, so I added some explanation
// but this will take some valuable bytes of size, so it might be deleted ...
poststr(request, "title='If you lost web password, configuration can be reset to factory defaults during the first minutes after startup. ");
poststr(request, "If you have security concerns, this can be disabled here. But be sure, not to lose your password!' ");
hprintf255(request, "value=\"1\"%s>", (CFG_HasFlag(OBK_FLAG_RESETCFG_DISABLED) > 0 ? " checked" : ""));
poststr(request, "<label for=\"resetDis\">Disable possible reset of configuration</label>");
#endif
poststr(request, "</div>");
add_label_password_field(request, "Admin Password", "web_admin_password", CFG_GetWebPassword(), "");
#endif
poststr(request, "<br><br>\
Expand Down Expand Up @@ -1331,15 +1363,26 @@ int http_fn_cfg_wifi_set(http_request_t* request) {
if (web_password_enabled > 0 && http_getArg(request->url, "web_admin_password", tmpA, sizeof(tmpA))) {
if (strlen(tmpA) < 5) {
poststr_h4(request, "Web password needs to be at least 5 characters long!");
} else {
} else if (strcmp(CFG_GetWebPassword(),tmpA) != 0){
poststr(request, "<p>Web password has been changed.</p>");
CFG_SetWebPassword(tmpA);
}
}
} else {
CFG_SetWebPassword("");
if (strcmp(CFG_GetWebPassword(),"") != 0){
CFG_SetWebPassword("");
poststr(request, "<p>Web password has been disabled.</p>");
}
}
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
int dis_resetcfg = (http_getArg(request->url, "resetDis", tmpA, sizeof(tmpA))) ? 1 : 0;
if (dis_resetcfg != CFG_HasFlag(OBK_FLAG_RESETCFG_DISABLED)){
CFG_SetFlag(OBK_FLAG_RESETCFG_DISABLED, dis_resetcfg);
CFG_Save_IfThereArePendingChanges();
hprintf255(request, "<p>%sabled possible reset of configuration.</p>",dis_resetcfg==1 ? "Dis" : "En");
}
#endif
#endif // ENABLE_OBK_AUTHFAIL_CONFIGRESET
#endif // ALLOW_WEB_PASSWORD
CFG_Save_SetupTimer();
if (bChanged == 0) {
poststr(request, "<p>WiFi: No changes detected.</p>");
Expand Down Expand Up @@ -2600,7 +2643,7 @@ const char* g_obk_flagNames[] = {
"[TuyaMCU] Store raw data",
"[TuyaMCU] Store ALL data",
"[PWR] Invert AC dir",
"error",
"[HTTP] Disable password recovery (= clear configuration) directly after startup (please see documentation)",
"error",
"error",
};
Expand Down
3 changes: 3 additions & 0 deletions src/httpserver/http_fns.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ int http_fn_startup_command(http_request_t* request);
int http_fn_cfg_generic(http_request_t* request);
int http_fn_cfg_startup(http_request_t* request);
int http_fn_cfg_dgr(http_request_t* request);
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
int http_fn_reset_cfg(http_request_t* request);
#endif
22 changes: 21 additions & 1 deletion src/httpserver/new_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include "../new_cfg.h"
#include "../ota/ota.h"
#include "../hal/hal_wifi.h"
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
#include "../hal/hal_generic.h" // for HAL_RebootModule();
#endif
#include "../base64/base64.h"
#include "http_basic_auth.h"

Expand Down Expand Up @@ -737,7 +740,24 @@ int HTTP_ProcessPacket(http_request_t* request) {
}

if (http_basic_auth_run(request) == HTTP_BASIC_AUTH_FAIL) {
return 0;
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
if (g_auth_fail>-99 || g_secondsElapsed > TIME_TO_RESET_CFG_AFTER_STARTUP){ //-99 is our "magic" to allow reset
#endif
return 0;
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
}
if (http_getArgInteger(request->url, "resetmagic") == g_auth_fail){
CFG_SetDefaultConfig();
CFG_Save_IfThereArePendingChanges();
addLogAdv(LOG_INFO, LOG_FEATURE_HTTP, "Going to call HAL_RebootModule\r\n");
HAL_RebootModule();
}
if (http_getArgInteger(request->url, "authfailcont") == g_auth_fail) {
g_auth_fail=0;
return http_basic_auth_unauth(request);
}
return http_fn_reset_cfg(request);
#endif
}

if (http_checkUrlBase(urlStr, "")) return http_fn_empty_url(request);
Expand Down
3 changes: 3 additions & 0 deletions src/httpserver/new_http.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ extern const char htmlHeadMeta[];
extern const char htmlFooterReturnToMainPage[];
extern const char htmlFooterRefreshLink[];
extern const char htmlFooterReturnToCfgOrMainPage[];
#if ENABLE_OBK_AUTHFAIL_CONFIGRESET
extern const char htmlBodyEnd[];
#endif

extern const char* htmlPinRoleNames[];

Expand Down
3 changes: 2 additions & 1 deletion src/new_pins.h
Original file line number Diff line number Diff line change
Expand Up @@ -1055,8 +1055,9 @@ typedef struct pinsState_s {
#define OBK_FLAG_TUYAMCU_STORE_RAW_DATA 46
#define OBK_FLAG_TUYAMCU_STORE_ALL_DATA 47
#define OBK_FLAG_POWER_INVERT_AC 48
#define OBK_FLAG_RESETCFG_DISABLED 49

#define OBK_TOTAL_FLAGS 49
#define OBK_TOTAL_FLAGS 50

#define LOGGER_FLAG_MQTT_DEDUPER 1
#define LOGGER_FLAG_POWER_SAVE 2
Expand Down
13 changes: 13 additions & 0 deletions src/obk_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@
//ENABLE_DRIVER_TUYAMCU - Enable support for TuyaMCU and tmSensor


// settings for possible reset device to defaults after unsuccessful auth retries
// will only work for small time window after a (re)start of a device (configured below)
// enable (or disable) the feature
#define ENABLE_OBK_AUTHFAIL_CONFIGRESET 1

// default time to reset CFG to defaults after startup
// 180 seconds = 3 minutes should be enough
#define TIME_TO_RESET_CFG_AFTER_STARTUP 180
// after this amount of failed auths, display page to reset config (during first TIME_TO_RESET_CFG_AFTER_STARTUP seconds)
#define FAILED_AUTH_ATTEMPTS 5



#if PLATFORM_XR809

#define OBK_DISABLE_ALL_DRIVERS 1
Expand Down
Loading