From 15349520d26538cee0dba501ea69b54e7fe8a66f Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 9 Feb 2024 00:05:54 +0100 Subject: [PATCH] 0.8.77 * merge PR: BugFix: ACK #1414 * fix suspicious if condition #1416 * prepared API token for access, not functional #1415 --- src/CHANGES.md | 5 ++++ src/app.cpp | 2 +- src/app.h | 8 +++++-- src/appInterface.h | 3 ++- src/defines.h | 2 +- src/web/Protection.h | 34 ++++++++++++++++++++++++--- src/web/RestApi.h | 55 ++++++++++++++++++++++++++++++++++---------- src/web/lang.h | 10 ++++++-- src/web/web.h | 2 +- 9 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a9301d44d..b75ba2b3f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.77 - 2024-02-08 +* merge PR: BugFix: ACK #1414 +* fix suspicious if condition #1416 +* prepared API token for access, not functional #1415 + ## 0.8.76 - 2024-02-07 * revert changes from yesterday regarding snprintf and its size #1410, #1411 * reduced cppcheck linter warnings significantly diff --git a/src/app.cpp b/src/app.cpp index c93be7778..bee12387d 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -239,7 +239,7 @@ void app::updateNtp(void) { } } - if ((mSunrise == 0) && (mConfig->sun.lat) && (mConfig->sun.lon)) { + if ((0 == mSunrise) && (0.0 != mConfig->sun.lat) && (0.0 != mConfig->sun.lon)) { mCalculatedTimezoneOffset = (int8_t)((mConfig->sun.lon >= 0 ? mConfig->sun.lon + 7.5 : mConfig->sun.lon - 7.5) / 15) * 3600; tickCalcSunrise(); } diff --git a/src/app.h b/src/app.h index 60be4d1d0..be20f26f7 100644 --- a/src/app.h +++ b/src/app.h @@ -251,8 +251,8 @@ class app : public IApp, public ah::Scheduler { mProtection->lock(); } - void unlock(const char *clientIp) override { - mProtection->unlock(clientIp); + char *unlock(const char *clientIp) override { + return mProtection->unlock(clientIp); } void resetLockTimeout(void) override { @@ -267,6 +267,10 @@ class app : public IApp, public ah::Scheduler { return mProtection->isProtected(clientIp); } + bool isProtected(const char *clientIp, const char *token) const override { + return mProtection->isProtected(clientIp, token); + } + bool getNrfEnabled(void) override { return mConfig->nrf.enabled; } diff --git a/src/appInterface.h b/src/appInterface.h index 6703b5bf8..937908e2d 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -62,10 +62,11 @@ class IApp { virtual uint32_t getMqttTxCnt() = 0; virtual void lock(void) = 0; - virtual void unlock(const char *clientIp) = 0; + virtual char *unlock(const char *clientIp) = 0; virtual void resetLockTimeout(void) = 0; virtual bool isProtected(void) const = 0; virtual bool isProtected(const char *clientIp) const = 0; + virtual bool isProtected(const char *clientIp, const char *token) 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 9ea3834c8..46be8dac5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 76 +#define VERSION_PATCH 77 //------------------------------------- typedef struct { diff --git a/src/web/Protection.h b/src/web/Protection.h index 6b079e82f..f62f1380e 100644 --- a/src/web/Protection.h +++ b/src/web/Protection.h @@ -19,6 +19,7 @@ class Protection { mPwd = pwd; mLogoutTimeout = 0; mLoginIp.fill(0); + mToken.fill(0); // no password set - unlock if(pwd[0] == '\0') @@ -50,20 +51,34 @@ class Protection { mLoginIp.fill(0); } - void unlock(const char *clientIp) { + char *unlock(const char *clientIp) { mLogoutTimeout = LOGOUT_TIMEOUT; mProtected = false; ah::ip2Arr(static_cast(mLoginIp.data()), clientIp); + genToken(); + + return reinterpret_cast(mToken.data()); } void resetLockTimeout(void) { - mLogoutTimeout = LOGOUT_TIMEOUT; + if(0 != mLogoutTimeout) + mLogoutTimeout = LOGOUT_TIMEOUT; } bool isProtected(void) const { return mProtected; } + bool isProtected(const char *clientIp, const char *token) const { + if(isProtected(clientIp)) + return true; + + if(0 == mToken[0]) // token is zero + return true; + + return (0 != strncmp(token, mToken.data(), 16)); + } + bool isProtected(const char *clientIp) const { if(mProtected) return true; @@ -81,14 +96,27 @@ class Protection { return false; } + private: + void genToken() { + mToken.fill(0); + for(uint8_t i = 0; i < 16; i++) { + mToken[i] = random(1, 35); + 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 + } + } + protected: static Protection *mInstance; private: const char *mPwd; bool mProtected = true; - uint16_t mLogoutTimeout = LOGOUT_TIMEOUT; + uint16_t mLogoutTimeout = 0; std::array mLoginIp; + std::array mToken; }; #endif /*__PROTECTION_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ce580dd56..59b786d75 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -70,7 +70,7 @@ class RestApi { if(obj[F("path")] == "ctrl") setCtrl(obj, dummy, "*"); else if(obj[F("path")] == "setup") - setSetup(obj, dummy); + setSetup(obj, dummy, "*"); } private: @@ -169,7 +169,7 @@ class RestApi { if(path == "ctrl") root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str()); else if(path == "setup") - root[F("success")] = setSetup(obj, root); + root[F("success")] = setSetup(obj, root, request->client()->remoteIP().toString().c_str()); else { root[F("success")] = false; root[F("error")] = F(PATH_NOT_FOUND) + path; @@ -831,23 +831,44 @@ class RestApi { } bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { - Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); - bool accepted = true; - if(NULL == iv) { - jsonOut[F("error")] = F(INV_INDEX_INVALID) + jsonIn[F("id")].as(); - return false; + if(F("auth") == jsonIn[F("cmd")]) { + if(String(jsonIn["val"]) == String(mConfig->sys.adminPwd)) + jsonOut["token"] = mApp->unlock(clientIP); + else { + jsonOut[F("error")] = F(AUTH_ERROR); + return false; + } + return true; } - jsonOut[F("id")] = jsonIn[F("id")]; - if(mConfig->sys.adminPwd[0] != '\0') { - if(strncmp("*", clientIP, 1) != 0) { // no call from API (MqTT) + /*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(clientIP, token)) { + jsonOut[F("error")] = F(IS_PROTECTED); + jsonOut[F("bla")] = String(token); + return false; + } + } + }*/ + + if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set + if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT if(mApp->isProtected(clientIP)) { - jsonOut[F("error")] = F(INV_IS_PROTECTED); + jsonOut[F("error")] = F(IS_PROTECTED); return false; } } } + Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]); + bool accepted = true; + if(NULL == iv) { + jsonOut[F("error")] = F(INV_INDEX_INVALID) + jsonIn[F("id")].as(); + return false; + } + jsonOut[F("id")] = jsonIn[F("id")]; + if(F("power") == jsonIn[F("cmd")]) accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff); else if(F("restart") == jsonIn[F("cmd")]) @@ -882,7 +903,17 @@ class RestApi { return true; } - bool setSetup(JsonObject jsonIn, JsonObject jsonOut) { + bool setSetup(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) { + /*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(clientIP, token)) { + jsonOut[F("error")] = F(IS_PROTECTED); + return false; + } + } + }*/ + #if !defined(ETHERNET) if(F("scan_wifi") == jsonIn[F("cmd")]) mApp->scanAvailNetworks(); diff --git a/src/web/lang.h b/src/web/lang.h index 6cddbc12c..1e0669284 100644 --- a/src/web/lang.h +++ b/src/web/lang.h @@ -30,6 +30,12 @@ #define INV_INDEX_INVALID "inverter index invalid: " #endif +#ifdef LANG_DE + #define AUTH_ERROR "Authentifizierungsfehler" +#else /*LANG_EN*/ + #define AUTH_ERROR "authentication error" +#endif + #ifdef LANG_DE #define UNKNOWN_CMD "unbekanntes Kommando: '" #else /*LANG_EN*/ @@ -37,9 +43,9 @@ #endif #ifdef LANG_DE - #define INV_IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" + #define IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!" #else /*LANG_EN*/ - #define INV_IS_PROTECTED "not logged in, command not possible!" + #define IS_PROTECTED "not logged in, command not possible!" #endif #ifdef LANG_DE diff --git a/src/web/web.h b/src/web/web.h index a85e4b0a3..76503f0b1 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -782,7 +782,7 @@ class Web { // report value if (0 == channel) { // Report a _total value if also channel values were reported. Otherwise report without _total - char total[7]; + char total[7] = {0}; if (metricDeclared) { // A declaration and value for channels have been delivered. So declare and deliver a _total metric snprintf(total, sizeof(total), "_total");