Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class FirebaseAppCheckPlugin : FlutterFirebasePlugin, FlutterPlugin, FirebaseApp
androidProvider: String?,
appleProvider: String?,
debugToken: String?,
recaptchaSiteKey: String?,
callback: (Result<Unit>) -> Unit
) {
try {
Expand All @@ -64,8 +65,11 @@ class FirebaseAppCheckPlugin : FlutterFirebasePlugin, FlutterPlugin, FirebaseApp
DebugAppCheckProviderFactory.getInstance())
}
"recaptcha" -> {
firebaseAppCheck.installAppCheckProviderFactory(
RecaptchaAppCheckProviderFactory.getInstance())
if (recaptchaSiteKey == null) {
throw Exception("reCAPTCHA site key must not be null")
}
val factory = RecaptchaAppCheckProviderFactory.getInstance(recaptchaSiteKey)
firebaseAppCheck.installAppCheckProviderFactory(factory)
}
else -> {
firebaseAppCheck.installAppCheckProviderFactory(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ interface FirebaseAppCheckHostApi {
androidProvider: String?,
appleProvider: String?,
debugToken: String?,
recaptchaSiteKey: String?,
callback: (Result<Unit>) -> Unit
)

Expand Down Expand Up @@ -306,15 +307,20 @@ interface FirebaseAppCheckHostApi {
val androidProviderArg = args[1] as String?
val appleProviderArg = args[2] as String?
val debugTokenArg = args[3] as String?
api.activate(appNameArg, androidProviderArg, appleProviderArg, debugTokenArg) {
result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(GeneratedAndroidFirebaseAppCheckPigeonUtils.wrapError(error))
} else {
reply.reply(GeneratedAndroidFirebaseAppCheckPigeonUtils.wrapResult(null))
}
}
val recaptchaSiteKeyArg = args[4] as String?
api.activate(
appNameArg,
androidProviderArg,
appleProviderArg,
debugTokenArg,
recaptchaSiteKeyArg) { result: Result<Unit> ->
val error = result.exceptionOrNull()
if (error != null) {
reply.reply(GeneratedAndroidFirebaseAppCheckPigeonUtils.wrapError(error))
} else {
reply.reply(GeneratedAndroidFirebaseAppCheckPigeonUtils.wrapResult(null))
}
}
}
} else {
channel.setMessageHandler(null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import 'package:flutter/material.dart';

import 'firebase_options.dart';

const kWebRecaptchaSiteKey = '6Lemcn0dAAAAABLkf6aiiHvpGD6x-zF3nOSDU2M8';
const kWebRecaptchaSiteKey = 'put-default-web-sitekey';
const kIOSRecaptchaSiteKey = 'put-default-ios-sitekey';
const kAndroidRecaptchaSitekey = 'put-default-android-sitekey';

// Windows: create a debug token in the Firebase Console
// (App Check > Apps > Manage debug tokens), then paste it here
Expand Down Expand Up @@ -77,15 +79,36 @@ class FirebaseAppCheckExample extends StatefulWidget {

class _FirebaseAppCheck extends State<FirebaseAppCheckExample> {
final appCheck = FirebaseAppCheck.instance;
final TextEditingController _recaptchaSiteKeyController =
TextEditingController();
String _message = '';
String _eventToken = 'not yet';

String get _recaptchaSiteKey {
final text = _recaptchaSiteKeyController.text.trim();
if (text.isNotEmpty) return text;
if (kIsWeb) return kWebRecaptchaSiteKey;
if (defaultTargetPlatform == TargetPlatform.iOS) {
return kIOSRecaptchaSiteKey;
}
if (defaultTargetPlatform == TargetPlatform.android) {
return kAndroidRecaptchaSitekey;
}
return '';
}

@override
void initState() {
appCheck.onTokenChange.listen(setEventToken);
super.initState();
}

@override
void dispose() {
_recaptchaSiteKeyController.dispose();
super.dispose();
}

void setMessage(String message) {
setState(() {
_message = message;
Expand All @@ -101,18 +124,20 @@ class _FirebaseAppCheck extends State<FirebaseAppCheckExample> {
Future<void> _activate({
AndroidAppCheckProvider? android,
AppleAppCheckProvider? apple,
WebProvider? web,
WindowsAppCheckProvider? windows,
}) async {
try {
await appCheck.activate(
providerAndroid: android ?? const AndroidPlayIntegrityProvider(),
providerApple: apple ?? const AppleDeviceCheckProvider(),
providerWeb: ReCaptchaV3Provider(kWebRecaptchaSiteKey),
providerWeb: web ?? ReCaptchaV3Provider(kWebRecaptchaSiteKey),
providerWindows: windows ?? const WindowsDebugProvider(),
);
final providerName = windows?.runtimeType.toString() ??
apple?.runtimeType.toString() ??
android?.runtimeType.toString() ??
web?.runtimeType.toString() ??
'default';
setMessage('Activated with $providerName');
} catch (e) {
Expand Down Expand Up @@ -170,6 +195,24 @@ class _FirebaseAppCheck extends State<FirebaseAppCheckExample> {
'activate(AppAttest + DeviceCheck fallback)',
),
),
const SizedBox(height: 8),
TextField(
controller: _recaptchaSiteKeyController,
decoration: const InputDecoration(
labelText: 'reCAPTCHA Enterprise Site Key (optional)',
hintText: 'Leave empty to use default site key',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => _activate(
android: AndroidReCaptchaProvider(_recaptchaSiteKey),
apple: AppleReCaptchaProvider(_recaptchaSiteKey),
web: ReCaptchaEnterpriseProvider(_recaptchaSiteKey),
),
child: const Text('activate(ReCaptcha)'),
),
const SizedBox(height: 16),
const Text(
'Actions',
Expand Down
Loading
Loading