Skip to content

Commit 03b8d7e

Browse files
authored
Add App Check hooks for desktop rest calls (#1198)
* Add App Check hooks for desktop * Formatting * Update comments * Fix include problems * Update based on feedback * Update file format
1 parent a9248c8 commit 03b8d7e

File tree

23 files changed

+288
-78
lines changed

23 files changed

+288
-78
lines changed

admob/src/common/admob_common.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ FIREBASE_APP_REGISTER_CALLBACKS(
4141
if (app == ::firebase::App::GetInstance()) {
4242
firebase::admob::Terminate();
4343
}
44-
});
44+
},
45+
false);
4546

4647
namespace firebase {
4748
namespace admob {

analytics/src/analytics_common.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ FIREBASE_APP_REGISTER_CALLBACKS(
3939
if (app == ::firebase::App::GetInstance()) {
4040
firebase::analytics::Terminate();
4141
}
42-
});
42+
},
43+
false);
4344

4445
namespace firebase {
4546
namespace analytics {

app/src/function_registry.h

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum FunctionId {
3535
FnAuthGetCurrentUserUid,
3636
FnAuthAddAuthStateListener,
3737
FnAuthRemoveAuthStateListener,
38+
FnAppCheckGetTokenAsync,
3839
};
3940

4041
// Class for providing a generic way for firebase libraries to expose their

app/src/util.h

+10-6
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,18 @@ class AppCallback {
9191

9292
// Initialize a module instance.
9393
//
94-
// Right now all module auto-initialization is disabled by default. Module
95-
// initialization can be enabled on a case by case basis using
94+
// Module auto-initialization is determined by the enabled flag.
95+
// Most products should default to false, except for App Check which
96+
// needs to be aware of App creation, and may not require user calls.
97+
// Module initialization can be enabled on a case by case basis using
9698
// SetEnabledByName() before creating an App object, for example:
9799
// SetEnabledByName("analytics", true);
98-
AppCallback(const char* module_name, Created created, Destroyed destroyed)
100+
AppCallback(const char* module_name, Created created, Destroyed destroyed,
101+
bool enabled_by_default)
99102
: module_name_(module_name),
100103
created_(created),
101104
destroyed_(destroyed),
102-
enabled_(false) {
105+
enabled_(enabled_by_default) {
103106
AddCallback(this);
104107
}
105108

@@ -186,14 +189,15 @@ class AppCallback {
186189
// }
187190
// });
188191
#define FIREBASE_APP_REGISTER_CALLBACKS(module_name, created_code, \
189-
destroyed_code) \
192+
destroyed_code, enabled_by_default) \
190193
namespace firebase { \
191194
static InitResult module_name##Created(::firebase::App* app) { \
192195
created_code; \
193196
} \
194197
static void module_name##Destroyed(::firebase::App* app) { destroyed_code; } \
195198
static ::firebase::AppCallback module_name##_app_callback( \
196-
#module_name, module_name##Created, module_name##Destroyed); \
199+
#module_name, module_name##Created, module_name##Destroyed, \
200+
enabled_by_default); \
197201
/* This is a global symbol that is referenced from all compilation units */ \
198202
/* that include this module. */ \
199203
void* FIREBASE_APP_REGISTER_CALLBACKS_INITIALIZER_NAME(module_name) \

app_check/integration_test/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ endif()
234234
# Add the Firebase libraries to the target using the function from the SDK.
235235
add_subdirectory(${FIREBASE_CPP_SDK_DIR} bin/ EXCLUDE_FROM_ALL)
236236
# Note that firebase_app needs to be last in the list.
237-
set(firebase_libs firebase_app_check firebase_database firebase_auth firebase_app)
237+
set(firebase_libs firebase_app_check firebase_database firebase_storage firebase_auth firebase_app)
238238
set(gtest_libs gtest gmock)
239239
target_link_libraries(${integration_test_target_name} ${firebase_libs}
240240
${gtest_libs} ${ADDITIONAL_LIBS})

app_check/integration_test/src/integration_test.cc

+79-1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "firebase/auth.h"
3737
#include "firebase/database.h"
3838
#include "firebase/internal/platform.h"
39+
#include "firebase/storage.h"
3940
#include "firebase/util.h"
4041
#include "firebase_test_framework.h" // NOLINT
4142

@@ -106,6 +107,14 @@ class FirebaseAppCheckTest : public FirebaseTest {
106107
// Initialize everything needed for Database tests.
107108
void InitializeAppAuthDatabase();
108109

110+
// Initialize Firebase Storage.
111+
void InitializeStorage();
112+
// Shut down Firebase Storage.
113+
void TerminateStorage();
114+
115+
// Initialize everything needed for Storage tests.
116+
void InitializeAppAuthStorage();
117+
109118
firebase::database::DatabaseReference CreateWorkingPath(
110119
bool suppress_cleanup = false);
111120

@@ -114,8 +123,9 @@ class FirebaseAppCheckTest : public FirebaseTest {
114123

115124
bool initialized_;
116125
firebase::database::Database* database_;
117-
118126
std::vector<firebase::database::DatabaseReference> cleanup_paths_;
127+
128+
firebase::storage::Storage* storage_;
119129
};
120130

121131
// Listens for token changed notifications
@@ -157,6 +167,8 @@ void FirebaseAppCheckTest::TerminateAppCheck() {
157167
delete app_check;
158168
}
159169
}
170+
171+
firebase::app_check::AppCheck::SetAppCheckProviderFactory(nullptr);
160172
}
161173

162174
void FirebaseAppCheckTest::InitializeApp() {
@@ -189,6 +201,7 @@ FirebaseAppCheckTest::FirebaseAppCheckTest()
189201
app_(nullptr),
190202
auth_(nullptr),
191203
database_(nullptr),
204+
storage_(nullptr),
192205
cleanup_paths_() {
193206
FindFirebaseConfig(FIREBASE_CONFIG_STRING);
194207
}
@@ -201,6 +214,7 @@ FirebaseAppCheckTest::~FirebaseAppCheckTest() {
201214
void FirebaseAppCheckTest::TearDown() {
202215
// Teardown all the products
203216
TerminateDatabase();
217+
TerminateStorage();
204218
TerminateAuth();
205219
TerminateAppCheck();
206220
TerminateApp();
@@ -298,6 +312,43 @@ void FirebaseAppCheckTest::InitializeAppAuthDatabase() {
298312
InitializeDatabase();
299313
}
300314

315+
void FirebaseAppCheckTest::InitializeStorage() {
316+
LogDebug("Initializing Firebase Storage.");
317+
318+
::firebase::ModuleInitializer initializer;
319+
initializer.Initialize(
320+
app_, &storage_, [](::firebase::App* app, void* target) {
321+
LogDebug("Attempting to initialize Firebase Storage.");
322+
::firebase::InitResult result;
323+
*reinterpret_cast<firebase::storage::Storage**>(target) =
324+
firebase::storage::Storage::GetInstance(app, &result);
325+
return result;
326+
});
327+
328+
WaitForCompletion(initializer.InitializeLastResult(), "InitializeStorage");
329+
330+
ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
331+
<< initializer.InitializeLastResult().error_message();
332+
333+
LogDebug("Successfully initialized Firebase Storage.");
334+
}
335+
336+
void FirebaseAppCheckTest::TerminateStorage() {
337+
if (storage_) {
338+
LogDebug("Shutdown the Storage library.");
339+
delete storage_;
340+
storage_ = nullptr;
341+
}
342+
343+
ProcessEvents(100);
344+
}
345+
346+
void FirebaseAppCheckTest::InitializeAppAuthStorage() {
347+
InitializeApp();
348+
InitializeAuth();
349+
InitializeStorage();
350+
}
351+
301352
void FirebaseAppCheckTest::SignIn() {
302353
if (auth_->current_user() != nullptr) {
303354
// Already signed in.
@@ -674,4 +725,31 @@ TEST_F(FirebaseAppCheckTest, DISABLED_TestRunTransaction) {
674725
}
675726
}
676727

728+
TEST_F(FirebaseAppCheckTest, TestStorageReadFile) {
729+
InitializeAppCheckWithDebug();
730+
InitializeAppAuthStorage();
731+
firebase::storage::StorageReference ref = storage_->GetReference("test.txt");
732+
EXPECT_TRUE(ref.is_valid());
733+
const size_t kBufferSize = 128;
734+
char buffer[kBufferSize];
735+
memset(buffer, 0, sizeof(buffer));
736+
firebase::Future<size_t> future = ref.GetBytes(buffer, kBufferSize);
737+
WaitForCompletion(future, "GetBytes", firebase::storage::kErrorNone);
738+
LogDebug(" buffer: %s", buffer);
739+
}
740+
741+
TEST_F(FirebaseAppCheckTest, TestStorageReadFileUnauthenticated) {
742+
// Don't set up AppCheck
743+
InitializeAppAuthStorage();
744+
firebase::storage::StorageReference ref = storage_->GetReference("test.txt");
745+
EXPECT_TRUE(ref.is_valid());
746+
const size_t kBufferSize = 128;
747+
char buffer[kBufferSize];
748+
memset(buffer, 0, sizeof(buffer));
749+
firebase::Future<size_t> future = ref.GetBytes(buffer, kBufferSize);
750+
WaitForCompletion(future, "GetBytes",
751+
firebase::storage::kErrorUnauthenticated);
752+
LogDebug(" buffer: %s", buffer);
753+
}
754+
677755
} // namespace firebase_testapp_automated

app_check/src/common/app_check.cc

+36-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "app/src/include/firebase/version.h"
2727
#include "app/src/log.h"
2828
#include "app/src/util.h"
29+
#include "app_check/src/common/common.h"
2930

3031
// Include the header that matches the platform being used.
3132
#if FIREBASE_PLATFORM_ANDROID
@@ -38,11 +39,22 @@
3839
// FIREBASE_PLATFORM_TVOS
3940

4041
// Register the module initializer.
41-
FIREBASE_APP_REGISTER_CALLBACKS(app_check,
42-
{ return ::firebase::kInitResultSuccess; },
43-
{
44-
// Nothing to tear down.
45-
});
42+
FIREBASE_APP_REGISTER_CALLBACKS(
43+
app_check,
44+
{
45+
// Create the AppCheck object for the given app.
46+
::firebase::app_check::AppCheck::GetInstance(app);
47+
return ::firebase::kInitResultSuccess;
48+
},
49+
{
50+
::firebase::app_check::AppCheck* app_check =
51+
::firebase::app_check::internal::GetExistingAppCheckInstance(app);
52+
if (app_check) {
53+
delete app_check;
54+
}
55+
},
56+
// App Check wants to be turned on by default
57+
true);
4658

4759
namespace firebase {
4860
namespace app_check {
@@ -57,7 +69,26 @@ AppCheckListener::~AppCheckListener() {}
5769
AppCheckProvider::~AppCheckProvider() {}
5870
AppCheckProviderFactory::~AppCheckProviderFactory() {}
5971

72+
namespace internal {
73+
74+
AppCheck* GetExistingAppCheckInstance(::firebase::App* app) {
75+
if (!app) return nullptr;
76+
77+
MutexLock lock(g_app_check_lock);
78+
if (g_app_check_map) {
79+
auto it = g_app_check_map->find(app);
80+
if (it != g_app_check_map->end()) {
81+
return it->second;
82+
}
83+
}
84+
return nullptr;
85+
}
86+
87+
} // namespace internal
88+
6089
AppCheck* AppCheck::GetInstance(::firebase::App* app) {
90+
if (!app) return nullptr;
91+
6192
MutexLock lock(g_app_check_lock);
6293
if (!g_app_check_map) {
6394
g_app_check_map = new std::map<::firebase::App*, AppCheck*>();

app_check/src/common/common.h

+6
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ namespace firebase {
1919
namespace app_check {
2020
namespace internal {
2121

22+
// Used by App Check functions that return a future
2223
enum AppCheckFn {
2324
kAppCheckFnGetAppCheckToken = 0,
2425
kAppCheckFnCount,
2526
};
2627

28+
// Helper function to get an existing AppCheck instance or nullptr,
29+
// if an instance does not already exist.
30+
::firebase::app_check::AppCheck* GetExistingAppCheckInstance(
31+
::firebase::App* app);
32+
2733
} // namespace internal
2834
} // namespace app_check
2935
} // namespace firebase

app_check/src/desktop/app_check_desktop.cc

+43
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <ctime>
1818
#include <string>
1919

20+
#include "app/src/function_registry.h"
21+
#include "app/src/log.h"
2022
#include "app_check/src/common/common.h"
2123

2224
namespace firebase {
@@ -28,10 +30,12 @@ static AppCheckProviderFactory* g_provider_factory = nullptr;
2830
AppCheckInternal::AppCheckInternal(App* app)
2931
: app_(app), cached_token_(), cached_provider_() {
3032
future_manager().AllocFutureApi(this, kAppCheckFnCount);
33+
InitRegistryCalls();
3134
}
3235

3336
AppCheckInternal::~AppCheckInternal() {
3437
future_manager().ReleaseFutureApi(this);
38+
CleanupRegistryCalls();
3539
app_ = nullptr;
3640
// Clear the cached token by setting the expiration
3741
cached_token_.expire_time_millis = 0;
@@ -126,6 +130,45 @@ void AppCheckInternal::RemoveAppCheckListener(AppCheckListener* listener) {
126130
}
127131
}
128132

133+
static int g_app_check_registry_count = 0;
134+
135+
void AppCheckInternal::InitRegistryCalls() {
136+
if (g_app_check_registry_count == 0) {
137+
app_->function_registry()->RegisterFunction(
138+
::firebase::internal::FnAppCheckGetTokenAsync,
139+
AppCheckInternal::GetAppCheckTokenAsyncForRegistry);
140+
}
141+
g_app_check_registry_count++;
142+
}
143+
144+
void AppCheckInternal::CleanupRegistryCalls() {
145+
g_app_check_registry_count--;
146+
if (g_app_check_registry_count == 0) {
147+
app_->function_registry()->UnregisterFunction(
148+
::firebase::internal::FnAppCheckGetTokenAsync);
149+
}
150+
}
151+
152+
// Static functions used by the internal registry tool
153+
bool AppCheckInternal::GetAppCheckTokenAsyncForRegistry(App* app,
154+
void* /*unused*/,
155+
void* out) {
156+
Future<AppCheckToken>* out_future = static_cast<Future<AppCheckToken>*>(out);
157+
if (!app || !out_future) {
158+
return false;
159+
}
160+
161+
AppCheck* app_check = AppCheck::GetInstance(app);
162+
if (app_check) {
163+
// TODO(amaurice): This should call some internal function instead of the
164+
// public one, since this will change the *LastResult value behind the
165+
// scenes.
166+
*out_future = app_check->GetAppCheckToken(false);
167+
return true;
168+
}
169+
return false;
170+
}
171+
129172
} // namespace internal
130173
} // namespace app_check
131174
} // namespace firebase

app_check/src/desktop/app_check_desktop.h

+12
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ class AppCheckInternal {
6060
// Get the Provider associated with the stored App used to create this.
6161
AppCheckProvider* GetProvider();
6262

63+
// Adds internal App Check functions to the function registry, which other
64+
// products can then call to get App Check information without needing a
65+
// direct dependency.
66+
void InitRegistryCalls();
67+
68+
// Removes those functions from the registry.
69+
void CleanupRegistryCalls();
70+
71+
// Gets a Future<AppCheckToken> for the given App, stored in the out_future.
72+
static bool GetAppCheckTokenAsyncForRegistry(App* app, void* /*unused*/,
73+
void* out_future);
74+
6375
::firebase::App* app_;
6476

6577
FutureManager future_manager_;

auth/src/auth.cc

+6-5
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@
4343
#endif // FIREBASE_PLATFORM_WINDOWS
4444

4545
// Register the module initializer.
46-
FIREBASE_APP_REGISTER_CALLBACKS(auth,
47-
{ return ::firebase::kInitResultSuccess; },
48-
{
49-
// Nothing to tear down.
50-
});
46+
FIREBASE_APP_REGISTER_CALLBACKS(
47+
auth, { return ::firebase::kInitResultSuccess; },
48+
{
49+
// Nothing to tear down.
50+
},
51+
false);
5152

5253
namespace firebase {
5354
namespace auth {

0 commit comments

Comments
 (0)