mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-02 18:51:38 +02:00
0.8.78
* fixed protection
This commit is contained in:
parent
8b2db4abfa
commit
d5cecbb5b0
7 changed files with 49 additions and 56 deletions
|
@ -1,6 +1,6 @@
|
||||||
# Development Changes
|
# Development Changes
|
||||||
|
|
||||||
## 0.8.78 - 2024-02-09
|
## 0.8.78 - 2024-02-10
|
||||||
* finalized API token access #1415
|
* finalized API token access #1415
|
||||||
|
|
||||||
## 0.8.77 - 2024-02-08
|
## 0.8.77 - 2024-02-08
|
||||||
|
|
12
src/app.h
12
src/app.h
|
@ -247,8 +247,8 @@ class app : public IApp, public ah::Scheduler {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock(void) override {
|
void lock(bool fromWeb) override {
|
||||||
mProtection->lock();
|
mProtection->lock(fromWeb);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *unlock(const char *clientIp, bool loginFromWeb) override {
|
char *unlock(const char *clientIp, bool loginFromWeb) override {
|
||||||
|
@ -259,12 +259,8 @@ class app : public IApp, public ah::Scheduler {
|
||||||
mProtection->resetLockTimeout();
|
mProtection->resetLockTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isProtected(void) const override {
|
bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const override {
|
||||||
return mProtection->isProtected();
|
return mProtection->isProtected(clientIp, token, askedFromWeb);
|
||||||
}
|
|
||||||
|
|
||||||
bool isProtected(const char *token, bool askedFromWeb) const override {
|
|
||||||
return mProtection->isProtected(token, askedFromWeb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool getNrfEnabled(void) override {
|
bool getNrfEnabled(void) override {
|
||||||
|
|
|
@ -61,11 +61,10 @@ class IApp {
|
||||||
virtual uint32_t getMqttRxCnt() = 0;
|
virtual uint32_t getMqttRxCnt() = 0;
|
||||||
virtual uint32_t getMqttTxCnt() = 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 char *unlock(const char *clientIp, bool loginFromWeb) = 0;
|
||||||
virtual void resetLockTimeout(void) = 0;
|
virtual void resetLockTimeout(void) = 0;
|
||||||
virtual bool isProtected(void) const = 0;
|
virtual bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const = 0;
|
||||||
virtual bool isProtected(const char *token, bool askedFromWeb) const = 0;
|
|
||||||
|
|
||||||
virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0;
|
virtual uint16_t getHistoryValue(uint8_t type, uint16_t i) = 0;
|
||||||
virtual uint16_t getHistoryMaxDay() = 0;
|
virtual uint16_t getHistoryMaxDay() = 0;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 8
|
#define VERSION_MINOR 8
|
||||||
#define VERSION_PATCH 77
|
#define VERSION_PATCH 78
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -18,12 +18,9 @@ class Protection {
|
||||||
explicit Protection(const char *pwd) {
|
explicit Protection(const char *pwd) {
|
||||||
mPwd = pwd;
|
mPwd = pwd;
|
||||||
mLogoutTimeout = 0;
|
mLogoutTimeout = 0;
|
||||||
mLoginIp.fill(0);
|
mWebIp.fill(0);
|
||||||
|
mApiIp.fill(0);
|
||||||
mToken.fill(0);
|
mToken.fill(0);
|
||||||
|
|
||||||
// no password set - unlock
|
|
||||||
if(pwd[0] == '\0')
|
|
||||||
mProtected = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -40,27 +37,30 @@ class Protection {
|
||||||
// auto logout
|
// auto logout
|
||||||
if(0 != mLogoutTimeout) {
|
if(0 != mLogoutTimeout) {
|
||||||
if (0 == --mLogoutTimeout) {
|
if (0 == --mLogoutTimeout) {
|
||||||
if(mPwd[0] != '\0') {
|
if(mPwd[0] != '\0')
|
||||||
mProtected = true;
|
lock(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lock(void) {
|
void lock(bool fromWeb) {
|
||||||
mProtected = true;
|
mWebIp.fill(0);
|
||||||
mLoginIp.fill(0);
|
if(fromWeb)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mApiIp.fill(0);
|
||||||
mToken.fill(0);
|
mToken.fill(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *unlock(const char *clientIp, bool loginFromWeb) {
|
char *unlock(const char *clientIp, bool loginFromWeb) {
|
||||||
mLogoutTimeout = LOGOUT_TIMEOUT;
|
mLogoutTimeout = LOGOUT_TIMEOUT;
|
||||||
mProtected = false;
|
|
||||||
|
|
||||||
if(loginFromWeb)
|
if(loginFromWeb)
|
||||||
ah::ip2Arr(static_cast<uint8_t*>(mLoginIp.data()), clientIp);
|
ah::ip2Arr(static_cast<uint8_t*>(mWebIp.data()), clientIp);
|
||||||
else
|
else {
|
||||||
|
ah::ip2Arr(static_cast<uint8_t*>(mApiIp.data()), clientIp);
|
||||||
genToken();
|
genToken();
|
||||||
|
}
|
||||||
|
|
||||||
return reinterpret_cast<char*>(mToken.data());
|
return reinterpret_cast<char*>(mToken.data());
|
||||||
}
|
}
|
||||||
|
@ -70,30 +70,19 @@ class Protection {
|
||||||
mLogoutTimeout = LOGOUT_TIMEOUT;
|
mLogoutTimeout = LOGOUT_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isProtected(void) const {
|
bool isProtected(const char *clientIp, const char *token, bool askedFromWeb) const {
|
||||||
return mProtected;
|
if(mPwd[0] == '\0') // no password set
|
||||||
}
|
|
||||||
|
|
||||||
bool isProtected(const char *token, bool askedFromWeb) const { // token == clientIp
|
|
||||||
if(mProtected)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if(mPwd[0] == '\0')
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(askedFromWeb) { // check IP address
|
if(askedFromWeb)
|
||||||
std::array<uint8_t, 4> ip;
|
return !isIdentical(clientIp, mWebIp);
|
||||||
ah::ip2Arr(static_cast<uint8_t*>(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;
|
|
||||||
|
|
||||||
|
// 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 (0 != strncmp(token, mToken.data(), 16));
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -106,18 +95,27 @@ class Protection {
|
||||||
if(mToken[i] < 10)
|
if(mToken[i] < 10)
|
||||||
mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed)
|
mToken[i] += 0x30; // convert to ascii number 1-9 (zero isn't allowed)
|
||||||
else
|
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<uint8_t, 4> cmp) const {
|
||||||
|
std::array<uint8_t, 4> ip;
|
||||||
|
ah::ip2Arr(static_cast<uint8_t*>(ip.data()), clientIp);
|
||||||
|
for(uint8_t i = 0; i < 4; i++) {
|
||||||
|
if(cmp[i] != ip[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static Protection *mInstance;
|
static Protection *mInstance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const char *mPwd;
|
const char *mPwd;
|
||||||
bool mProtected = true;
|
|
||||||
uint16_t mLogoutTimeout = 0;
|
uint16_t mLogoutTimeout = 0;
|
||||||
std::array<uint8_t, 4> mLoginIp;
|
std::array<uint8_t, 4> mWebIp, mApiIp;
|
||||||
std::array<char, 17> mToken;
|
std::array<char, 17> mToken;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -266,7 +266,7 @@ class RestApi {
|
||||||
obj[F("modules")] = String(mApp->getVersionModules());
|
obj[F("modules")] = String(mApp->getVersionModules());
|
||||||
obj[F("build")] = String(AUTO_GIT_HASH);
|
obj[F("build")] = String(AUTO_GIT_HASH);
|
||||||
obj[F("env")] = String(ENV_NAME);
|
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_mask")] = (uint16_t)(mConfig->sys.protectionMask );
|
||||||
obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0');
|
obj[F("menu_protEn")] = (bool) (mConfig->sys.adminPwd[0] != '\0');
|
||||||
obj[F("cst_lnk")] = String(mConfig->plugin.customLink);
|
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(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set
|
||||||
if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT
|
if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT
|
||||||
const char* token = jsonIn["token"];
|
const char* token = jsonIn["token"];
|
||||||
if(mApp->isProtected(token, false)) {
|
if(mApp->isProtected(clientIP, token, false)) {
|
||||||
jsonOut[F("error")] = F(IS_PROTECTED);
|
jsonOut[F("error")] = F(IS_PROTECTED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -897,7 +897,7 @@ class RestApi {
|
||||||
if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set
|
if(mConfig->sys.adminPwd[0] != '\0') { // check if admin password is set
|
||||||
if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT
|
if(strncmp("*", clientIP, 1) != 0) { // no call from MqTT
|
||||||
const char* token = jsonIn["token"];
|
const char* token = jsonIn["token"];
|
||||||
if(mApp->isProtected(token, false)) {
|
if(mApp->isProtected(clientIP, token, false)) {
|
||||||
jsonOut[F("error")] = F(IS_PROTECTED);
|
jsonOut[F("error")] = F(IS_PROTECTED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@ class Web {
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkProtection(AsyncWebServerRequest *request) {
|
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);
|
checkRedirect(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -328,7 +328,7 @@ class Web {
|
||||||
DPRINTLN(DBG_VERBOSE, F("onLogout"));
|
DPRINTLN(DBG_VERBOSE, F("onLogout"));
|
||||||
|
|
||||||
checkProtection(request);
|
checkProtection(request);
|
||||||
mApp->lock();
|
mApp->lock(true);
|
||||||
|
|
||||||
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
|
AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len);
|
||||||
response->addHeader(F("Content-Encoding"), "gzip");
|
response->addHeader(F("Content-Encoding"), "gzip");
|
||||||
|
@ -455,7 +455,7 @@ class Web {
|
||||||
// protection
|
// protection
|
||||||
if (request->arg("adminpwd") != "{PWD}") {
|
if (request->arg("adminpwd") != "{PWD}") {
|
||||||
request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN);
|
request->arg("adminpwd").toCharArray(mConfig->sys.adminPwd, PWD_LEN);
|
||||||
mApp->lock();
|
mApp->lock(false);
|
||||||
}
|
}
|
||||||
mConfig->sys.protectionMask = 0x0000;
|
mConfig->sys.protectionMask = 0x0000;
|
||||||
for (uint8_t i = 0; i < 7; i++) {
|
for (uint8_t i = 0; i < 7; i++) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue