Skip to content

Commit

Permalink
feat(functions): pass limitedUseAppCheckToken option to Cloud Funct…
Browse files Browse the repository at this point in the history
…ion (#11402)
  • Loading branch information
russellwheatley committed Aug 10, 2023
1 parent b569f16 commit 9fce7f2
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 15 deletions.
4 changes: 2 additions & 2 deletions packages/cloud_functions/cloud_functions/android/build.gradle
Expand Up @@ -8,7 +8,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
classpath 'com.android.tools.build:gradle:8.0.1'
}
}

Expand Down Expand Up @@ -39,7 +39,7 @@ android {
if (project.android.hasProperty("namespace")) {
namespace 'io.flutter.plugins.firebase.functions'
}

compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand Down
Expand Up @@ -13,6 +13,7 @@
import com.google.firebase.FirebaseApp;
import com.google.firebase.functions.FirebaseFunctions;
import com.google.firebase.functions.FirebaseFunctionsException;
import com.google.firebase.functions.HttpsCallableOptions;
import com.google.firebase.functions.HttpsCallableReference;
import com.google.firebase.functions.HttpsCallableResult;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
Expand Down Expand Up @@ -74,6 +75,8 @@ private Task<Object> httpsFunctionCall(Map<String, Object> arguments) {
String functionUri = (String) arguments.get("functionUri");
String origin = (String) arguments.get("origin");
Integer timeout = (Integer) arguments.get("timeout");
boolean limitedUseAppCheckToken =
(boolean) Objects.requireNonNull(arguments.get("limitedUseAppCheckToken"));
Object parameters = arguments.get("parameters");

if (origin != null) {
Expand All @@ -82,12 +85,16 @@ private Task<Object> httpsFunctionCall(Map<String, Object> arguments) {
}

HttpsCallableReference httpsCallableReference;
HttpsCallableOptions options =
new HttpsCallableOptions.Builder()
.setLimitedUseAppCheckTokens(limitedUseAppCheckToken)
.build();

if (functionName != null) {
httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName);
httpsCallableReference = firebaseFunctions.getHttpsCallable(functionName, options);
} else if (functionUri != null) {
httpsCallableReference =
firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri));
firebaseFunctions.getHttpsCallableFromUrl(new URL(functionUri), options);
} else {
throw new IllegalArgumentException("Either functionName or functionUri must be set");
}
Expand Down
Expand Up @@ -26,13 +26,10 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
namespace 'io.flutter.plugins.firebase.functions.example'
compileSdkVersion 33
compileSdk 33

lintOptions {
disable 'InvalidPackage'
}

defaultConfig {
defaultConfig {
applicationId "io.flutter.plugins.firebase.functions.example"
minSdkVersion 16
targetSdkVersion 33
Expand All @@ -48,6 +45,9 @@ android {
signingConfig signingConfigs.debug
}
}
lint {
disable 'InvalidPackage'
}
}

flutter {
Expand Down
Expand Up @@ -86,6 +86,7 @@ - (void)httpsFunctionCall:(id)arguments withMethodCallResult:(FLTFirebaseMethodC
NSString *region = arguments[@"region"];
NSNumber *timeout = arguments[@"timeout"];
NSObject *parameters = arguments[@"parameters"];
NSNumber *limitedUseAppCheckToken = arguments[@"limitedUseAppCheckToken"];

FIRApp *app = [FLTFirebasePlugin firebaseAppNamed:appName];
FIRFunctions *functions = [FIRFunctions functionsForApp:app region:region];
Expand All @@ -94,12 +95,15 @@ - (void)httpsFunctionCall:(id)arguments withMethodCallResult:(FLTFirebaseMethodC
[functions useEmulatorWithHost:[url host] port:[[url port] intValue]];
}

FIRHTTPSCallableOptions *options = [[FIRHTTPSCallableOptions alloc]
initWithRequireLimitedUseAppCheckTokens:[limitedUseAppCheckToken boolValue]];

FIRHTTPSCallable *function;

if (![functionName isEqual:[NSNull null]]) {
function = [functions HTTPSCallableWithName:functionName];
function = [functions HTTPSCallableWithName:functionName options:options];
} else if (![functionUri isEqual:[NSNull null]]) {
function = [functions HTTPSCallableWithURL:[NSURL URLWithString:functionUri]];
function = [functions HTTPSCallableWithURL:[NSURL URLWithString:functionUri] options:options];
} else {
result.error(@"IllegalArgumentException", @"Either functionName or functionUri must be set",
nil, nil);
Expand Down
Expand Up @@ -5,10 +5,16 @@

/// Interface representing an HttpsCallable instance's options,
class HttpsCallableOptions {
/// Constructs a new [HttpsCallableOptions] instance with given timeout.
/// Constructs a new [HttpsCallableOptions] instance with given `timeout` & `limitedUseAppCheckToken`
/// Defaults [timeout] to 60 seconds.
HttpsCallableOptions({this.timeout = const Duration(seconds: 60)});
/// Defaults [limitedUseAppCheckToken] to `false`
HttpsCallableOptions(
{this.timeout = const Duration(seconds: 60),
this.limitedUseAppCheckToken = false});

/// Returns the timeout for this instance
Duration timeout;

/// Sets whether or not to use limited-use App Check tokens when invoking the associated function.
bool limitedUseAppCheckToken;
}
Expand Up @@ -28,6 +28,7 @@ class MethodChannelHttpsCallable extends HttpsCallablePlatform {
'region': functions.region,
'timeout': options.timeout.inMilliseconds,
'parameters': parameters,
'limitedUseAppCheckToken': options.limitedUseAppCheckToken,
});

if (result is Map) {
Expand Down
Expand Up @@ -89,6 +89,7 @@ void main() {
expect(httpsCallable!.options, isInstanceOf<HttpsCallableOptions>());
expect(httpsCallable!.options.timeout, isInstanceOf<Duration>());
expect(httpsCallable!.options.timeout.inMinutes, 1);
expect(httpsCallable!.options.limitedUseAppCheckToken, false);
});
});

Expand Down Expand Up @@ -119,6 +120,7 @@ void main() {
'region': functions!.region,
'timeout': httpsCallable!.options.timeout.inMilliseconds,
'parameters': kParameters,
'limitedUseAppCheckToken': false,
},
),
]);
Expand Down Expand Up @@ -149,6 +151,7 @@ void main() {
'region': functions!.region,
'timeout': httpsCallable!.options.timeout.inMilliseconds,
'parameters': kParameters,
'limitedUseAppCheckToken': false,
},
),
]);
Expand All @@ -169,6 +172,7 @@ void main() {
'region': functions!.region,
'timeout': httpsCallable!.options.timeout.inMilliseconds,
'parameters': null,
'limitedUseAppCheckToken': false,
},
),
]);
Expand All @@ -189,6 +193,7 @@ void main() {
'region': functions!.region,
'timeout': httpsCallable!.options.timeout.inMilliseconds,
'parameters': null,
'limitedUseAppCheckToken': false,
},
),
]);
Expand Down
Expand Up @@ -30,7 +30,9 @@ class HttpsCallableWeb extends HttpsCallablePlatform {

functions_interop.HttpsCallableOptions callableOptions =
functions_interop.HttpsCallableOptions(
timeout: options.timeout.inMilliseconds);
timeout: options.timeout.inMilliseconds,
limitedUseAppCheckTokens: options.limitedUseAppCheckToken,
);

late functions_interop.HttpsCallable callable;

Expand Down
Expand Up @@ -44,9 +44,12 @@ abstract class FunctionsJsImpl {
@JS('HttpsCallableOptions')
@anonymous
abstract class HttpsCallableOptions {
external factory HttpsCallableOptions({int? timeout});
external factory HttpsCallableOptions(
{int? timeout, bool? limitedUseAppCheckTokens});
external int get timeout;
external set timeout(int t);
external bool get limitedUseAppCheckTokens;
external set limitedUseAppCheckTokens(bool t);
}

/// An HttpsCallableResult wraps a single result from a function call.
Expand Down
Expand Up @@ -227,6 +227,21 @@ void main() {
// https://github.com/firebase/flutterfire/issues/9652
skip: defaultTargetPlatform == TargetPlatform.android,
);

test(
'allow passing of `limitedUseAppCheckToken` as option',
() async {
final instance = FirebaseFunctions.instance;
instance.useFunctionsEmulator('localhost', 5001);
final timeoutCallable = FirebaseFunctions.instance.httpsCallable(
kTestFunctionDefaultRegion,
options: HttpsCallableOptions(timeout: const Duration(seconds: 3), limitedUseAppCheckToken: true),
);

HttpsCallableResult results = await timeoutCallable(null);
expect(results.data, equals('null'));
},
);
});
});
}

0 comments on commit 9fce7f2

Please sign in to comment.