From 5d7b22448e075f5b1e6102b0de54ecb846260165 Mon Sep 17 00:00:00 2001 From: iranl Date: Tue, 11 Feb 2025 21:52:33 +0100 Subject: [PATCH] TOTP max invalid tries --- src/Config.h | 2 +- src/ImportExport.cpp | 15 +++++++++++++-- src/ImportExport.h | 2 ++ src/NukiNetwork.cpp | 5 +++++ src/NukiOpenerWrapper.h | 2 +- src/NukiWrapper.h | 2 +- src/WebCfgServer.cpp | 5 +++++ 7 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Config.h b/src/Config.h index 3106db9..711efab 100644 --- a/src/Config.h +++ b/src/Config.h @@ -5,7 +5,7 @@ #define NUKI_HUB_VERSION "9.09" #define NUKI_HUB_VERSION_INT (uint32_t)909 #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2025-02-10" +#define NUKI_HUB_DATE "2025-02-11" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" diff --git a/src/ImportExport.cpp b/src/ImportExport.cpp index 7d600b8..21d46e6 100644 --- a/src/ImportExport.cpp +++ b/src/ImportExport.cpp @@ -1,4 +1,5 @@ #include "ImportExport.h" +#include "EspMillis.h" #include "SPIFFS.h" #include "Logger.h" #include "PreferencesKeys.h" @@ -268,10 +269,18 @@ int ImportExport::checkDuoApprove() bool ImportExport::checkTOTP(String* totpKey) { - String key(totpKey->c_str()); - if(_totpEnabled) { + if((pow(_invalidCount, 5) + _lastCodeCheck) > espMillis()) + { + _lastCodeCheck = espMillis(); + return false; + } + + _lastCodeCheck = espMillis(); + + String key(totpKey->c_str()); + time_t now; time(&now); int totpTime = -60; @@ -282,11 +291,13 @@ bool ImportExport::checkTOTP(String* totpKey) if(key.toInt() == key2.toInt()) { + _invalidCount = 0; Log->println("Successful TOTP MFA Auth"); return true; } totpTime += 30; } + _invalidCount++; Log->println("Failed TOTP MFA Auth"); } return false; diff --git a/src/ImportExport.h b/src/ImportExport.h index 341d4dc..302974b 100644 --- a/src/ImportExport.h +++ b/src/ImportExport.h @@ -27,6 +27,8 @@ public: JsonDocument _duoSessions; JsonDocument _totpSessions; JsonDocument _sessionsOpts; + int64_t _lastCodeCheck = 0; + int _invalidCount = 0; private: void saveSessions(); Preferences* _preferences; diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp index 8dfd06e..608ff6a 100644 --- a/src/NukiNetwork.cpp +++ b/src/NukiNetwork.cpp @@ -384,6 +384,11 @@ bool NukiNetwork::update() wdt_hal_write_protect_enable(&rtc_wdt_ctx); int64_t ts = espMillis(); _device->update(); + + if(_importExport->getTOTPEnabled() && _importExport->_invalidCount > 0 && (ts - (120000 * _importExport->_invalidCount)) > _importExport->_lastCodeCheck) + { + _importExport->_invalidCount--; + } if(disableNetwork || !_mqttEnabled || _device->isApOpen()) { diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h index f3caec9..5e09d1c 100644 --- a/src/NukiOpenerWrapper.h +++ b/src/NukiOpenerWrapper.h @@ -108,7 +108,7 @@ private: int _retryConfigCount = 0; int _retryLockstateCount = 0; int64_t _nextRetryTs = 0; - int64_t _invalidCount = 0; + int _invalidCount = 0; int64_t _lastCodeCheck = 0; std::vector _keypadCodeIds; std::vector _keypadCodes; diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h index 76ddbd8..1fe4d1f 100644 --- a/src/NukiWrapper.h +++ b/src/NukiWrapper.h @@ -108,7 +108,7 @@ private: bool _publishAuthData = false; bool _clearAuthData = false; bool _checkKeypadCodes = false; - int64_t _invalidCount = 0; + int _invalidCount = 0; int64_t _lastCodeCheck = 0; std::vector _keypadCodeIds; std::vector _keypadCodes; diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index 80bba13..d9f8843 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -1885,6 +1885,11 @@ esp_err_t WebCfgServer::buildTOTPHtml(PsychicRequest *request, PsychicResponse* return buildConfirmHtml(request, resp, "NTP time not synced yet, TOTP not available, please wait for NTP to sync", 3, true); } + if((pow(_importExport->_invalidCount, 5) + _importExport->_lastCodeCheck) > espMillis()) + { + return buildConfirmHtml(request, resp, "Too many invalid TOTP tries, please wait before retrying", 3, true); + } + PsychicStreamResponse response(resp, "text/html"); response.beginSend(); response.print("");