14
14
15
15
#include " app_check/src/desktop/app_check_desktop.h"
16
16
17
+ #include < ctime>
18
+ #include < string>
19
+
17
20
#include " app_check/src/common/common.h"
18
21
19
22
namespace firebase {
@@ -22,13 +25,16 @@ namespace internal {
22
25
23
26
static AppCheckProviderFactory* g_provider_factory = nullptr ;
24
27
25
- AppCheckInternal::AppCheckInternal (App* app) : app_(app) {
28
+ AppCheckInternal::AppCheckInternal (App* app)
29
+ : app_(app), cached_token_(), cached_provider_() {
26
30
future_manager ().AllocFutureApi (this , kAppCheckFnCount );
27
31
}
28
32
29
33
AppCheckInternal::~AppCheckInternal () {
30
34
future_manager ().ReleaseFutureApi (this );
31
35
app_ = nullptr ;
36
+ // Clear the cached token by setting the expiration
37
+ cached_token_.expire_time_millis = 0 ;
32
38
}
33
39
34
40
::firebase::App* AppCheckInternal::app () const { return app_; }
@@ -37,6 +43,29 @@ ReferenceCountedFutureImpl* AppCheckInternal::future() {
37
43
return future_manager ().GetFutureApi (this );
38
44
}
39
45
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
40
69
void AppCheckInternal::SetAppCheckProviderFactory (
41
70
AppCheckProviderFactory* factory) {
42
71
g_provider_factory = factory;
@@ -47,8 +76,30 @@ void AppCheckInternal::SetTokenAutoRefreshEnabled(
47
76
48
77
Future<AppCheckToken> AppCheckInternal::GetAppCheckToken (bool force_refresh) {
49
78
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
+ }
52
103
return MakeFuture (future (), handle);
53
104
}
54
105
@@ -57,9 +108,23 @@ Future<AppCheckToken> AppCheckInternal::GetAppCheckTokenLastResult() {
57
108
future ()->LastResult (kAppCheckFnGetAppCheckToken ));
58
109
}
59
110
60
- void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {}
111
+ void AppCheckInternal::AddAppCheckListener (AppCheckListener* listener) {
112
+ if (listener) {
113
+ token_listeners_.push_back (listener);
61
114
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
+ }
63
128
64
129
} // namespace internal
65
130
} // namespace app_check
0 commit comments