From d5cecbb5b017349ece28431ed9b44ad724887039 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 10 Feb 2024 13:03:29 +0100 Subject: [PATCH] 0.8.78 * fixed protection --- src/CHANGES.md | 2 +- src/app.h | 12 +++----- src/appInterface.h | 5 ++- src/defines.h | 2 +- src/web/Protection.h | 72 +++++++++++++++++++++----------------------- src/web/RestApi.h | 6 ++-- src/web/web.h | 6 ++-- 7 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index ea067bd2..ce0adc6b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,6 +1,6 @@ # Development Changes -## 0.8.78 - 2024-02-09 +## 0.8.78 - 2024-02-10 * finalized API token access #1415 ## 0.8.77 - 2024-02-08 diff --git a/src/app.h b/src/app.h index 1a4e780d..b16d7aeb 100644 --- a/src/app.h +++ b/src/app.h @@ -247,8 +247,8 @@ class app : public IApp, public ah::Scheduler { #endif } - void lock(void) override { - mProtection->lock(); + void lock(bool fromWeb) override { + mProtection->lock(fromWeb); } char *unlock(const char *clientIp, bool loginFromWeb) override { @@ -259,12 +259,8 @@ class app : public IApp, public ah::Scheduler { mProtection->resetLockTimeout(); } - bool isProtected(void) const override { - return mProtection->isProtected(); - } - - bool isProtected(const char *token, bool askedFromWeb) const override { - return mProtection->isProtected(token, askedFromWeb); + bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const override { + return mProtection->isProtected(clientIp, token, askedFromWeb); } bool getNrfEnabled(void) override { diff --git a/src/appInterface.h b/src/appInterface.h index f0d2b2a0..536455e0 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -61,11 +61,10 @@ class IApp { virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; - virtual void lock(void) = 0; + virtual void lock(bool fromWeb) = 0; virtual char *unlock(const char *clientIp, bool loginFromWeb) = 0; virtual void resetLockTimeout(void) = 0; - virtual bool isProtected(void) const = 0; - virtual bool isProtected(const char *token, bool askedFromWeb) const = 0; + virtual bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const = 0; virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0; virtual uint16_t getHistoryMaxDay() = 0; diff --git a/src/defines.h b/src/defines.h index 46be8dac..ab685698 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 77 +#define VERSION_PATCH 78 //------------------------------------- typedef struct { diff --git a/src/web/Protection.h b/src/web/Protection.h index b9eeef95..7c1ff71e 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -18,12 +18,9 @@ class Protection { explicit Protection(const char *pwd) { mPwd = pwd; mLogoutTimeout = 0; - mLoginIp.fill(0); + mWebIp.fill(0); + mApiIp.fill(0); mToken.fill(0); - - // no password set - unlock - if(pwd[0] == '\0') - mProtected = false; } public: @@ -40,27 +37,30 @@ class Protection { // auto logout if(0 != mLogoutTimeout) { if (0 == --mLogoutTimeout) { - if(mPwd[0] != '\0') { - mProtected = true; - } + if(mPwd[0] != '\0') + lock(false); } } } - void lock(void) { - mProtected = true; - mLoginIp.fill(0); + void lock(bool fromWeb) { + mWebIp.fill(0); + if(fromWeb) + return; + + mApiIp.fill(0); mToken.fill(0); } char *unlock(const char *clientIp, bool loginFromWeb) { mLogoutTimeout = LOGOUT_TIMEOUT; - mProtected = false; if(loginFromWeb) - ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); - else + ah::ip2Arr(static_cast(mWebIp.data()), clientIp); + else { + ah::ip2Arr(static_cast(mApiIp.data()), clientIp); genToken(); + } return reinterpret_cast(mToken.data()); } @@ -70,30 +70,19 @@ class Protection { mLogoutTimeout = LOGOUT_TIMEOUT; } - bool isProtected(void) const { - return mProtected; - } - - bool isProtected(const char *token, bool askedFromWeb) const { // token == clientIp - if(mProtected) - return true; - - if(mPwd[0] == '\0') + bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const { + if(mPwd[0] == '\0') // no password set return false; - if(askedFromWeb) { // check IP address - std::array ip; - ah::ip2Arr(static_cast(ip.data()), token); - for(uint8_t i = 0; i < 4; i++) { - if(mLoginIp[i] != ip[i]) - return true; - } - } else { // API call - check token - if(0 == mToken[0]) // token is zero - return true; + if(askedFromWeb) + return !isIdentical(clientIp, mWebIp); + // API call + if(0 == mToken[0]) // token is zero, from WebUi (logged in) + return !isIdentical(clientIp, mWebIp); + + if(isIdentical(clientIp, mApiIp)) return (0 != strncmp(token, mToken.data(), 16)); - } return false; } @@ -106,18 +95,27 @@ class Protection { if(mToken[i] < 10) mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed) else - mToken[i] += 0x37; // convert to ascii upper case character + mToken[i] += 0x37; // convert to ascii upper case character A-Z } } + bool isIdentical(const char *clientIp, const std::array cmp) const { + std::array ip; + ah::ip2Arr(static_cast(ip.data()), clientIp); + for(uint8_t i = 0; i < 4; i++) { + if(cmp[i] != ip[i]) + return false; + } + return true; + } + protected: static Protection *mInstance; private: const char *mPwd; - bool mProtected = true; uint16_t mLogoutTimeout = 0; - std::array mLoginIp; + std::array mWebIp, mApiIp; std::array mToken; }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 5103f3ba..53b604b5 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -266,7 +266,7 @@ class RestApi { obj[F("modules")] = String(mApp->getVersionModules()); obj[F("build")] = String(AUTO_GIT_HASH); obj[F("env")] = String(ENV_NAME); - obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str(), true); + obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str(), "", true); obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask ); obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0'); obj[F("cst_lnk")] = String(mConfig->plugin.customLink); @@ -844,7 +844,7 @@ class RestApi { if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT const char* token = jsonIn["token"]; - if(mApp->isProtected(token, false)) { + if(mApp->isProtected(clientIP, token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } @@ -897,7 +897,7 @@ class RestApi { if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT const char* token = jsonIn["token"]; - if(mApp->isProtected(token, false)) { + if(mApp->isProtected(clientIP, token, false)) { jsonOut[F("error")] = F(IS_PROTECTED); return false; } diff --git a/src/web/web.h b/src/web/web.h index 7ed41f92..692dd779 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -227,7 +227,7 @@ class Web { } void checkProtection(AsyncWebServerRequest *request) { - if(mApp->isProtected(request->client()->remoteIP().toString().c_str(), true)) { + if(mApp->isProtected(request->client()->remoteIP().toString().c_str(), "", true)) { checkRedirect(request); return; } @@ -328,7 +328,7 @@ class Web { DPRINTLN(DBG_VERBOSE, F("onLogout")); checkProtection(request); - mApp->lock(); + mApp->lock(true); AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); response->addHeader(F("Content-Encoding"), "gzip"); @@ -455,7 +455,7 @@ class Web { // protection if (request->arg("adminpwd") != "{PWD}") { request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN); - mApp->lock(); + mApp->lock(false); } mConfig->sys.protectionMask = 0x0000; for (uint8_t i = 0; i < 7; i++) {