Skip to content

Commit 45f8e32

Browse files
authored
App Check Desktop - GetToken and Listeners support (#1184)
* App Check Desktop - GetToken and Listeners support * Formatting * Update app_check_desktop.cc * Update app_check_desktop.cc * Cache the Provider * Update app_check_desktop.cc * Update app_check_desktop.cc
1 parent e61d6bb commit 45f8e32

File tree

3 files changed

+94
-6
lines changed

3 files changed

+94
-6
lines changed

app_check/integration_test/src/integration_test.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,18 @@ TEST_F(FirebaseAppCheckTest, TestGetTokenForcingRefresh) {
370370
EXPECT_NE(token.token, "");
371371
EXPECT_NE(token.expire_time_millis, 0);
372372

373+
// Wait a bit to make sure the expire time would be different
374+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
375+
373376
// GetToken with force_refresh=false will return the same token.
374377
firebase::Future<::firebase::app_check::AppCheckToken> future2 =
375378
app_check->GetAppCheckToken(false);
376379
EXPECT_TRUE(WaitForCompletion(future2, "GetToken #2"));
377380
EXPECT_EQ(future.result()->expire_time_millis,
378381
future2.result()->expire_time_millis);
379382

383+
std::this_thread::sleep_for(std::chrono::milliseconds(500));
384+
380385
// GetToken with force_refresh=true will return a new token.
381386
firebase::Future<::firebase::app_check::AppCheckToken> future3 =
382387
app_check->GetAppCheckToken(true);
@@ -452,7 +457,7 @@ TEST_F(FirebaseAppCheckTest, TestSignIn) {
452457
TEST_F(FirebaseAppCheckTest, TestDebugProviderValidToken) {
453458
firebase::app_check::DebugAppCheckProviderFactory* factory =
454459
firebase::app_check::DebugAppCheckProviderFactory::GetInstance();
455-
#if FIREBASE_PLATFORM_IOS
460+
#if FIREBASE_PLATFORM_IOS || FIREBASE_PLATFORM_DESKTOP
456461
ASSERT_NE(factory, nullptr);
457462
InitializeApp();
458463
firebase::app_check::AppCheckProvider* provider =

app_check/src/desktop/app_check_desktop.cc

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
#include "app_check/src/desktop/app_check_desktop.h"
1616

17+
#include <ctime>
18+
#include <string>
19+
1720
#include "app_check/src/common/common.h"
1821

1922
namespace firebase {
@@ -22,13 +25,16 @@ namespace internal {
2225

2326
static AppCheckProviderFactory* g_provider_factory = nullptr;
2427

25-
AppCheckInternal::AppCheckInternal(App* app) : app_(app) {
28+
AppCheckInternal::AppCheckInternal(App* app)
29+
: app_(app), cached_token_(), cached_provider_() {
2630
future_manager().AllocFutureApi(this, kAppCheckFnCount);
2731
}
2832

2933
AppCheckInternal::~AppCheckInternal() {
3034
future_manager().ReleaseFutureApi(this);
3135
app_ = nullptr;
36+
// Clear the cached token by setting the expiration
37+
cached_token_.expire_time_millis = 0;
3238
}
3339

3440
::firebase::App* AppCheckInternal::app() const { return app_; }
@@ -37,6 +43,29 @@ ReferenceCountedFutureImpl* AppCheckInternal::future() {
3743
return future_manager().GetFutureApi(this);
3844
}
3945

46+
bool AppCheckInternal::HasValidCacheToken() const {
47+
// Get the current time, in milliseconds
48+
int64_t current_time = std::time(nullptr) * 1000;
49+
// TODO(amaurice): Add some additional time to the check
50+
return cached_token_.expire_time_millis > current_time;
51+
}
52+
53+
void AppCheckInternal::UpdateCachedToken(AppCheckToken token) {
54+
cached_token_ = token;
55+
// Call the token listeners
56+
for (AppCheckListener* listener : token_listeners_) {
57+
listener->OnAppCheckTokenChanged(token);
58+
}
59+
}
60+
61+
AppCheckProvider* AppCheckInternal::GetProvider() {
62+
if (!cached_provider_ && g_provider_factory && app_) {
63+
cached_provider_ = g_provider_factory->CreateProvider(app_);
64+
}
65+
return cached_provider_;
66+
}
67+
68+
// static
4069
void AppCheckInternal::SetAppCheckProviderFactory(
4170
AppCheckProviderFactory* factory) {
4271
g_provider_factory = factory;
@@ -47,8 +76,30 @@ void AppCheckInternal::SetTokenAutoRefreshEnabled(
4776

4877
Future<AppCheckToken> AppCheckInternal::GetAppCheckToken(bool force_refresh) {
4978
auto handle = future()->SafeAlloc<AppCheckToken>(kAppCheckFnGetAppCheckToken);
50-
AppCheckToken token;
51-
future()->CompleteWithResult(handle, 0, token);
79+
if (!force_refresh && HasValidCacheToken()) {
80+
// If the cached token is valid, and not told to refresh, return the cache
81+
future()->CompleteWithResult(handle, 0, cached_token_);
82+
} else {
83+
// Get a new token, and pass the result into the future.
84+
AppCheckProvider* provider = GetProvider();
85+
if (provider != nullptr) {
86+
auto token_callback{
87+
[this, handle](firebase::app_check::AppCheckToken token,
88+
int error_code, const std::string& error_message) {
89+
if (error_code == firebase::app_check::kAppCheckErrorNone) {
90+
UpdateCachedToken(token);
91+
future()->CompleteWithResult(handle, 0, token);
92+
} else {
93+
future()->Complete(handle, error_code, error_message.c_str());
94+
}
95+
}};
96+
provider->GetToken(token_callback);
97+
} else {
98+
future()->Complete(
99+
handle, firebase::app_check::kAppCheckErrorInvalidConfiguration,
100+
"No AppCheckProvider installed.");
101+
}
102+
}
52103
return MakeFuture(future(), handle);
53104
}
54105

@@ -57,9 +108,23 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
57108
future()->LastResult(kAppCheckFnGetAppCheckToken));
58109
}
59110

60-
void AppCheckInternal::AddAppCheckListener(AppCheckListener* listener) {}
111+
void AppCheckInternal::AddAppCheckListener(AppCheckListener* listener) {
112+
if (listener) {
113+
token_listeners_.push_back(listener);
61114

62-
void AppCheckInternal::RemoveAppCheckListener(AppCheckListener* listener) {}
115+
// Following the Android pattern, if there is a cached token, call the
116+
// listener. Note that the iOS implementation does not do this.
117+
if (HasValidCacheToken()) {
118+
listener->OnAppCheckTokenChanged(cached_token_);
119+
}
120+
}
121+
}
122+
123+
void AppCheckInternal::RemoveAppCheckListener(AppCheckListener* listener) {
124+
if (listener) {
125+
token_listeners_.remove(listener);
126+
}
127+
}
63128

64129
} // namespace internal
65130
} // namespace app_check

app_check/src/desktop/app_check_desktop.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#ifndef FIREBASE_APP_CHECK_SRC_DESKTOP_APP_CHECK_DESKTOP_H_
1616
#define FIREBASE_APP_CHECK_SRC_DESKTOP_APP_CHECK_DESKTOP_H_
1717

18+
#include <list>
19+
1820
#include "app/src/future_manager.h"
1921
#include "app/src/include/firebase/app.h"
2022
#include "app/src/include/firebase/future.h"
@@ -49,9 +51,25 @@ class AppCheckInternal {
4951
ReferenceCountedFutureImpl* future();
5052

5153
private:
54+
// Is the cached token valid
55+
bool HasValidCacheToken() const;
56+
57+
// Update the cached Token, and call the listeners
58+
void UpdateCachedToken(AppCheckToken token);
59+
60+
// Get the Provider associated with the stored App used to create this.
61+
AppCheckProvider* GetProvider();
62+
5263
::firebase::App* app_;
5364

5465
FutureManager future_manager_;
66+
67+
// Cached provider for the App. Use GetProvider instead of this.
68+
AppCheckProvider* cached_provider_;
69+
// Cached token, can be expired.
70+
AppCheckToken cached_token_;
71+
// List of registered listeners for Token changes.
72+
std::list<AppCheckListener*> token_listeners_;
5573
};
5674

5775
} // namespace internal

0 commit comments

Comments
 (0)