From fa98e29cba7368314218179216a22c1a7ae23e2e Mon Sep 17 00:00:00 2001 From: suwatchai Date: Thu, 2 Dec 2021 09:59:35 +0700 Subject: [PATCH] Fixed UID accidently changed after auth token expired and access denied in Firebase.setReadWriteRules issues. --- README.md | 2 +- library.json | 2 +- library.properties | 2 +- src/FirebaseESP8266.h | 10 +-- src/README.md | 2 +- src/common.h | 5 +- src/json/MB_String.h | 2 +- src/rtdb/FB_RTDB.cpp | 60 +++++++-------- src/rtdb/FB_RTDB.h | 6 +- src/signer/Signer.cpp | 175 +++++++++++------------------------------- src/signer/Signer.h | 5 +- 11 files changed, 95 insertions(+), 176 deletions(-) diff --git a/README.md b/README.md index 32ca1c71..44720a17 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.4390794.svg)](https://doi.org/10.5281/zenodo.4390794) -Google's Firebase Realtime Database Arduino Library for ESP8266 v3.7.0 +Google's Firebase Realtime Database Arduino Library for ESP8266 v3.7.1 This library supports ESP8266 MCU from Espressif. The following are platforms in which libraries are also available. diff --git a/library.json b/library.json index c6e7c9f2..38aba320 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "Firebase ESP8266 Client", - "version": "3.7.0", + "version": "3.7.1", "keywords": "communication, REST, esp8266, arduino", "description": "The secure, fast and reliable Firebase Realtime database library to read, store, update, delete, listen, backup, and restore data. You can also read and modify the database security rules with this library.", "repository": { diff --git a/library.properties b/library.properties index a6aa1a01..b47a66bb 100644 --- a/library.properties +++ b/library.properties @@ -1,6 +1,6 @@ name=Firebase ESP8266 Client -version=3.7.0 +version=3.7.1 author=Mobizt diff --git a/src/FirebaseESP8266.h b/src/FirebaseESP8266.h index 9ea249f0..b8384ba1 100644 --- a/src/FirebaseESP8266.h +++ b/src/FirebaseESP8266.h @@ -1,16 +1,16 @@ #ifndef FIREBASE_CLIENT_VERSION -#define FIREBASE_CLIENT_VERSION "3.7.0" +#define FIREBASE_CLIENT_VERSION "3.7.1" #endif /** - * Google's Firebase Realtime Database Arduino Library for ESP8266, v3.7.0 + * Google's Firebase Realtime Database Arduino Library for ESP8266, v3.7.1 * - * Created November 23, 2021 + * Created December 2, 2021 * * Updates: - * - Fixed compilation error in FirebaseJson due to multiple sources of cJSON. - * - Add support ESP8266 external virtual RAM (SRAM or PSRAM). + * - Fixed UID accidently changed after auth token expired. + * - Fixed access denied in Firebase.setReadWriteRules. * * * This library provides ESP8266 to perform REST API by GET PUT, POST, PATCH, DELETE data from/to with Google's Firebase database using get, set, update diff --git a/src/README.md b/src/README.md index 41505f79..1498fff6 100644 --- a/src/README.md +++ b/src/README.md @@ -1,7 +1,7 @@ # Firebase Realtime Database Arduino Library for ESP8266 -Google's Firebase Realtime Database Arduino Library for ESP8266 v3.7.0 +Google's Firebase Realtime Database Arduino Library for ESP8266 v3.7.1 diff --git a/src/common.h b/src/common.h index bcca9781..251fbcc3 100644 --- a/src/common.h +++ b/src/common.h @@ -1,6 +1,6 @@ /** - * Created November 19, 2021 + * Created December 2, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -31,7 +31,6 @@ #define FB_COMMON_H_ #include -#include #include #include #include @@ -1689,7 +1688,7 @@ static const char fb_esp_pgm_str_183[] PROGMEM = "file"; static const char fb_esp_pgm_str_184[] PROGMEM = "/fb_bin_0.tmp"; static const char fb_esp_pgm_str_185[] PROGMEM = "The backup data should be the JSON object"; static const char fb_esp_pgm_str_186[] PROGMEM = "object"; -//static const char fb_esp_pgm_str_187[] PROGMEM = ""; +static const char fb_esp_pgm_str_187[] PROGMEM = "user_id"; //static const char fb_esp_pgm_str_188[] PROGMEM = ""; static const char fb_esp_pgm_str_189[] PROGMEM = "payload too large"; static const char fb_esp_pgm_str_190[] PROGMEM = "cannot config time"; diff --git a/src/json/MB_String.h b/src/json/MB_String.h index 459edbc7..6a5865f9 100644 --- a/src/json/MB_String.h +++ b/src/json/MB_String.h @@ -54,7 +54,7 @@ #define MB_STRING_MAJOR 1 #define MB_STRING_MINOR 1 -#define MB_STRING_PATCH 0 +#define MB_STRING_PATCH 2 #if defined(ESP8266) && defined(MMU_EXTERNAL_HEAP) && defined(MB_STRING_USE_PSRAM) #include diff --git a/src/rtdb/FB_RTDB.cpp b/src/rtdb/FB_RTDB.cpp index a71fc365..5cf76d61 100644 --- a/src/rtdb/FB_RTDB.cpp +++ b/src/rtdb/FB_RTDB.cpp @@ -1,9 +1,9 @@ /** - * Google's Firebase Realtime Database class, FB_RTDB.cpp version 1.2.8 + * Google's Firebase Realtime Database class, FB_RTDB.cpp version 1.2.9 * * This library supports Espressif ESP8266 and ESP32 * - * Created November 20, 2021 + * Created December 2, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -102,6 +102,29 @@ bool FB_RTDB::mSetRules(FirebaseData *fbdo, const char *rules) return ret; } +void FB_RTDB::storeToken(MBSTRING &atok, const char *databaseSecret) +{ + atok = Signer.config->_int.auth_token; + Signer.setTokenType(token_type_legacy_token); + Signer.config->signer.tokens.legacy_token = databaseSecret; + ut->storeS(Signer.config->_int.auth_token, Signer.config->signer.tokens.legacy_token, false); + Signer.config->_int.ltok_len = strlen(databaseSecret); + Signer.config->_int.rtok_len = 0; + Signer.config->_int.atok_len = 0; + Signer.handleToken(); +} + +void FB_RTDB::restoreToken(MBSTRING &atok, fb_esp_auth_token_type tk) +{ + ut->storeS(Signer.config->_int.auth_token, atok.c_str(), false); + ut->clearS(atok); + Signer.config->signer.tokens.legacy_token = ""; + Signer.config->signer.tokens.token_type = tk; + Signer.config->_int.atok_len = Signer.config->_int.auth_token.length(); + Signer.config->_int.ltok_len = 0; + Signer.handleToken(); +} + bool FB_RTDB::mSetQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret) { if (fbdo->_ss.rtdb.pause) @@ -117,16 +140,7 @@ bool FB_RTDB::mSetQueryIndex(FirebaseData *fbdo, const char *path, const char *n fb_esp_auth_token_type tk = Signer.getTokenType(); if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) - { - atok = Signer.config->_int.auth_token; - Signer.setTokenType(token_type_legacy_token); - Signer.config->signer.tokens.legacy_token = databaseSecret; - ut->storeS(Signer.config->_int.auth_token, Signer.config->signer.tokens.legacy_token, false); - Signer.config->_int.ltok_len = strlen(databaseSecret); - Signer.config->_int.rtok_len = 0; - Signer.config->_int.atok_len = 0; - Signer.handleToken(); - } + storeToken(atok, databaseSecret); if (getRules(fbdo)) { @@ -171,15 +185,7 @@ bool FB_RTDB::mSetQueryIndex(FirebaseData *fbdo, const char *path, const char *n } if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) - { - ut->storeS(Signer.config->_int.auth_token, atok.c_str(), false); - ut->clearS(atok); - Signer.config->signer.tokens.legacy_token = ""; - Signer.config->signer.tokens.token_type = tk; - Signer.config->_int.atok_len = Signer.config->_int.auth_token.length(); - Signer.config->_int.ltok_len = 0; - Signer.handleToken(); - } + restoreToken(atok, tk); ut->clearS(s); return ret; @@ -195,15 +201,12 @@ bool FB_RTDB::mSetReadWriteRules(FirebaseData *fbdo, const char *path, const cha MBSTRING s; bool ret = false; + MBSTRING atok; fb_esp_auth_token_type tk = Signer.getTokenType(); if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) - { - Signer.config->signer.tokens.legacy_token = databaseSecret; - Signer.config->signer.tokens.token_type = token_type_legacy_token; - Signer.handleToken(); - } + storeToken(atok, databaseSecret); if (getRules(fbdo)) { @@ -267,10 +270,7 @@ bool FB_RTDB::mSetReadWriteRules(FirebaseData *fbdo, const char *path, const cha } if (strlen(databaseSecret) && tk != token_type_oauth2_access_token && tk != token_type_legacy_token) - { - Signer.config->signer.tokens.token_type = tk; - Signer.handleToken(); - } + restoreToken(atok, tk); ut->clearS(s); return ret; diff --git a/src/rtdb/FB_RTDB.h b/src/rtdb/FB_RTDB.h index 59fede4e..2e15a94b 100644 --- a/src/rtdb/FB_RTDB.h +++ b/src/rtdb/FB_RTDB.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Realtime Database class, FB_RTDB.h version 1.2.8 + * Google's Firebase Realtime Database class, FB_RTDB.h version 1.2.9 * * This library supports Espressif ESP8266 and ESP32 * - * Created November 20, 2021 + * Created December 2, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2021 K. Suwatchai (Mobizt) @@ -1765,6 +1765,8 @@ class FB_RTDB void sendCB(FirebaseData *fbdo); void splitStreamPayload(const char *payloads, std::vector &payload); void parseStreamPayload(FirebaseData *fbdo, const char *payload); + void storeToken(MBSTRING &atok, const char *databaseSecret); + void restoreToken(MBSTRING &atok, fb_esp_auth_token_type tk); bool mSetQueryIndex(FirebaseData *fbdo, const char *path, const char *node, const char *databaseSecret); bool mBeginStream(FirebaseData *fbdo, const char *path); void mSetReadTimeout(FirebaseData *fbdo, const char *millisec); diff --git a/src/signer/Signer.cpp b/src/signer/Signer.cpp index 6dabdc37..c1e8ad99 100644 --- a/src/signer/Signer.cpp +++ b/src/signer/Signer.cpp @@ -1,9 +1,9 @@ /** - * Google's Firebase Token Generation class, Signer.cpp version 1.2.7 + * Google's Firebase Token Generation class, Signer.cpp version 1.2.8 * * This library supports Espressif ESP8266 and ESP32 * - * Created November 19, 2021 + * Created December 2, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) @@ -93,27 +93,17 @@ bool Firebase_Signer::parseSAFile() config->_int.fb_file.close(); ut->delP(&buf); - tmp = ut->strP(fb_esp_pgm_str_243); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_243)) { if (ut->strposP(config->signer.result->to(), fb_esp_pgm_str_244, 0) > -1) { - tmp = ut->strP(fb_esp_pgm_str_245); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_245)) config->service_account.data.project_id = config->signer.result->to(); - tmp = ut->strP(fb_esp_pgm_str_246); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + + if (parseJsonResponse(fb_esp_pgm_str_246)) config->service_account.data.private_key_id = config->signer.result->to(); - tmp = ut->strP(fb_esp_pgm_str_247); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + + if (parseJsonResponse(fb_esp_pgm_str_247)) { tmp = (char *)ut->newP(strlen(config->signer.result->to())); size_t c = 0; @@ -133,15 +123,9 @@ bool Firebase_Signer::parseSAFile() ut->delP(&tmp); } - tmp = ut->strP(fb_esp_pgm_str_248); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_248)) config->service_account.data.client_email = config->signer.result->to(); - tmp = ut->strP(fb_esp_pgm_str_253); - config->signer.json->get(*config->signer.result, (const char *)tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_253)) config->service_account.data.client_id = config->signer.result->to(); delete config->signer.json; @@ -513,6 +497,15 @@ void Firebase_Signer::tokenProcessingTask() #endif } +bool Firebase_Signer::parseJsonResponse(PGM_P key_path) +{ + char *tmp = ut->strP(key_path); + config->signer.result->clear(); + config->signer.json->get(*config->signer.result, tmp); + ut->delP(&tmp); + return config->signer.result->success; +} + bool Firebase_Signer::refreshToken() { if (config->_int.fb_reconnect_wifi) @@ -617,19 +610,12 @@ bool Firebase_Signer::refreshToken() int httpCode = 0; if (handleTokenResponse(httpCode)) { - tmp = ut->strP(fb_esp_pgm_str_257); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_257)) { error.code = config->signer.result->to(); config->signer.tokens.status = token_status_error; - tmp = ut->strP(fb_esp_pgm_str_258); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_258)) error.message = config->signer.result->to(); } @@ -645,36 +631,25 @@ bool Firebase_Signer::refreshToken() { if (isAuthToken(false)) { - tmp = ut->strP(fb_esp_pgm_str_208); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_208)) { ut->storeS(config->_int.auth_token, config->signer.result->to(), false); config->_int.atok_len = strlen(config->signer.result->to()); config->_int.ltok_len = 0; } - tmp = ut->strP(fb_esp_pgm_str_209); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_209)) { ut->storeS(config->_int.refresh_token, config->signer.result->to(), false); config->_int.rtok_len = strlen(config->signer.result->to()); } - tmp = ut->strP(fb_esp_pgm_str_210); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_210)) getExpiration(config->signer.result->to()); - tmp = ut->strP(fb_esp_pgm_str_175); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_187)) auth->token.uid = config->signer.result->to(); + } return handleSignerError(0); } @@ -1465,20 +1440,13 @@ bool Firebase_Signer::getIdToken(bool createUser, const char *email, const char { struct fb_esp_auth_token_error_t error; - tmp = ut->strP(fb_esp_pgm_str_257); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_257)) { error.code = config->signer.result->to(); if (!createUser) config->signer.tokens.status = token_status_error; - tmp = ut->strP(fb_esp_pgm_str_258); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_258)) error.message = config->signer.result->to(); } @@ -1506,35 +1474,23 @@ bool Firebase_Signer::getIdToken(bool createUser, const char *email, const char config->signer.anonymous = strlen(email) == 0 && strlen(password) == 0; } - tmp = ut->strP(fb_esp_pgm_str_200); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_200)) { config->_int.auth_token = config->signer.result->to(); config->_int.atok_len = strlen(config->signer.result->to()); config->_int.ltok_len = 0; } - tmp = ut->strP(fb_esp_pgm_str_201); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_201)) { ut->storeS(config->_int.refresh_token, config->signer.result->to(), false); config->_int.rtok_len = strlen(config->signer.result->to()); } - tmp = ut->strP(fb_esp_pgm_str_202); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_202)) getExpiration(config->signer.result->to()); - tmp = ut->strP(fb_esp_pgm_str_175); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_175)) auth->token.uid = config->signer.result->to(); if (!createUser) @@ -1647,20 +1603,10 @@ bool Firebase_Signer::deleteIdToken(const char *idToken) { struct fb_esp_auth_token_error_t error; - //config->signer.json->toString(Serial, true); - - tmp = ut->strP(fb_esp_pgm_str_257); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_257)) { error.code = config->signer.result->to(); - - tmp = ut->strP(fb_esp_pgm_str_258); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_258)) error.message = config->signer.result->to(); } @@ -1808,18 +1754,12 @@ bool Firebase_Signer::requestTokens() if (handleTokenResponse(httpCode)) { ut->clearS(config->signer.tokens.jwt); - char *tmp = ut->strP(fb_esp_pgm_str_257); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_257)) { error.code = config->signer.result->to(); config->signer.tokens.status = token_status_error; - tmp = ut->strP(fb_esp_pgm_str_258); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_258)) error.message = config->signer.result->to(); } @@ -1835,53 +1775,37 @@ bool Firebase_Signer::requestTokens() { if (config->signer.tokens.token_type == token_type_custom_token) { - tmp = ut->strP(fb_esp_pgm_str_200); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + + if (parseJsonResponse(fb_esp_pgm_str_200)) { ut->storeS(config->_int.auth_token, config->signer.result->to(), false); config->_int.atok_len = strlen(config->signer.result->to()); config->_int.ltok_len = 0; } - tmp = ut->strP(fb_esp_pgm_str_201); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_201)) { ut->storeS(config->_int.refresh_token, config->signer.result->to(), false); config->_int.rtok_len = strlen(config->signer.result->to()); } - tmp = ut->strP(fb_esp_pgm_str_202); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_202)) getExpiration(config->signer.result->to()); } else if (config->signer.tokens.token_type == token_type_oauth2_access_token) { - tmp = ut->strP(fb_esp_pgm_str_235); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + + if (parseJsonResponse(fb_esp_pgm_str_235)) { ut->storeS(config->_int.auth_token, config->signer.result->to(), false); config->_int.atok_len = strlen(config->signer.result->to()); config->_int.ltok_len = 0; } - tmp = ut->strP(fb_esp_pgm_str_236); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_236)) config->signer.tokens.auth_type = config->signer.result->to(); - tmp = ut->strP(fb_esp_pgm_str_210); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_210)) getExpiration(config->signer.result->to()); } return handleSignerError(0); @@ -2024,17 +1948,10 @@ bool Firebase_Signer::handleEmailSending(const char *payload, fb_esp_user_email_ { struct fb_esp_auth_token_error_t error; - tmp = ut->strP(fb_esp_pgm_str_257); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_257)) { error.code = config->signer.result->to(); - tmp = ut->strP(fb_esp_pgm_str_258); - config->signer.json->get(*config->signer.result, tmp); - ut->delP(&tmp); - if (config->signer.result->success) + if (parseJsonResponse(fb_esp_pgm_str_258)) error.message = config->signer.result->to(); } if (type == fb_esp_user_email_sending_type_verify) diff --git a/src/signer/Signer.h b/src/signer/Signer.h index 7d2d2667..87555f6a 100644 --- a/src/signer/Signer.h +++ b/src/signer/Signer.h @@ -1,9 +1,9 @@ /** - * Google's Firebase Token Generation class, Signer.h version 1.2.7 + * Google's Firebase Token Generation class, Signer.h version 1.2.8 * * This library supports Espressif ESP8266 and ESP32 * - * Created November 19, 2021 + * Created December 2, 2021 * * This work is a part of Firebase ESP Client library * Copyright (c) 2020, 2021 K. Suwatchai (Mobizt) @@ -93,6 +93,7 @@ class Firebase_Signer bool isAuthToken(bool admin); bool isExpired(); bool handleToken(); + bool parseJsonResponse(PGM_P key_path); bool refreshToken(); void setTokenError(int code); bool handleSignerError(int code, int httpCode = 0);