Browse Source

0.8.70 - 2024-02-01

* prevent sending commands to inverter which isn't active #1387
* protect commands from popup in `/live` if password is set #1199
pull/1402/head
lumapu 8 months ago
parent
commit
4d7362fa6b
  1. 1
      src/CHANGES.md
  2. 5
      src/app.cpp
  3. 22
      src/app.h
  4. 6
      src/appInterface.h
  5. 2
      src/defines.h
  6. 4
      src/utils/spiPatcher.cpp
  7. 4
      src/utils/spiPatcher.h
  8. 7
      src/web/Protection.cpp
  9. 93
      src/web/Protection.h
  10. 15
      src/web/RestApi.h
  11. 6
      src/web/lang.h
  12. 49
      src/web/web.h

1
src/CHANGES.md

@ -2,6 +2,7 @@
## 0.8.70 - 2024-02-01
* prevent sending commands to inverter which isn't active #1387
* protect commands from popup in `/live` if password is set #1199
## 0.8.69 - 2024-01-31
* merge PR: Dynamic retries, pendular first rx chan #1394

5
src/app.cpp

@ -97,9 +97,8 @@ void app::setup() {
esp_task_wdt_reset();
mWeb.setup(this, &mSys, mConfig);
mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0);
mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig);
mProtection = Protection::getInstance(mConfig->sys.adminPwd);
#ifdef ENABLE_SYSLOG
mDbgSyslog.setup(mConfig); // be sure to init after mWeb.setup (webSerial uses also debug callback)
@ -182,6 +181,8 @@ void app::onNetwork(bool gotIp) {
void app::regularTickers(void) {
DPRINTLN(DBG_DEBUG, F("regularTickers"));
everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc");
everySec([this]() { mProtection->tickSecond(); }, "prot");
// Plugins
#if defined(PLUGIN_DISPLAY)
if (DISP_TYPE_T0_NONE != mConfig->plugin.display.type)

22
src/app.h

@ -30,6 +30,7 @@
#include "utils/scheduler.h"
#include "utils/syslog.h"
#include "web/RestApi.h"
#include "web/Protection.h"
#if defined(ENABLE_HISTORY)
#include "plugins/history.h"
#endif /*ENABLE_HISTORY*/
@ -246,8 +247,24 @@ class app : public IApp, public ah::Scheduler {
#endif
}
bool getProtection(AsyncWebServerRequest *request) {
return mWeb.isProtected(request);
void lock(void) override {
mProtection->lock();
}
void unlock(const char *clientIp) override {
mProtection->unlock(clientIp);
}
void resetLockTimeout(void) override {
mProtection->resetLockTimeout();
}
bool isProtected(void) const override {
return mProtection->isProtected();
}
bool isProtected(const char *clientIp) const override {
return mProtection->isProtected(clientIp);
}
bool getNrfEnabled(void) {
@ -387,6 +404,7 @@ class app : public IApp, public ah::Scheduler {
#endif /* defined(ETHERNET) */
WebType mWeb;
RestApiType mApi;
Protection *mProtection;
#ifdef ENABLE_SYSLOG
DbgSyslog mDbgSyslog;
#endif

6
src/appInterface.h

@ -61,7 +61,11 @@ class IApp {
virtual uint32_t getMqttRxCnt() = 0;
virtual uint32_t getMqttTxCnt() = 0;
virtual bool getProtection(AsyncWebServerRequest *request) = 0;
virtual void lock(void) = 0;
virtual void 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 uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0;
virtual uint16_t getHistoryMaxDay() = 0;

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 69
#define VERSION_PATCH 70
//-------------------------------------
typedef struct {

4
src/utils/spiPatcher.cpp

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#if defined(ESP32)

4
src/utils/spiPatcher.h

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#ifndef __SPI_PATCHER_H__

7
src/web/Protection.cpp

@ -0,0 +1,7 @@
//-----------------------------------------------------------------------------
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#include "Protection.h"
Protection *Protection::mInstance = nullptr;

93
src/web/Protection.h

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#ifndef __PROTECTION_H__
#define __PROTECTION_H__
#pragma once
#include <array>
#include <cstdint>
#include "../config/config.h"
#include "../utils/helper.h"
class Protection {
protected:
Protection(const char *pwd) {
mPwd = pwd;
mLogoutTimeout = 0;
mLoginIp.fill(0);
// no password set - unlock
if(pwd[0] == '\0')
mProtected = false;
}
public:
Protection(Protection &other) = delete;
void operator=(const Protection &) = delete;
static Protection* getInstance(const char *pwd) {
if(nullptr == mInstance)
mInstance = new Protection(pwd);
return mInstance;
}
void tickSecond() {
// auto logout
if(0 != mLogoutTimeout) {
if (0 == --mLogoutTimeout) {
if(mPwd[0] == '\0')
mProtected = true;
}
}
}
void lock(void) {
mProtected = true;
mLoginIp.fill(0);
}
void unlock(const char *clientIp) {
mProtected = false;
ah::ip2Arr(static_cast<uint8_t*>(mLoginIp.data()), clientIp);
}
void resetLockTimeout(void) {
mLogoutTimeout = LOGOUT_TIMEOUT;
}
bool isProtected(void) const {
return mProtected;
}
bool isProtected(const char *clientIp) const {
if(mProtected)
return true;
if(mPwd[0] == '\0')
return false;
uint8_t ip[4];
ah::ip2Arr(ip, clientIp);
for(uint8_t i = 0; i < 4; i++) {
if(mLoginIp[i] != ip[i])
return true;
}
return true;
}
protected:
static Protection *mInstance;
private:
const char *mPwd;
bool mProtected = true;
uint16_t mLogoutTimeout = LOGOUT_TIMEOUT;
std::array<uint8_t, 4> mLoginIp;
};
#endif /*__PROTECTION_H__*/

15
src/web/RestApi.h

@ -68,7 +68,7 @@ class RestApi {
DynamicJsonDocument json(128);
JsonObject dummy = json.as<JsonObject>();
if(obj[F("path")] == "ctrl")
setCtrl(obj, dummy);
setCtrl(obj, dummy, "api");
else if(obj[F("path")] == "setup")
setSetup(obj, dummy);
}
@ -168,7 +168,7 @@ class RestApi {
if(!err) {
String path = request->url().substring(5);
if(path == "ctrl")
root[F("success")] = setCtrl(obj, root);
root[F("success")] = setCtrl(obj, root, request->client()->remoteIP().toString().c_str());
else if(path == "setup")
root[F("success")] = setSetup(obj, root);
else {
@ -263,7 +263,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->getProtection(request);
obj[F("menu_prot")] = mApp->isProtected(request->client()->remoteIP().toString().c_str());
obj[F("menu_mask")] = (uint16_t)(mConfig->sys.protectionMask );
obj[F("menu_protEn")] = (bool) (strlen(mConfig->sys.adminPwd) > 0);
obj[F("cst_lnk")] = String(mConfig->plugin.customLink);
@ -847,7 +847,7 @@ class RestApi {
}
bool setCtrl(JsonObject jsonIn, JsonObject jsonOut) {
bool setCtrl(JsonObject jsonIn, JsonObject jsonOut, const char *clientIP) {
Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")]);
bool accepted = true;
if(NULL == iv) {
@ -856,6 +856,13 @@ class RestApi {
}
jsonOut[F("id")] = jsonIn[F("id")];
if(strncmp("api", clientIP, 3) != 0) {
if(mApp->isProtected(clientIP)) {
jsonOut[F("error")] = F(INV_IS_PROTECTED);
return false;
}
}
if(F("power") == jsonIn[F("cmd")])
accepted = iv->setDevControlRequest((jsonIn[F("val")] == 1) ? TurnOn : TurnOff);
else if(F("restart") == jsonIn[F("cmd")])

6
src/web/lang.h

@ -36,6 +36,12 @@
#define UNKNOWN_CMD "unknown cmd: '"
#endif
#ifdef LANG_DE
#define INV_IS_PROTECTED "nicht angemeldet, Kommando nicht möglich!"
#else /*LANG_EN*/
#define INV_IS_PROTECTED "not logged in, command not possible!"
#endif
#ifdef LANG_DE
#define INV_DOES_NOT_ACCEPT_LIMIT_AT_MOMENT "Leistungsbegrenzung / Ansteuerung aktuell nicht möglich"
#else /*LANG_EN*/

49
src/web/web.h

@ -47,9 +47,6 @@ template <class HMSYSTEM>
class Web {
public:
Web(void) : mWeb(80), mEvts("/events") {
mProtected = true;
mLogoutTimeout = 0;
memset(mSerialBuf, 0, WEB_SERIAL_BUF_SIZE);
mSerialBufFill = 0;
mSerialAddTime = true;
@ -110,16 +107,6 @@ class Web {
}
void tickSecond() {
if (0 != mLogoutTimeout) {
mLogoutTimeout -= 1;
if (0 == mLogoutTimeout) {
if (strlen(mConfig->sys.adminPwd) > 0)
mProtected = true;
}
DPRINTLN(DBG_DEBUG, "auto logout in " + String(mLogoutTimeout));
}
if (mSerialClientConnnected) {
if (mSerialBufFill > 0) {
mEvts.send(mSerialBuf, "serial", millis());
@ -133,27 +120,6 @@ class Web {
return &mWeb;
}
void setProtection(bool protect) {
mProtected = protect;
}
bool isProtected(AsyncWebServerRequest *request) {
bool prot;
prot = mProtected;
if(!prot) {
if(strlen(mConfig->sys.adminPwd) > 0) {
uint8_t ip[4];
ah::ip2Arr(ip, request->client()->remoteIP().toString().c_str());
for(uint8_t i = 0; i < 4; i++) {
if(mLoginIp[i] != ip[i])
prot = true;
}
}
}
return prot;
}
void showUpdate2(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
if (!index) {
Serial.printf("Update Start: %s\n", filename.c_str());
@ -264,7 +230,7 @@ class Web {
}
void checkProtection(AsyncWebServerRequest *request) {
if(isProtected(request)) {
if(mApp->isProtected(request->client()->remoteIP().toString().c_str())) {
checkRedirect(request);
return;
}
@ -351,8 +317,7 @@ class Web {
if (request->args() > 0) {
if (String(request->arg("pwd")) == String(mConfig->sys.adminPwd)) {
mProtected = false;
ah::ip2Arr(mLoginIp, request->client()->remoteIP().toString().c_str());
mApp->unlock(request->client()->remoteIP().toString().c_str());
request->redirect("/");
}
}
@ -366,8 +331,7 @@ class Web {
DPRINTLN(DBG_VERBOSE, F("onLogout"));
checkProtection(request);
mProtected = true;
mApp->lock();
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
response->addHeader(F("Content-Encoding"), "gzip");
@ -390,7 +354,6 @@ class Web {
void onCss(AsyncWebServerRequest *request) {
DPRINTLN(DBG_VERBOSE, F("onCss"));
mLogoutTimeout = LOGOUT_TIMEOUT;
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/css"), style_css, style_css_len);
response->addHeader(F("Content-Encoding"), "gzip");
if(request->hasParam("v")) {
@ -424,6 +387,7 @@ class Web {
AsyncWebServerResponse *response = request->beginResponse_P(200, favicon_type, favicon_ico, favicon_ico_len);
response->addHeader(F("Content-Encoding"), "gzip");
request->send(response);
mApp->resetLockTimeout();
}
void showNotFound(AsyncWebServerRequest *request) {
@ -495,7 +459,7 @@ class Web {
// protection
if (request->arg("adminpwd") != "{PWD}") {
request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN);
mProtected = (strlen(mConfig->sys.adminPwd) > 0);
mApp->lock();
}
mConfig->sys.protectionMask = 0x0000;
for (uint8_t i = 0; i < 7; i++) {
@ -945,9 +909,6 @@ class Web {
#endif
AsyncWebServer mWeb;
AsyncEventSource mEvts;
bool mProtected;
uint32_t mLogoutTimeout;
uint8_t mLoginIp[4];
IApp *mApp;
HMSYSTEM *mSys;

Loading…
Cancel
Save