Skip to content

Commit 62255d7

Browse files
committed
Feat: add in limited use tokens to functions
1 parent 5f348b8 commit 62255d7

14 files changed

Lines changed: 218 additions & 13 deletions

File tree

app/src/function_registry.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum FunctionId {
3838
FnAppCheckGetTokenAsync,
3939
FnAppCheckAddListener,
4040
FnAppCheckRemoveListener,
41+
FnAppCheckGetLimitedUseTokenAsync,
4142
};
4243

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

app_check/src/common/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ enum AppCheckFn {
2424
kAppCheckFnGetAppCheckToken = 0,
2525
kAppCheckFnGetAppCheckStringInternal,
2626
kAppCheckFnGetLimitedUseAppCheckToken,
27+
kAppCheckFnGetLimitedUseAppCheckStringInternal,
2728
kAppCheckFnCount,
2829
};
2930

app_check/src/desktop/app_check_desktop.cc

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,30 @@ Future<std::string> AppCheckInternal::GetAppCheckTokenStringInternal() {
186186
return MakeFuture(future(), handle);
187187
}
188188

189+
Future<std::string> AppCheckInternal::GetLimitedUseAppCheckTokenStringInternal() {
190+
auto handle =
191+
future()->SafeAlloc<std::string>(kAppCheckFnGetLimitedUseAppCheckStringInternal);
192+
193+
AppCheckProvider* provider = GetProvider();
194+
if (provider != nullptr) {
195+
auto token_callback{
196+
[this, handle](firebase::app_check::AppCheckToken token,
197+
int error_code, const std::string& error_message) {
198+
if (error_code == firebase::app_check::kAppCheckErrorNone) {
199+
future()->CompleteWithResult(handle, 0, token.token);
200+
} else {
201+
future()->Complete(handle, error_code, error_message.c_str());
202+
}
203+
}};
204+
provider->GetLimitedUseToken(token_callback);
205+
} else {
206+
future()->Complete(
207+
handle, firebase::app_check::kAppCheckErrorInvalidConfiguration,
208+
"No AppCheckProvider installed.");
209+
}
210+
return MakeFuture(future(), handle);
211+
}
212+
189213
void AppCheckInternal::AddAppCheckListener(AppCheckListener* listener) {
190214
if (listener) {
191215
token_listeners_.push_back(listener);
@@ -211,6 +235,9 @@ void AppCheckInternal::InitRegistryCalls() {
211235
app_->function_registry()->RegisterFunction(
212236
::firebase::internal::FnAppCheckGetTokenAsync,
213237
AppCheckInternal::GetAppCheckTokenAsyncForRegistry);
238+
app_->function_registry()->RegisterFunction(
239+
::firebase::internal::FnAppCheckGetLimitedUseTokenAsync,
240+
AppCheckInternal::GetLimitedUseAppCheckTokenAsyncForRegistry);
214241
app_->function_registry()->RegisterFunction(
215242
::firebase::internal::FnAppCheckAddListener,
216243
AppCheckInternal::AddAppCheckListenerForRegistry);
@@ -226,6 +253,8 @@ void AppCheckInternal::CleanupRegistryCalls() {
226253
if (g_app_check_registry_count == 0) {
227254
app_->function_registry()->UnregisterFunction(
228255
::firebase::internal::FnAppCheckGetTokenAsync);
256+
app_->function_registry()->UnregisterFunction(
257+
::firebase::internal::FnAppCheckGetLimitedUseTokenAsync);
229258
app_->function_registry()->UnregisterFunction(
230259
::firebase::internal::FnAppCheckAddListener);
231260
app_->function_registry()->UnregisterFunction(
@@ -250,6 +279,24 @@ bool AppCheckInternal::GetAppCheckTokenAsyncForRegistry(App* app,
250279
return false;
251280
}
252281

282+
// static
283+
bool AppCheckInternal::GetLimitedUseAppCheckTokenAsyncForRegistry(App* app,
284+
void* /*unused*/,
285+
void* out) {
286+
Future<std::string>* out_future = static_cast<Future<std::string>*>(out);
287+
if (!app || !out_future) {
288+
return false;
289+
}
290+
291+
AppCheck* app_check = AppCheck::GetInstance(app);
292+
if (app_check && app_check->internal_) {
293+
*out_future =
294+
app_check->internal_->GetLimitedUseAppCheckTokenStringInternal();
295+
return true;
296+
}
297+
return false;
298+
}
299+
253300
void FunctionRegistryAppCheckListener::AddListener(
254301
FunctionRegistryCallback callback, void* context) {
255302
callbacks_.emplace_back(callback, context);

app_check/src/desktop/app_check_desktop.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ class AppCheckInternal {
7070
// internal methods to not conflict with the publicly returned future.
7171
Future<std::string> GetAppCheckTokenStringInternal();
7272

73+
// Gets the limited-use App Check token as just the string, to be used by
74+
// internal methods to not conflict with the publicly returned future.
75+
Future<std::string> GetLimitedUseAppCheckTokenStringInternal();
76+
7377
void AddAppCheckListener(AppCheckListener* listener);
7478

7579
void RemoveAppCheckListener(AppCheckListener* listener);
@@ -100,6 +104,9 @@ class AppCheckInternal {
100104
static bool GetAppCheckTokenAsyncForRegistry(App* app, void* /*unused*/,
101105
void* out_future);
102106

107+
static bool GetLimitedUseAppCheckTokenAsyncForRegistry(App* app, void* /*unused*/,
108+
void* out_future);
109+
103110
static bool AddAppCheckListenerForRegistry(App* app, void* callback,
104111
void* context);
105112

functions/src/android/functions_android.cc

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,18 @@ namespace internal {
3535
"(Ljava/lang/String;)" \
3636
"Lcom/google/firebase/functions/HttpsCallableReference;", \
3737
util::kMethodTypeInstance), \
38+
X(GetHttpsCallableWithOptions, "getHttpsCallable", \
39+
"(Ljava/lang/String;Lcom/google/firebase/functions/HttpsCallableOptions;)" \
40+
"Lcom/google/firebase/functions/HttpsCallableReference;", \
41+
util::kMethodTypeInstance), \
3842
X(GetHttpsCallableFromURL, "getHttpsCallableFromUrl", \
3943
"(Ljava/net/URL;)" \
4044
"Lcom/google/firebase/functions/HttpsCallableReference;", \
4145
util::kMethodTypeInstance), \
46+
X(GetHttpsCallableFromURLWithOptions, "getHttpsCallableFromUrl", \
47+
"(Ljava/net/URL;Lcom/google/firebase/functions/HttpsCallableOptions;)" \
48+
"Lcom/google/firebase/functions/HttpsCallableReference;", \
49+
util::kMethodTypeInstance), \
4250
X(UseFunctionsEmulator, "useFunctionsEmulator", \
4351
"(Ljava/lang/String;)V", \
4452
util::kMethodTypeInstance)
@@ -50,6 +58,21 @@ METHOD_LOOKUP_DEFINITION(firebase_functions,
5058
"com/google/firebase/functions/FirebaseFunctions",
5159
FIREBASE_FUNCTIONS_METHODS)
5260

61+
// clang-format off
62+
#define CALLABLE_OPTIONS_METHODS(X) \
63+
X(BuilderConstructor, "<init>", "()V"), \
64+
X(SetLimitedUseAppCheckTokens, "setLimitedUseAppCheckTokens", \
65+
"(Z)Lcom/google/firebase/functions/HttpsCallableOptions$Builder;"), \
66+
X(Build, "build", "()Lcom/google/firebase/functions/HttpsCallableOptions;")
67+
// clang-format on
68+
69+
METHOD_LOOKUP_DECLARATION(callable_options_builder, CALLABLE_OPTIONS_METHODS)
70+
METHOD_LOOKUP_DEFINITION(
71+
callable_options_builder,
72+
PROGUARD_KEEP_CLASS
73+
"com/google/firebase/functions/HttpsCallableOptions$Builder",
74+
CALLABLE_OPTIONS_METHODS)
75+
5376
// clang-format off
5477
#define FUNCTIONS_EXCEPTION_METHODS(X) \
5578
X(GetMessage, "getMessage", "()Ljava/lang/String;"), \
@@ -125,6 +148,7 @@ bool FunctionsInternal::Initialize(App* app) {
125148
functions_exception::CacheMethodIds(env, activity) &&
126149
functions_exception_code::CacheMethodIds(env, activity) &&
127150
functions_exception_code::CacheFieldIds(env, activity) &&
151+
callable_options_builder::CacheMethodIds(env, activity) &&
128152
// Call Initialize on all other Functions internal classes.
129153
HttpsCallableReferenceInternal::Initialize(app))) {
130154
return false;
@@ -144,6 +168,7 @@ void FunctionsInternal::Terminate(App* app) {
144168
firebase_functions::ReleaseClass(env);
145169
functions_exception::ReleaseClass(env);
146170
functions_exception_code::ReleaseClass(env);
171+
callable_options_builder::ReleaseClass(env);
147172

148173
// Call Terminate on all other Functions internal classes.
149174
HttpsCallableReferenceInternal::Terminate(app);
@@ -186,14 +211,37 @@ Error FunctionsInternal::ErrorFromJavaFunctionsException(
186211

187212
HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallable(
188213
const char* name) const {
214+
return GetHttpsCallable(name, HttpsCallableOptions());
215+
}
216+
217+
HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallable(
218+
const char* name, const HttpsCallableOptions& options) const {
189219
FIREBASE_ASSERT_RETURN(nullptr, name != nullptr);
190220
JNIEnv* env = app_->GetJNIEnv();
221+
222+
// Create HttpsCallableOptions
223+
jobject builder = env->NewObject(
224+
callable_options_builder::GetClass(),
225+
callable_options_builder::GetMethodId(callable_options_builder::kBuilderConstructor));
226+
jobject builder2 = env->CallObjectMethod(
227+
builder,
228+
callable_options_builder::GetMethodId(callable_options_builder::kSetLimitedUseAppCheckTokens),
229+
options.limited_use_app_check_token);
230+
env->DeleteLocalRef(builder);
231+
builder = builder2;
232+
jobject java_options = env->CallObjectMethod(
233+
builder,
234+
callable_options_builder::GetMethodId(callable_options_builder::kBuild));
235+
env->DeleteLocalRef(builder);
236+
191237
jobject name_string = env->NewStringUTF(name);
192238
jobject callable_reference_obj = env->CallObjectMethod(
193239
obj_,
194-
firebase_functions::GetMethodId(firebase_functions::kGetHttpsCallable),
195-
name_string);
240+
firebase_functions::GetMethodId(firebase_functions::kGetHttpsCallableWithOptions),
241+
name_string, java_options);
196242
env->DeleteLocalRef(name_string);
243+
env->DeleteLocalRef(java_options);
244+
197245
if (util::LogException(env, kLogLevelError,
198246
"Functions::GetHttpsCallable() (name = %s) failed",
199247
name)) {
@@ -208,15 +256,38 @@ HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallable(
208256

209257
HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallableFromURL(
210258
const char* url) const {
259+
return GetHttpsCallableFromURL(url, HttpsCallableOptions());
260+
}
261+
262+
HttpsCallableReferenceInternal* FunctionsInternal::GetHttpsCallableFromURL(
263+
const char* url, const HttpsCallableOptions& options) const {
211264
FIREBASE_ASSERT_RETURN(nullptr, url != nullptr);
212265
JNIEnv* env = app_->GetJNIEnv();
266+
267+
// Create HttpsCallableOptions
268+
jobject builder = env->NewObject(
269+
callable_options_builder::GetClass(),
270+
callable_options_builder::GetMethodId(callable_options_builder::kBuilderConstructor));
271+
jobject builder2 = env->CallObjectMethod(
272+
builder,
273+
callable_options_builder::GetMethodId(callable_options_builder::kSetLimitedUseAppCheckTokens),
274+
options.limited_use_app_check_token);
275+
env->DeleteLocalRef(builder);
276+
builder = builder2;
277+
jobject java_options = env->CallObjectMethod(
278+
builder,
279+
callable_options_builder::GetMethodId(callable_options_builder::kBuild));
280+
env->DeleteLocalRef(builder);
281+
213282
jobject url_object = util::CharsToURL(env, url);
214283
jobject callable_reference_obj =
215284
env->CallObjectMethod(obj_,
216285
firebase_functions::GetMethodId(
217-
firebase_functions::kGetHttpsCallableFromURL),
218-
url_object);
286+
firebase_functions::kGetHttpsCallableFromURLWithOptions),
287+
url_object, java_options);
219288
env->DeleteLocalRef(url_object);
289+
env->DeleteLocalRef(java_options);
290+
220291
if (util::LogException(
221292
env, kLogLevelError,
222293
"Functions::GetHttpsCallableFromURL() (url = %s) failed", url)) {

functions/src/android/functions_android.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,16 @@ class FunctionsInternal {
4949

5050
HttpsCallableReferenceInternal* GetHttpsCallable(const char* name) const;
5151

52+
HttpsCallableReferenceInternal* GetHttpsCallable(
53+
const char* name, const HttpsCallableOptions& options) const;
54+
5255
// Get a FunctionsReference for the specified URL.
5356
HttpsCallableReferenceInternal* GetHttpsCallableFromURL(
5457
const char* url) const;
5558

59+
HttpsCallableReferenceInternal* GetHttpsCallableFromURL(
60+
const char* url, const HttpsCallableOptions& options) const;
61+
5662
void UseFunctionsEmulator(const char* origin);
5763

5864
// Convert an error code obtained from a Java FunctionsException into a C++

functions/src/common/functions.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,12 +147,24 @@ HttpsCallableReference Functions::GetHttpsCallable(const char* name) const {
147147
return HttpsCallableReference(internal_->GetHttpsCallable(name));
148148
}
149149

150+
HttpsCallableReference Functions::GetHttpsCallable(
151+
const char* name, const HttpsCallableOptions& options) const {
152+
if (!internal_) return HttpsCallableReference();
153+
return HttpsCallableReference(internal_->GetHttpsCallable(name, options));
154+
}
155+
150156
HttpsCallableReference Functions::GetHttpsCallableFromURL(
151157
const char* url) const {
152158
if (!internal_) return HttpsCallableReference();
153159
return HttpsCallableReference(internal_->GetHttpsCallableFromURL(url));
154160
}
155161

162+
HttpsCallableReference Functions::GetHttpsCallableFromURL(
163+
const char* url, const HttpsCallableOptions& options) const {
164+
if (!internal_) return HttpsCallableReference();
165+
return HttpsCallableReference(internal_->GetHttpsCallableFromURL(url, options));
166+
}
167+
156168
void Functions::UseFunctionsEmulator(const char* origin) {
157169
if (!internal_) return;
158170
internal_->UseFunctionsEmulator(origin);

functions/src/desktop/callable_reference_desktop.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ enum CallableReferenceFn {
3434
};
3535

3636
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
37-
FunctionsInternal* functions, const char* url)
38-
: functions_(functions), url_(url) {
37+
FunctionsInternal* functions, const char* url,
38+
const HttpsCallableOptions& options)
39+
: functions_(functions), url_(url), options_(options) {
3940
functions_->future_manager().AllocFutureApi(this, kCallableReferenceFnCount);
4041
rest::InitTransportCurl();
4142
transport_.set_is_async(true);
@@ -48,7 +49,7 @@ HttpsCallableReferenceInternal::~HttpsCallableReferenceInternal() {
4849

4950
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
5051
const HttpsCallableReferenceInternal& other)
51-
: functions_(other.functions_), url_(other.url_) {
52+
: functions_(other.functions_), url_(other.url_), options_(other.options_) {
5253
functions_->future_manager().AllocFutureApi(this, kCallableReferenceFnCount);
5354
rest::InitTransportCurl();
5455
transport_.set_is_async(true);
@@ -58,13 +59,16 @@ HttpsCallableReferenceInternal& HttpsCallableReferenceInternal::operator=(
5859
const HttpsCallableReferenceInternal& other) {
5960
functions_ = other.functions_;
6061
url_ = other.url_;
62+
options_ = other.options_;
6163
return *this;
6264
}
6365

6466
#if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN)
6567
HttpsCallableReferenceInternal::HttpsCallableReferenceInternal(
6668
HttpsCallableReferenceInternal&& other)
67-
: functions_(other.functions_), url_(std::move(other.url_)) {
69+
: functions_(other.functions_),
70+
url_(std::move(other.url_)),
71+
options_(other.options_) {
6872
other.functions_ = nullptr;
6973
functions_->future_manager().MoveFutureApi(&other, this);
7074
rest::InitTransportCurl();
@@ -76,6 +80,7 @@ HttpsCallableReferenceInternal& HttpsCallableReferenceInternal::operator=(
7680
functions_ = other.functions_;
7781
other.functions_ = nullptr;
7882
url_ = std::move(other.url_);
83+
options_ = other.options_;
7984
functions_->future_manager().MoveFutureApi(&other, this);
8085
return *this;
8186
}
@@ -333,9 +338,12 @@ Future<HttpsCallableResult> HttpsCallableReferenceInternal::Call(
333338

334339
// Check for App Check token function
335340
Future<std::string> app_check_future;
341+
::firebase::internal::FunctionId token_function_id =
342+
options_.limited_use_app_check_token
343+
? ::firebase::internal::FnAppCheckGetLimitedUseTokenAsync
344+
: ::firebase::internal::FnAppCheckGetTokenAsync;
336345
bool succeeded = functions_->app()->function_registry()->CallFunction(
337-
::firebase::internal::FnAppCheckGetTokenAsync, functions_->app(), nullptr,
338-
&app_check_future);
346+
token_function_id, functions_->app(), nullptr, &app_check_future);
339347
if (succeeded && app_check_future.status() != kFutureStatusInvalid) {
340348
// Perform the transform request on a completion
341349
app_check_future.OnCompletion([&](const Future<std::string>& future_token) {

functions/src/desktop/callable_reference_desktop.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class HttpsCallableRequest : public rest::Request {
5454

5555
class HttpsCallableReferenceInternal {
5656
public:
57-
HttpsCallableReferenceInternal(FunctionsInternal* functions, const char* url);
57+
HttpsCallableReferenceInternal(FunctionsInternal* functions, const char* url,
58+
const HttpsCallableOptions& options);
5859
~HttpsCallableReferenceInternal();
5960

6061
// Copy constructor. It's totally okay (and efficient) to copy
@@ -112,6 +113,9 @@ class HttpsCallableReferenceInternal {
112113
// The URL of the endpoint this reference points to.
113114
std::string url_;
114115

116+
// Options for the callable reference.
117+
HttpsCallableOptions options_;
118+
115119
rest::TransportCurl transport_;
116120
// For now, we only allow one request per reference at a time in C++.
117121
// TODO(klimt): Figure out the lifetime issues enough to allow multiple

functions/src/desktop/functions_desktop.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ class FunctionsInternal {
3939
// Get a FunctionsReference for the specified path.
4040
HttpsCallableReferenceInternal* GetHttpsCallable(const char* name) const;
4141

42+
HttpsCallableReferenceInternal* GetHttpsCallable(
43+
const char* name, const HttpsCallableOptions& options) const;
44+
4245
// Get a FunctionsReference for the specified URL.
4346
HttpsCallableReferenceInternal* GetHttpsCallableFromURL(
4447
const char* url) const;
4548

49+
HttpsCallableReferenceInternal* GetHttpsCallableFromURL(
50+
const char* url, const HttpsCallableOptions& options) const;
51+
4652
void UseFunctionsEmulator(const char* origin);
4753

4854
// Returns the URL for the endpoint with the given name.

0 commit comments

Comments
 (0)