Skip to content

Commit

Permalink
Add support the FirebaseApp deinitialization (deinitializeApp)
Browse files Browse the repository at this point in the history
  • Loading branch information
mobizt committed Jun 7, 2024
1 parent 18bc211 commit 58f5d48
Show file tree
Hide file tree
Showing 259 changed files with 1,112 additions and 333 deletions.
16 changes: 14 additions & 2 deletions FAQ.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

Revision `2024-06-06T02:25:03Z`
Revision `2024-06-07T05:35:03Z`

# Async Firebase Client library for Arduino Frequently Asked Questions.

Expand Down Expand Up @@ -34,6 +34,8 @@ Revision `2024-06-06T02:25:03Z`
- [Q27: How can I run Realtime Database task and Cloud Firestore Database task using the same async client?](#q27-how-can-i-run-realtime-database-task-and-cloud-firestore-database-task-using-the-same-async-client)
- [Q28: Why my Arduino MKR board failed to connect to the server?](#q28-why-my-arduino-mkr-board-failed-to-connect-to-the-server)
- [Q29: Why my SIM7600 failed to connect to the server?](#q29-why-my-sim7600-failed-to-connect-to-the-server)
- [Q30: How to stop the authentication task?](#q30-how-to-stop-the-authentication-task)
- [Q31: How to remove authentication task handler from Firebase service app?](#q31-how-to-remove-authentication-task-handler-from-firebase-service-app)

### Q1: Why I get an error `"TCP connection failed"`?

Expand Down Expand Up @@ -338,4 +340,14 @@ For running more tasks concurrency, see [Running Many Tasks Concurrency Using Di
#### A28: Please see, [Possible WiFi issues](#possible-wifi-issues) and [Possible WiFi firmware issues](#possible-wifi-firmware-issues).

### Q29: Why my SIM7600 failed to connect to the server?
#### A29: Please see, [Possible GSM issues](#possible-gsm-issues).
#### A29: Please see, [Possible GSM issues](#possible-gsm-issues).

### Q30: How to stop the authentication task?
#### A30: Normally the authentication task was unable to stop after initialize unless it can deinitialize.

You can use `deinitializeApp(<FirebaseApp>)` to deinitalize the `FirebaseApp` that was initialized.

You also can block the `FirebaseApp::loop()` from the running in loop to pause the authentication task but it is not recommended.

### Q31: How to remove authentication task handler from Firebase service app?
#### A31: You can use `<FirebaseServiceApp>::resetApp()` to unbind or remove the `FirebaseApp` from the Firebase service app.
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/mobizt/FirebaseClient/.github%2Fworkflows%2Fcompile_library.yml?logo=github&label=compile) [![Github Stars](https://img.shields.io/github/stars/mobizt/FirebaseClient?logo=github)](https://github.com/mobizt/FirebaseClient/stargazers) ![Github Issues](https://img.shields.io/github/issues/mobizt/FirebaseClient?logo=github)

![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.2.10-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)
![GitHub Release](https://img.shields.io/github/v/release/mobizt/FirebaseClient) ![Arduino](https://img.shields.io/badge/Arduino-v1.2.11-57C207?logo=arduino) ![PlatformIO](https://badges.registry.platformio.org/packages/mobizt/library/FirebaseClient.svg) ![GitHub Release Date](https://img.shields.io/github/release-date/mobizt/FirebaseClient)

[![GitHub Sponsors](https://img.shields.io/github/sponsors/mobizt?logo=github)](https://github.com/sponsors/mobizt)

Revision `2024-06-06T11:57:47Z`
Revision `2024-06-07T03:49:12Z`

## Table of Contents

Expand Down Expand Up @@ -805,15 +805,13 @@ The debug information (`String`) from the async result can be obtained from `Str

The Firebase app (`FirebaseApp`) is the class that used to handle the authentication task.

The process of App intitialization:
The processes of App intitialization are the following

- The `FirebaseApp` class accepts the user auth data (`user_auth_data`) which is the struct that holds the user sign-in credentials and tokens.
- User calls `initializeApp(...)` to initialize the authentication task handler.

The user auth data that passes to the `FirebaseApp` class constructor can be obtained from the authentication/authorization classes via `getAuth` function.
- User calls `FirebaseApp::getApp<T>(<FirebaseServiceApp>)` to bind the authentication task handler with the Service apps before use.

The app token (`app_token_t`) that is the object that provided by the user auth data (`user_auth_data`), will provide the `auth tokens` that used in the authorization requests.

- User calls `FirebaseApp::getApp<T>(<FirebaseServiceApp>)` to apply the auth data from app token to the Service apps before use.
User can unbind the `FirebaseApp` or authentication task handler from the Service app by calling `resetApp()` from the app.

The authentication/authorization classes also mentioned in the earlier section will be discussed here.

Expand Down Expand Up @@ -877,6 +875,15 @@ initializeApp(<AsyncClientClass>, <FirebaseApp>, <user_auth_data>, <AsyncResultC

`<UID>` The Task UID. See [Async Result](#async-result) section.

- ### deinitializeApp or Firebase::deinitializeApp

Since v1.2.11, to deinitialize the `FirebaseApp`, call `Firebase::deinitializeApp` or static function `deinitializeApp` which the functions parameters are included the following.

```cpp
initializeApp(<FirebaseApp>);
```
`<FirebaseApp>` The `FirebaseApp` class object to handle authentication/authorization task.
- ### CustomAuth (ID Token Authorization Using Service Account)
Expand Down Expand Up @@ -1945,8 +1952,12 @@ void setup()
#endif
#endif
// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(user_auth), asyncCB, "authTask");
// Binding the FirebaseApp for authentication handler.
// To unbind, use Database.resetApp();
app.getApp<RealtimeDatabase>(Database);
Database.url(DATABASE_URL);
Expand Down Expand Up @@ -2085,8 +2096,12 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(user_auth), aResult_no_callback);

// Binding the FirebaseApp for authentication handler.
// To unbind, use Database.resetApp();
app.getApp<RealtimeDatabase>(Database);

Database.url(DATABASE_URL);
Expand Down Expand Up @@ -2230,10 +2245,14 @@ void setup()
#endif
#endif
// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(user_auth), aResult_no_callback);
authHandler();
// Binding the FirebaseApp for authentication handler.
// To unbind, use Database.resetApp();
app.getApp<RealtimeDatabase>(Database);
Database.url(DATABASE_URL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* SYNTAX:
*
* CustomAuth::CustomAuth(<TimeStatusCallback>, <api_key>, <client_email>, <project_id>, <private_key>, <user_id>, <scope>, <claims>, <expire>);
*
*
* <TimeStatusCallback> - The time status callback that provide the UNIX timestamp value used for JWT token signing.
* <api_key> - The web API key of project.
* <client_email> - The service account client Email.
Expand Down Expand Up @@ -125,6 +125,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(custom_auth), asyncCB, "authTask");
}

Expand All @@ -135,7 +137,7 @@ void loop()

// The JWT token processor required for ServiceAuth and CustomAuth authentications.
// JWT is a static object of JWTClass and it's not thread safe.
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// and set it to the FirebaseApp via FirebaseApp::setJWTProcessor(<JWTClass>), before calling initializeApp.
JWT.loop(app.getAuth());

Expand Down Expand Up @@ -193,4 +195,3 @@ void printResult(AsyncResult &aResult)
Firebase.printf("task: %s, payload: %s\n", aResult.uid().c_str(), aResult.c_str());
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(sa_file_auth), asyncCB, "authTask");
}

Expand All @@ -159,7 +161,7 @@ void loop()

// The JWT token processor required for ServiceAuth and CustomAuth authentications.
// JWT is a static object of JWTClass and it's not thread safe.
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// and set it to the FirebaseApp via FirebaseApp::setJWTProcessor(<JWTClass>), before calling initializeApp.
JWT.loop(app.getAuth());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,10 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
// The async result and async result callback are not needed for no authentication.
initializeApp(aClient, app, getAuth(no_auth));

}

void loop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(sa_auth), asyncCB, "authTask");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(sa_file_auth), asyncCB, "authTask");
}

Expand All @@ -150,7 +152,7 @@ void loop()

// The JWT token processor required for ServiceAuth and CustomAuth authentications.
// JWT is a static object of JWTClass and it's not thread safe.
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// and set it to the FirebaseApp via FirebaseApp::setJWTProcessor(<JWTClass>), before calling initializeApp.
JWT.loop(app.getAuth());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(access_token), asyncCB, "authTask");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(custom_token), asyncCB, "authToken");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,16 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(id_token), asyncCB, "authToken");
}

void loop()
{
// The async task handler should run inside the main loop
// without blocking delay or bypassing with millis code blocks.

app.loop();

// To get the authentication time to live in seconds before expired.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
// The async result and async result callback are not needed for legacy token.
initializeApp(aClient, app, getAuth(legacy_token));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ void asyncCB(AsyncResult &aResult);

void printResult(AsyncResult &aResult);

bool verifyUser(const String &apiKey, const String &email, const String &password);

DefaultNetwork network; // initilize with boolean parameter to enable/disable network reconnection

UserAuth user_auth(API_KEY, USER_EMAIL, USER_PASSWORD, 3000 /* expire period in seconds (<3600) */);
Expand Down Expand Up @@ -100,15 +102,25 @@ void setup()

Firebase.printf("Firebase Client v%s\n", FIREBASE_CLIENT_VERSION);

Serial.println("Initializing app...");

#if defined(ESP32) || defined(ESP8266) || defined(PICO_RP2040)
ssl_client.setInsecure();
#if defined(ESP8266)
ssl_client.setBufferSizes(4096, 1024);
#endif
#endif

// You can validate or verify user before initializing the app.
Serial.print("Verifying user... ");
bool ret = verifyUser(API_KEY, USER_EMAIL, USER_PASSWORD);
if (ret)
Serial.println("ok");
else
Serial.println("failed");

Serial.println("Initializing app...");

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(user_auth), asyncCB, "authTask");
}

Expand Down Expand Up @@ -163,4 +175,59 @@ void printResult(AsyncResult &aResult)
{
Firebase.printf("task: %s, payload: %s\n", aResult.uid().c_str(), aResult.c_str());
}
}

bool verifyUser(const String &apiKey, const String &email, const String &password)
{
if (ssl_client.connected())
ssl_client.stop();

String host = "www.googleapis.com";
bool ret = false;

if (ssl_client.connect(host.c_str(), 443) > 0)
{
String payload = "{\"email\":\"";
payload += email;
payload += "\",\"password\":\"";
payload += password;
payload += "\",\"returnSecureToken\":true}";

String header = "POST /identitytoolkit/v3/relyingparty/verifyPassword?key=";
header += apiKey;
header += " HTTP/1.1\r\n";
header += "Host: ";
header += host;
header += "\r\n";
header += "Content-Type: application/json\r\n";
header += "Content-Length: ";
header += payload.length();
header += "\r\n\r\n";

if (ssl_client.print(header) == header.length())
{
if (ssl_client.print(payload) == payload.length())
{
unsigned long ms = millis();
while (ssl_client.connected() && ssl_client.available() == 0 && millis() - ms < 5000)
{
delay(1);
}

ms = millis();
while (ssl_client.connected() && ssl_client.available() && millis() - ms < 5000)
{
String line = ssl_client.readStringUntil('\n');
if (line.length())
{
ret = line.indexOf("HTTP/1.1 200 OK") > -1;
break;
}
}
ssl_client.stop();
}
}
}

return ret;
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(custom_auth), aResult_no_callback);
}

Expand All @@ -135,7 +137,7 @@ void loop()

// The JWT token processor required for ServiceAuth and CustomAuth authentications.
// JWT is a static object of JWTClass and it's not thread safe.
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// and set it to the FirebaseApp via FirebaseApp::setJWTProcessor(<JWTClass>), before calling initializeApp.
JWT.loop(app.getAuth());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ void setup()
#endif
#endif

// Initialize the FirebaseApp or auth task handler.
// To deinitialize, use deinitializeApp(app).
initializeApp(aClient, app, getAuth(sa_file_auth), aResult_no_callback);
}

Expand All @@ -159,7 +161,7 @@ void loop()

// The JWT token processor required for ServiceAuth and CustomAuth authentications.
// JWT is a static object of JWTClass and it's not thread safe.
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// In multi-threaded operations (multi-FirebaseApp), you have to define JWTClass for each FirebaseApp,
// and set it to the FirebaseApp via FirebaseApp::setJWTProcessor(<JWTClass>), before calling initializeApp.
JWT.loop(app.getAuth());

Expand Down
Loading

0 comments on commit 58f5d48

Please sign in to comment.