diff --git a/packages/firebase_app_check/firebase_app_check/android/build.gradle b/packages/firebase_app_check/firebase_app_check/android/build.gradle index 45c2fa4d6345..81e347abd98e 100644 --- a/packages/firebase_app_check/firebase_app_check/android/build.gradle +++ b/packages/firebase_app_check/firebase_app_check/android/build.gradle @@ -80,6 +80,7 @@ android { implementation platform("com.google.firebase:firebase-bom:${getRootProjectExtOrCoreProperty("FirebaseSDKVersion", firebaseCoreProject)}") implementation 'com.google.firebase:firebase-appcheck-debug' implementation 'com.google.firebase:firebase-appcheck-playintegrity' + implementation 'com.google.firebase:firebase-appcheck-recaptchaenterprise:16.0.0-beta01' implementation 'androidx.annotation:annotation:1.7.0' } } diff --git a/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/FirebaseAppCheckPlugin.kt b/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/FirebaseAppCheckPlugin.kt index 0dc0ce26dc7e..4bb063508300 100644 --- a/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/FirebaseAppCheckPlugin.kt +++ b/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/FirebaseAppCheckPlugin.kt @@ -9,6 +9,7 @@ import com.google.firebase.FirebaseApp import com.google.firebase.appcheck.FirebaseAppCheck import com.google.firebase.appcheck.debug.DebugAppCheckProviderFactory import com.google.firebase.appcheck.playintegrity.PlayIntegrityAppCheckProviderFactory +import com.google.firebase.appcheck.recaptchaenterprise.RecaptchaEnterpriseAppCheckProviderFactory import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding import io.flutter.plugin.common.BinaryMessenger @@ -55,6 +56,7 @@ class FirebaseAppCheckPlugin : androidProvider: String?, appleProvider: String?, debugToken: String?, + recaptchaEnterpriseSiteKey: String?, callback: (Result) -> Unit ) { try { @@ -66,6 +68,16 @@ class FirebaseAppCheckPlugin : DebugAppCheckProviderFactory.getInstance() ) } + "recaptchaEnterprise" -> { + if (recaptchaEnterpriseSiteKey != null) { + firebaseAppCheck.installAppCheckProviderFactory( + RecaptchaEnterpriseAppCheckProviderFactory.getInstance(recaptchaEnterpriseSiteKey) + ) + } else { + callback(Result.failure(FlutterError("invalid-argument", "Site key is required for reCAPTCHA Enterprise", null))) + return + } + } else -> { firebaseAppCheck.installAppCheckProviderFactory( PlayIntegrityAppCheckProviderFactory.getInstance() diff --git a/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/GeneratedAndroidFirebaseAppCheck.g.kt b/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/GeneratedAndroidFirebaseAppCheck.g.kt index 0a046dd5aa47..099f8514464d 100644 --- a/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/GeneratedAndroidFirebaseAppCheck.g.kt +++ b/packages/firebase_app_check/firebase_app_check/android/src/main/kotlin/io/flutter/plugins/firebase/appcheck/GeneratedAndroidFirebaseAppCheck.g.kt @@ -1,7 +1,7 @@ // Copyright 2025, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @@ -49,7 +49,7 @@ class FlutterError ( val code: String, override val message: String? = null, val details: Any? = null -) : Throwable() +) : RuntimeException() private open class GeneratedAndroidFirebaseAppCheckPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return super.readValueOfType(type, buffer) @@ -62,7 +62,7 @@ private open class GeneratedAndroidFirebaseAppCheckPigeonCodec : StandardMessage /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ interface FirebaseAppCheckHostApi { - fun activate(appName: String, androidProvider: String?, appleProvider: String?, debugToken: String?, callback: (Result) -> Unit) + fun activate(appName: String, androidProvider: String?, appleProvider: String?, debugToken: String?, recaptchaEnterpriseSiteKey: String?, callback: (Result) -> Unit) fun getToken(appName: String, forceRefresh: Boolean, callback: (Result) -> Unit) fun setTokenAutoRefreshEnabled(appName: String, isTokenAutoRefreshEnabled: Boolean, callback: (Result) -> Unit) fun registerTokenListener(appName: String, callback: (Result) -> Unit) @@ -86,7 +86,8 @@ 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 -> + val recaptchaEnterpriseSiteKeyArg = args[4] as String? + api.activate(appNameArg, androidProviderArg, appleProviderArg, debugTokenArg, recaptchaEnterpriseSiteKeyArg) { result: Result -> val error = result.exceptionOrNull() if (error != null) { reply.reply(GeneratedAndroidFirebaseAppCheckPigeonUtils.wrapError(error)) diff --git a/packages/firebase_app_check/firebase_app_check/example/android/build.gradle b/packages/firebase_app_check/firebase_app_check/example/android/build.gradle index d2ffbffa4cd2..c63004eaacea 100644 --- a/packages/firebase_app_check/firebase_app_check/example/android/build.gradle +++ b/packages/firebase_app_check/firebase_app_check/example/android/build.gradle @@ -1,5 +1,6 @@ allprojects { repositories { + mavenLocal() google() mavenCentral() } diff --git a/packages/firebase_app_check/firebase_app_check/example/android/settings.gradle b/packages/firebase_app_check/firebase_app_check/example/android/settings.gradle index 30463c1cf2f2..4fb566e9929e 100644 --- a/packages/firebase_app_check/firebase_app_check/example/android/settings.gradle +++ b/packages/firebase_app_check/firebase_app_check/example/android/settings.gradle @@ -22,7 +22,7 @@ plugins { // START: FlutterFire Configuration id "com.google.gms.google-services" version "4.3.15" apply false // END: FlutterFire Configuration - id "org.jetbrains.kotlin.android" version "1.9.22" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" diff --git a/packages/firebase_app_check/firebase_app_check/example/lib/main.dart b/packages/firebase_app_check/firebase_app_check/example/lib/main.dart index 8f26c6439a83..415cda451750 100644 --- a/packages/firebase_app_check/firebase_app_check/example/lib/main.dart +++ b/packages/firebase_app_check/firebase_app_check/example/lib/main.dart @@ -79,13 +79,21 @@ class _FirebaseAppCheck extends State { final appCheck = FirebaseAppCheck.instance; String _message = ''; String _eventToken = 'not yet'; + late final TextEditingController _siteKeyController; @override void initState() { + _siteKeyController = TextEditingController(text: kWebRecaptchaSiteKey); appCheck.onTokenChange.listen(setEventToken); super.initState(); } + @override + void dispose() { + _siteKeyController.dispose(); + super.dispose(); + } + void setMessage(String message) { setState(() { _message = message; @@ -101,16 +109,25 @@ class _FirebaseAppCheck extends State { Future _activate({ AndroidAppCheckProvider? android, AppleAppCheckProvider? apple, + String? webProviderType, WindowsAppCheckProvider? windows, }) async { try { + dynamic providerWeb; + if (webProviderType == 'enterprise') { + providerWeb = ReCaptchaEnterpriseProvider(_siteKeyController.text); + } else if (webProviderType == 'v3') { + providerWeb = ReCaptchaV3Provider(_siteKeyController.text); + } + await appCheck.activate( providerAndroid: android ?? const AndroidPlayIntegrityProvider(), providerApple: apple ?? const AppleDeviceCheckProvider(), - providerWeb: ReCaptchaV3Provider(kWebRecaptchaSiteKey), + providerWeb: providerWeb, providerWindows: windows ?? const WindowsDebugProvider(), ); final providerName = windows?.runtimeType.toString() ?? + webProviderType ?? apple?.runtimeType.toString() ?? android?.runtimeType.toString() ?? 'default'; @@ -170,6 +187,27 @@ class _FirebaseAppCheck extends State { 'activate(AppAttest + DeviceCheck fallback)', ), ), + const SizedBox(height: 8), + TextField( + controller: _siteKeyController, + decoration: const InputDecoration( + labelText: 'reCAPTCHA Site Key', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 8), + ElevatedButton( + onPressed: () => _activate( + android: AndroidReCaptchaEnterpriseProvider(siteKey: _siteKeyController.text), + ), + child: const Text('activate(Android reCAPTCHA Enterprise)'), + ), + ElevatedButton( + onPressed: () => _activate( + webProviderType: 'enterprise', + ), + child: const Text('activate(Web reCAPTCHA Enterprise)'), + ), const SizedBox(height: 16), const Text( 'Actions', diff --git a/packages/firebase_app_check/firebase_app_check/ios/firebase_app_check/Sources/firebase_app_check/FirebaseAppCheckMessages.g.swift b/packages/firebase_app_check/firebase_app_check/ios/firebase_app_check/Sources/firebase_app_check/FirebaseAppCheckMessages.g.swift index 1842cfe9c240..bc76bee940f7 100644 --- a/packages/firebase_app_check/firebase_app_check/ios/firebase_app_check/Sources/firebase_app_check/FirebaseAppCheckMessages.g.swift +++ b/packages/firebase_app_check/firebase_app_check/ios/firebase_app_check/Sources/firebase_app_check/FirebaseAppCheckMessages.g.swift @@ -1,7 +1,7 @@ // Copyright 2025, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -27,12 +27,13 @@ final class PigeonError: Error { } var localizedDescription: String { - "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" + return + "PigeonError(code: \(code), message: \(message ?? ""), details: \(details ?? "")" } } private func wrapResult(_ result: Any?) -> [Any?] { - [result] + return [result] } private func wrapError(_ error: Any) -> [Any?] { @@ -52,13 +53,13 @@ private func wrapError(_ error: Any) -> [Any?] { } return [ "\(error)", - "\(type(of: error))", + "\(Swift.type(of: error))", "Stacktrace: \(Thread.callStackSymbols)", ] } private func isNullish(_ value: Any?) -> Bool { - value is NSNull || value == nil + return value is NSNull || value == nil } private func nilOrValue(_ value: Any?) -> T? { @@ -66,73 +67,57 @@ private func nilOrValue(_ value: Any?) -> T? { return value as! T? } -private class FirebaseAppCheckMessagesPigeonCodecReader: FlutterStandardReader {} -private class FirebaseAppCheckMessagesPigeonCodecWriter: FlutterStandardWriter {} +private class FirebaseAppCheckMessagesPigeonCodecReader: FlutterStandardReader { +} + +private class FirebaseAppCheckMessagesPigeonCodecWriter: FlutterStandardWriter { +} private class FirebaseAppCheckMessagesPigeonCodecReaderWriter: FlutterStandardReaderWriter { override func reader(with data: Data) -> FlutterStandardReader { - FirebaseAppCheckMessagesPigeonCodecReader(data: data) + return FirebaseAppCheckMessagesPigeonCodecReader(data: data) } override func writer(with data: NSMutableData) -> FlutterStandardWriter { - FirebaseAppCheckMessagesPigeonCodecWriter(data: data) + return FirebaseAppCheckMessagesPigeonCodecWriter(data: data) } } class FirebaseAppCheckMessagesPigeonCodec: FlutterStandardMessageCodec, @unchecked Sendable { - static let shared = - FirebaseAppCheckMessagesPigeonCodec( - readerWriter: FirebaseAppCheckMessagesPigeonCodecReaderWriter() - ) + static let shared = FirebaseAppCheckMessagesPigeonCodec(readerWriter: FirebaseAppCheckMessagesPigeonCodecReaderWriter()) } + /// Generated protocol from Pigeon that represents a handler of messages from Flutter. protocol FirebaseAppCheckHostApi { - func activate(appName: String, androidProvider: String?, appleProvider: String?, - debugToken: String?, completion: @escaping (Result) -> Void) - func getToken(appName: String, forceRefresh: Bool, - completion: @escaping (Result) -> Void) - func setTokenAutoRefreshEnabled(appName: String, isTokenAutoRefreshEnabled: Bool, - completion: @escaping (Result) -> Void) + func activate(appName: String, androidProvider: String?, appleProvider: String?, debugToken: String?, recaptchaEnterpriseSiteKey: String?, completion: @escaping (Result) -> Void) + func getToken(appName: String, forceRefresh: Bool, completion: @escaping (Result) -> Void) + func setTokenAutoRefreshEnabled(appName: String, isTokenAutoRefreshEnabled: Bool, completion: @escaping (Result) -> Void) func registerTokenListener(appName: String, completion: @escaping (Result) -> Void) - func getLimitedUseAppCheckToken(appName: String, - completion: @escaping (Result) -> Void) + func getLimitedUseAppCheckToken(appName: String, completion: @escaping (Result) -> Void) } /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. class FirebaseAppCheckHostApiSetup { - static var codec: FlutterStandardMessageCodec { - FirebaseAppCheckMessagesPigeonCodec.shared - } - - /// Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through the - /// `binaryMessenger`. - static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseAppCheckHostApi?, - messageChannelSuffix: String = "") { + static var codec: FlutterStandardMessageCodec { FirebaseAppCheckMessagesPigeonCodec.shared } + /// Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: FirebaseAppCheckHostApi?, messageChannelSuffix: String = "") { let channelSuffix = messageChannelSuffix.count > 0 ? ".\(messageChannelSuffix)" : "" - let activateChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate\(channelSuffix)", - binaryMessenger: binaryMessenger, - codec: codec - ) - if let api { + let activateChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { activateChannel.setMessageHandler { message, reply in let args = message as! [Any?] let appNameArg = args[0] as! String let androidProviderArg: String? = nilOrValue(args[1]) let appleProviderArg: String? = nilOrValue(args[2]) let debugTokenArg: String? = nilOrValue(args[3]) - api.activate( - appName: appNameArg, - androidProvider: androidProviderArg, - appleProvider: appleProviderArg, - debugToken: debugTokenArg - ) { result in + let recaptchaEnterpriseSiteKeyArg: String? = nilOrValue(args[4]) + api.activate(appName: appNameArg, androidProvider: androidProviderArg, appleProvider: appleProviderArg, debugToken: debugTokenArg, recaptchaEnterpriseSiteKey: recaptchaEnterpriseSiteKeyArg) { result in switch result { case .success: reply(wrapResult(nil)) - case let .failure(error): + case .failure(let error): reply(wrapError(error)) } } @@ -140,21 +125,17 @@ class FirebaseAppCheckHostApiSetup { } else { activateChannel.setMessageHandler(nil) } - let getTokenChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getToken\(channelSuffix)", - binaryMessenger: binaryMessenger, - codec: codec - ) - if let api { + let getTokenChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getToken\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { getTokenChannel.setMessageHandler { message, reply in let args = message as! [Any?] let appNameArg = args[0] as! String let forceRefreshArg = args[1] as! Bool api.getToken(appName: appNameArg, forceRefresh: forceRefreshArg) { result in switch result { - case let .success(res): + case .success(let res): reply(wrapResult(res)) - case let .failure(error): + case .failure(let error): reply(wrapError(error)) } } @@ -162,24 +143,17 @@ class FirebaseAppCheckHostApiSetup { } else { getTokenChannel.setMessageHandler(nil) } - let setTokenAutoRefreshEnabledChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled\(channelSuffix)", - binaryMessenger: binaryMessenger, - codec: codec - ) - if let api { + let setTokenAutoRefreshEnabledChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { setTokenAutoRefreshEnabledChannel.setMessageHandler { message, reply in let args = message as! [Any?] let appNameArg = args[0] as! String let isTokenAutoRefreshEnabledArg = args[1] as! Bool - api.setTokenAutoRefreshEnabled( - appName: appNameArg, - isTokenAutoRefreshEnabled: isTokenAutoRefreshEnabledArg - ) { result in + api.setTokenAutoRefreshEnabled(appName: appNameArg, isTokenAutoRefreshEnabled: isTokenAutoRefreshEnabledArg) { result in switch result { case .success: reply(wrapResult(nil)) - case let .failure(error): + case .failure(let error): reply(wrapError(error)) } } @@ -187,20 +161,16 @@ class FirebaseAppCheckHostApiSetup { } else { setTokenAutoRefreshEnabledChannel.setMessageHandler(nil) } - let registerTokenListenerChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.registerTokenListener\(channelSuffix)", - binaryMessenger: binaryMessenger, - codec: codec - ) - if let api { + let registerTokenListenerChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.registerTokenListener\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { registerTokenListenerChannel.setMessageHandler { message, reply in let args = message as! [Any?] let appNameArg = args[0] as! String api.registerTokenListener(appName: appNameArg) { result in switch result { - case let .success(res): + case .success(let res): reply(wrapResult(res)) - case let .failure(error): + case .failure(let error): reply(wrapError(error)) } } @@ -208,20 +178,16 @@ class FirebaseAppCheckHostApiSetup { } else { registerTokenListenerChannel.setMessageHandler(nil) } - let getLimitedUseAppCheckTokenChannel = FlutterBasicMessageChannel( - name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getLimitedUseAppCheckToken\(channelSuffix)", - binaryMessenger: binaryMessenger, - codec: codec - ) - if let api { + let getLimitedUseAppCheckTokenChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getLimitedUseAppCheckToken\(channelSuffix)", binaryMessenger: binaryMessenger, codec: codec) + if let api = api { getLimitedUseAppCheckTokenChannel.setMessageHandler { message, reply in let args = message as! [Any?] let appNameArg = args[0] as! String api.getLimitedUseAppCheckToken(appName: appNameArg) { result in switch result { - case let .success(res): + case .success(let res): reply(wrapResult(res)) - case let .failure(error): + case .failure(let error): reply(wrapError(error)) } } diff --git a/packages/firebase_app_check/firebase_app_check/lib/firebase_app_check.dart b/packages/firebase_app_check/firebase_app_check/lib/firebase_app_check.dart index cd569468c12c..7c6afa311651 100644 --- a/packages/firebase_app_check/firebase_app_check/lib/firebase_app_check.dart +++ b/packages/firebase_app_check/firebase_app_check/lib/firebase_app_check.dart @@ -13,6 +13,7 @@ export 'package:firebase_app_check_platform_interface/firebase_app_check_platfor AndroidAppCheckProvider, AndroidDebugProvider, AndroidPlayIntegrityProvider, + AndroidReCaptchaEnterpriseProvider, AppleProvider, AppleAppCheckProvider, AppleDebugProvider, diff --git a/packages/firebase_app_check/firebase_app_check/windows/messages.g.cpp b/packages/firebase_app_check/firebase_app_check/windows/messages.g.cpp index 0343b73ea815..d46886ee294e 100644 --- a/packages/firebase_app_check/firebase_app_check/windows/messages.g.cpp +++ b/packages/firebase_app_check/firebase_app_check/windows/messages.g.cpp @@ -1,7 +1,7 @@ // Copyright 2025, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #undef _HAS_EXCEPTIONS @@ -13,16 +13,18 @@ #include #include +#include +#include #include #include #include namespace firebase_app_check_windows { -using flutter::BasicMessageChannel; -using flutter::CustomEncodableValue; -using flutter::EncodableList; -using flutter::EncodableMap; -using flutter::EncodableValue; +using ::flutter::BasicMessageChannel; +using ::flutter::CustomEncodableValue; +using ::flutter::EncodableList; +using ::flutter::EncodableMap; +using ::flutter::EncodableValue; FlutterError CreateConnectionError(const std::string channel_name) { return FlutterError( @@ -31,277 +33,419 @@ FlutterError CreateConnectionError(const std::string channel_name) { EncodableValue("")); } +namespace { +template +bool PigeonInternalDeepEquals(const T& a, const T& b); + +bool PigeonInternalDeepEquals(const double& a, const double& b); + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b); + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b); + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b); + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b); + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b); + +template +bool PigeonInternalDeepEquals(const T& a, const T& b) { + return a == b; +} + +template +bool PigeonInternalDeepEquals(const std::vector& a, const std::vector& b) { + if (a.size() != b.size()) { + return false; + } + for (size_t i = 0; i < a.size(); ++i) { + if (!PigeonInternalDeepEquals(a[i], b[i])) { + return false; + } + } + return true; +} + +template +bool PigeonInternalDeepEquals(const std::map& a, const std::map& b) { + if (a.size() != b.size()) { + return false; + } + for (const auto& kv : a) { + bool found = false; + for (const auto& b_kv : b) { + if (PigeonInternalDeepEquals(kv.first, b_kv.first)) { + if (PigeonInternalDeepEquals(kv.second, b_kv.second)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; +} + +bool PigeonInternalDeepEquals(const double& a, const double& b) { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (a == b) || (std::isnan(a) && std::isnan(b)); +} + +template +bool PigeonInternalDeepEquals(const std::optional& a, const std::optional& b) { + if (!a && !b) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +template +bool PigeonInternalDeepEquals(const std::unique_ptr& a, const std::unique_ptr& b) { + if (a.get() == b.get()) { + return true; + } + if (!a || !b) { + return false; + } + return PigeonInternalDeepEquals(*a, *b); +} + +bool PigeonInternalDeepEquals(const ::flutter::EncodableValue& a, const ::flutter::EncodableValue& b) { + if (a.index() != b.index()) { + return false; + } + if (const double* da = std::get_if(&a)) { + return PigeonInternalDeepEquals(*da, std::get(b)); + } else if (const ::flutter::EncodableList* la = std::get_if<::flutter::EncodableList>(&a)) { + return PigeonInternalDeepEquals(*la, std::get<::flutter::EncodableList>(b)); + } else if (const ::flutter::EncodableMap* ma = std::get_if<::flutter::EncodableMap>(&a)) { + return PigeonInternalDeepEquals(*ma, std::get<::flutter::EncodableMap>(b)); + } + return a == b; +} + +template +size_t PigeonInternalDeepHash(const T& v); + +size_t PigeonInternalDeepHash(const double& v); + +template +size_t PigeonInternalDeepHash(const std::vector& v); + +template +size_t PigeonInternalDeepHash(const std::map& v); + +template +size_t PigeonInternalDeepHash(const std::optional& v); + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v); + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v); + +template +size_t PigeonInternalDeepHash(const T& v) { + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::vector& v) { + size_t result = 1; + for (const auto& item : v) { + result = result * 31 + PigeonInternalDeepHash(item); + } + return result; +} + +template +size_t PigeonInternalDeepHash(const std::map& v) { + size_t result = 0; + for (const auto& kv : v) { + result += ((PigeonInternalDeepHash(kv.first) * 31) ^ PigeonInternalDeepHash(kv.second)); + } + return result; +} + +size_t PigeonInternalDeepHash(const double& v) { + if (std::isnan(v)) { + // Normalize NaN to a consistent hash. + return std::hash()(std::numeric_limits::quiet_NaN()); + } + if (v == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return std::hash()(0.0); + } + return std::hash()(v); +} + +template +size_t PigeonInternalDeepHash(const std::optional& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +template +size_t PigeonInternalDeepHash(const std::unique_ptr& v) { + return v ? PigeonInternalDeepHash(*v) : 0; +} + +size_t PigeonInternalDeepHash(const ::flutter::EncodableValue& v) { + size_t result = v.index(); + if (const double* dv = std::get_if(&v)) { + result = result * 31 + PigeonInternalDeepHash(*dv); + } else if (const ::flutter::EncodableList* lv = + std::get_if<::flutter::EncodableList>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*lv); + } else if (const ::flutter::EncodableMap* mv = + std::get_if<::flutter::EncodableMap>(&v)) { + result = result * 31 + PigeonInternalDeepHash(*mv); + } else { + std::visit( + [&result](const auto& val) { + using T = std::decay_t; + if constexpr (!std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v && + !std::is_same_v) { + result = result * 31 + PigeonInternalDeepHash(val); + } + }, + v); + } + return result; +} + +} // namespace + PigeonInternalCodecSerializer::PigeonInternalCodecSerializer() {} EncodableValue PigeonInternalCodecSerializer::ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const { - return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + uint8_t type, + ::flutter::ByteStreamReader* stream) const { + return ::flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } void PigeonInternalCodecSerializer::WriteValue( - const EncodableValue& value, flutter::ByteStreamWriter* stream) const { - flutter::StandardCodecSerializer::WriteValue(value, stream); + const EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const { + ::flutter::StandardCodecSerializer::WriteValue(value, stream); } /// The codec used by FirebaseAppCheckHostApi. -const flutter::StandardMessageCodec& FirebaseAppCheckHostApi::GetCodec() { - return flutter::StandardMessageCodec::GetInstance( - &PigeonInternalCodecSerializer::GetInstance()); +const ::flutter::StandardMessageCodec& FirebaseAppCheckHostApi::GetCodec() { + return ::flutter::StandardMessageCodec::GetInstance(&PigeonInternalCodecSerializer::GetInstance()); } -// Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through -// the `binary_messenger`. -void FirebaseAppCheckHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, - FirebaseAppCheckHostApi* api) { +// Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through the `binary_messenger`. +void FirebaseAppCheckHostApi::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + FirebaseAppCheckHostApi* api) { FirebaseAppCheckHostApi::SetUp(binary_messenger, api, ""); } -void FirebaseAppCheckHostApi::SetUp(flutter::BinaryMessenger* binary_messenger, - FirebaseAppCheckHostApi* api, - const std::string& message_channel_suffix) { - const std::string prepended_suffix = - message_channel_suffix.length() > 0 - ? std::string(".") + message_channel_suffix - : ""; +void FirebaseAppCheckHostApi::SetUp( + ::flutter::BinaryMessenger* binary_messenger, + FirebaseAppCheckHostApi* api, + const std::string& message_channel_suffix) { + const std::string prepended_suffix = message_channel_suffix.length() > 0 ? std::string(".") + message_channel_suffix : ""; { - BasicMessageChannel<> channel( - binary_messenger, - "dev.flutter.pigeon.firebase_app_check_platform_interface." - "FirebaseAppCheckHostApi.activate" + - prepended_suffix, - &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler( - [api](const EncodableValue& message, - const flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_app_name_arg = args.at(0); - if (encodable_app_name_arg.IsNull()) { - reply(WrapError("app_name_arg unexpectedly null.")); - return; - } - const auto& app_name_arg = - std::get(encodable_app_name_arg); - const auto& encodable_android_provider_arg = args.at(1); - const auto* android_provider_arg = - std::get_if(&encodable_android_provider_arg); - const auto& encodable_apple_provider_arg = args.at(2); - const auto* apple_provider_arg = - std::get_if(&encodable_apple_provider_arg); - const auto& encodable_debug_token_arg = args.at(3); - const auto* debug_token_arg = - std::get_if(&encodable_debug_token_arg); - api->Activate(app_name_arg, android_provider_arg, - apple_provider_arg, debug_token_arg, - [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - }); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_name_arg = args.at(0); + if (encodable_app_name_arg.IsNull()) { + reply(WrapError("app_name_arg unexpectedly null.")); + return; + } + const auto& app_name_arg = std::get(encodable_app_name_arg); + const auto& encodable_android_provider_arg = args.at(1); + const auto* android_provider_arg = std::get_if(&encodable_android_provider_arg); + const auto& encodable_apple_provider_arg = args.at(2); + const auto* apple_provider_arg = std::get_if(&encodable_apple_provider_arg); + const auto& encodable_debug_token_arg = args.at(3); + const auto* debug_token_arg = std::get_if(&encodable_debug_token_arg); + const auto& encodable_recaptcha_enterprise_site_key_arg = args.at(4); + const auto* recaptcha_enterprise_site_key_arg = std::get_if(&encodable_recaptcha_enterprise_site_key_arg); + api->Activate(app_name_arg, android_provider_arg, apple_provider_arg, debug_token_arg, recaptcha_enterprise_site_key_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); } else { channel.SetMessageHandler(nullptr); } } { - BasicMessageChannel<> channel( - binary_messenger, - "dev.flutter.pigeon.firebase_app_check_platform_interface." - "FirebaseAppCheckHostApi.getToken" + - prepended_suffix, - &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getToken" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler( - [api](const EncodableValue& message, - const flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_app_name_arg = args.at(0); - if (encodable_app_name_arg.IsNull()) { - reply(WrapError("app_name_arg unexpectedly null.")); - return; - } - const auto& app_name_arg = - std::get(encodable_app_name_arg); - const auto& encodable_force_refresh_arg = args.at(1); - if (encodable_force_refresh_arg.IsNull()) { - reply(WrapError("force_refresh_arg unexpectedly null.")); - return; - } - const auto& force_refresh_arg = - std::get(encodable_force_refresh_arg); - api->GetToken( - app_name_arg, force_refresh_arg, - [reply](ErrorOr>&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - auto output_optional = std::move(output).TakeValue(); - if (output_optional) { - wrapped.push_back( - EncodableValue(std::move(output_optional).value())); - } else { - wrapped.push_back(EncodableValue()); - } - reply(EncodableValue(std::move(wrapped))); - }); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_name_arg = args.at(0); + if (encodable_app_name_arg.IsNull()) { + reply(WrapError("app_name_arg unexpectedly null.")); + return; + } + const auto& app_name_arg = std::get(encodable_app_name_arg); + const auto& encodable_force_refresh_arg = args.at(1); + if (encodable_force_refresh_arg.IsNull()) { + reply(WrapError("force_refresh_arg unexpectedly null.")); + return; + } + const auto& force_refresh_arg = std::get(encodable_force_refresh_arg); + api->GetToken(app_name_arg, force_refresh_arg, [reply](ErrorOr>&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + auto output_optional = std::move(output).TakeValue(); + if (output_optional) { + wrapped.push_back(EncodableValue(std::move(output_optional).value())); + } else { + wrapped.push_back(EncodableValue()); } + reply(EncodableValue(std::move(wrapped))); }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); } else { channel.SetMessageHandler(nullptr); } } { - BasicMessageChannel<> channel( - binary_messenger, - "dev.flutter.pigeon.firebase_app_check_platform_interface." - "FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled" + - prepended_suffix, - &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler( - [api](const EncodableValue& message, - const flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_app_name_arg = args.at(0); - if (encodable_app_name_arg.IsNull()) { - reply(WrapError("app_name_arg unexpectedly null.")); - return; - } - const auto& app_name_arg = - std::get(encodable_app_name_arg); - const auto& encodable_is_token_auto_refresh_enabled_arg = - args.at(1); - if (encodable_is_token_auto_refresh_enabled_arg.IsNull()) { - reply(WrapError( - "is_token_auto_refresh_enabled_arg unexpectedly null.")); - return; - } - const auto& is_token_auto_refresh_enabled_arg = - std::get(encodable_is_token_auto_refresh_enabled_arg); - api->SetTokenAutoRefreshEnabled( - app_name_arg, is_token_auto_refresh_enabled_arg, - [reply](std::optional&& output) { - if (output.has_value()) { - reply(WrapError(output.value())); - return; - } - EncodableList wrapped; - wrapped.push_back(EncodableValue()); - reply(EncodableValue(std::move(wrapped))); - }); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_name_arg = args.at(0); + if (encodable_app_name_arg.IsNull()) { + reply(WrapError("app_name_arg unexpectedly null.")); + return; + } + const auto& app_name_arg = std::get(encodable_app_name_arg); + const auto& encodable_is_token_auto_refresh_enabled_arg = args.at(1); + if (encodable_is_token_auto_refresh_enabled_arg.IsNull()) { + reply(WrapError("is_token_auto_refresh_enabled_arg unexpectedly null.")); + return; + } + const auto& is_token_auto_refresh_enabled_arg = std::get(encodable_is_token_auto_refresh_enabled_arg); + api->SetTokenAutoRefreshEnabled(app_name_arg, is_token_auto_refresh_enabled_arg, [reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); } else { channel.SetMessageHandler(nullptr); } } { - BasicMessageChannel<> channel( - binary_messenger, - "dev.flutter.pigeon.firebase_app_check_platform_interface." - "FirebaseAppCheckHostApi.registerTokenListener" + - prepended_suffix, - &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.registerTokenListener" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler( - [api](const EncodableValue& message, - const flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_app_name_arg = args.at(0); - if (encodable_app_name_arg.IsNull()) { - reply(WrapError("app_name_arg unexpectedly null.")); - return; - } - const auto& app_name_arg = - std::get(encodable_app_name_arg); - api->RegisterTokenListener( - app_name_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back( - EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_name_arg = args.at(0); + if (encodable_app_name_arg.IsNull()) { + reply(WrapError("app_name_arg unexpectedly null.")); + return; + } + const auto& app_name_arg = std::get(encodable_app_name_arg); + api->RegisterTokenListener(app_name_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); } else { channel.SetMessageHandler(nullptr); } } { - BasicMessageChannel<> channel( - binary_messenger, - "dev.flutter.pigeon.firebase_app_check_platform_interface." - "FirebaseAppCheckHostApi.getLimitedUseAppCheckToken" + - prepended_suffix, - &GetCodec()); + BasicMessageChannel<> channel(binary_messenger, "dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getLimitedUseAppCheckToken" + prepended_suffix, &GetCodec()); if (api != nullptr) { - channel.SetMessageHandler( - [api](const EncodableValue& message, - const flutter::MessageReply& reply) { - try { - const auto& args = std::get(message); - const auto& encodable_app_name_arg = args.at(0); - if (encodable_app_name_arg.IsNull()) { - reply(WrapError("app_name_arg unexpectedly null.")); - return; - } - const auto& app_name_arg = - std::get(encodable_app_name_arg); - api->GetLimitedUseAppCheckToken( - app_name_arg, [reply](ErrorOr&& output) { - if (output.has_error()) { - reply(WrapError(output.error())); - return; - } - EncodableList wrapped; - wrapped.push_back( - EncodableValue(std::move(output).TakeValue())); - reply(EncodableValue(std::move(wrapped))); - }); - } catch (const std::exception& exception) { - reply(WrapError(exception.what())); + channel.SetMessageHandler([api](const EncodableValue& message, const ::flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_app_name_arg = args.at(0); + if (encodable_app_name_arg.IsNull()) { + reply(WrapError("app_name_arg unexpectedly null.")); + return; + } + const auto& app_name_arg = std::get(encodable_app_name_arg); + api->GetLimitedUseAppCheckToken(app_name_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; } + EncodableList wrapped; + wrapped.push_back(EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); } else { channel.SetMessageHandler(nullptr); } } } -EncodableValue FirebaseAppCheckHostApi::WrapError( - std::string_view error_message) { - return EncodableValue( - EncodableList{EncodableValue(std::string(error_message)), - EncodableValue("Error"), EncodableValue()}); +EncodableValue FirebaseAppCheckHostApi::WrapError(std::string_view error_message) { + return EncodableValue(EncodableList{ + EncodableValue(std::string(error_message)), + EncodableValue("Error"), + EncodableValue() + }); } EncodableValue FirebaseAppCheckHostApi::WrapError(const FlutterError& error) { - return EncodableValue(EncodableList{EncodableValue(error.code()), - EncodableValue(error.message()), - error.details()}); + return EncodableValue(EncodableList{ + EncodableValue(error.code()), + EncodableValue(error.message()), + error.details() + }); } } // namespace firebase_app_check_windows diff --git a/packages/firebase_app_check/firebase_app_check/windows/messages.g.h b/packages/firebase_app_check/firebase_app_check/windows/messages.g.h index c56d71862604..4d13d5ff3fe4 100644 --- a/packages/firebase_app_check/firebase_app_check/windows/messages.g.h +++ b/packages/firebase_app_check/firebase_app_check/windows/messages.g.h @@ -1,7 +1,7 @@ // Copyright 2025, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #ifndef PIGEON_MESSAGES_G_H_ @@ -17,29 +17,29 @@ namespace firebase_app_check_windows { + // Generated class from Pigeon. class FlutterError { public: - explicit FlutterError(const std::string& code) : code_(code) {} + explicit FlutterError(const std::string& code) + : code_(code) {} explicit FlutterError(const std::string& code, const std::string& message) - : code_(code), message_(message) {} - explicit FlutterError(const std::string& code, const std::string& message, - const flutter::EncodableValue& details) - : code_(code), message_(message), details_(details) {} + : code_(code), message_(message) {} + explicit FlutterError(const std::string& code, const std::string& message, const ::flutter::EncodableValue& details) + : code_(code), message_(message), details_(details) {} const std::string& code() const { return code_; } const std::string& message() const { return message_; } - const flutter::EncodableValue& details() const { return details_; } + const ::flutter::EncodableValue& details() const { return details_; } private: std::string code_; std::string message_; - flutter::EncodableValue details_; + ::flutter::EncodableValue details_; }; -template -class ErrorOr { +template class ErrorOr { public: ErrorOr(const T& rhs) : v_(rhs) {} ErrorOr(const T&& rhs) : v_(std::move(rhs)) {} @@ -58,7 +58,9 @@ class ErrorOr { std::variant v_; }; -class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { + + +class PigeonInternalCodecSerializer : public ::flutter::StandardCodecSerializer { public: PigeonInternalCodecSerializer(); inline static PigeonInternalCodecSerializer& GetInstance() { @@ -66,51 +68,55 @@ class PigeonInternalCodecSerializer : public flutter::StandardCodecSerializer { return sInstance; } - void WriteValue(const flutter::EncodableValue& value, - flutter::ByteStreamWriter* stream) const override; - + void WriteValue( + const ::flutter::EncodableValue& value, + ::flutter::ByteStreamWriter* stream) const override; protected: - flutter::EncodableValue ReadValueOfType( - uint8_t type, flutter::ByteStreamReader* stream) const override; + ::flutter::EncodableValue ReadValueOfType( + uint8_t type, + ::flutter::ByteStreamReader* stream) const override; }; -// Generated interface from Pigeon that represents a handler of messages from -// Flutter. +// Generated interface from Pigeon that represents a handler of messages from Flutter. class FirebaseAppCheckHostApi { public: FirebaseAppCheckHostApi(const FirebaseAppCheckHostApi&) = delete; FirebaseAppCheckHostApi& operator=(const FirebaseAppCheckHostApi&) = delete; virtual ~FirebaseAppCheckHostApi() {} virtual void Activate( - const std::string& app_name, const std::string* android_provider, - const std::string* apple_provider, const std::string* debug_token, - std::function reply)> result) = 0; + const std::string& app_name, + const std::string* android_provider, + const std::string* apple_provider, + const std::string* debug_token, + const std::string* recaptcha_enterprise_site_key, + std::function reply)> result) = 0; virtual void GetToken( - const std::string& app_name, bool force_refresh, - std::function> reply)> - result) = 0; + const std::string& app_name, + bool force_refresh, + std::function> reply)> result) = 0; virtual void SetTokenAutoRefreshEnabled( - const std::string& app_name, bool is_token_auto_refresh_enabled, - std::function reply)> result) = 0; + const std::string& app_name, + bool is_token_auto_refresh_enabled, + std::function reply)> result) = 0; virtual void RegisterTokenListener( - const std::string& app_name, - std::function reply)> result) = 0; + const std::string& app_name, + std::function reply)> result) = 0; virtual void GetLimitedUseAppCheckToken( - const std::string& app_name, - std::function reply)> result) = 0; + const std::string& app_name, + std::function reply)> result) = 0; // The codec used by FirebaseAppCheckHostApi. - static const flutter::StandardMessageCodec& GetCodec(); - // Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through - // the `binary_messenger`. - static void SetUp(flutter::BinaryMessenger* binary_messenger, - FirebaseAppCheckHostApi* api); - static void SetUp(flutter::BinaryMessenger* binary_messenger, - FirebaseAppCheckHostApi* api, - const std::string& message_channel_suffix); - static flutter::EncodableValue WrapError(std::string_view error_message); - static flutter::EncodableValue WrapError(const FlutterError& error); - + static const ::flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `FirebaseAppCheckHostApi` to handle messages through the `binary_messenger`. + static void SetUp( + ::flutter::BinaryMessenger* binary_messenger, + FirebaseAppCheckHostApi* api); + static void SetUp( + ::flutter::BinaryMessenger* binary_messenger, + FirebaseAppCheckHostApi* api, + const std::string& message_channel_suffix); + static ::flutter::EncodableValue WrapError(std::string_view error_message); + static ::flutter::EncodableValue WrapError(const FlutterError& error); protected: FirebaseAppCheckHostApi() = default; }; diff --git a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/android_providers.dart b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/android_providers.dart index c827b3184022..76ce5b389981 100644 --- a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/android_providers.dart +++ b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/android_providers.dart @@ -32,3 +32,15 @@ class AndroidDebugProvider extends AndroidAppCheckProvider { class AndroidPlayIntegrityProvider extends AndroidAppCheckProvider { const AndroidPlayIntegrityProvider() : super('playIntegrity'); } + +/// reCAPTCHA Enterprise provider for Android. +/// +/// See documentation: https://firebase.google.com/docs/app-check/android/recaptcha-enterprise-provider +class AndroidReCaptchaEnterpriseProvider extends AndroidAppCheckProvider { + /// Creates an Android reCAPTCHA Enterprise provider with a site key. + const AndroidReCaptchaEnterpriseProvider({required this.siteKey}) : super('recaptchaEnterprise'); + + /// The reCAPTCHA Enterprise site key. + final String siteKey; +} + diff --git a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/method_channel/method_channel_firebase_app_check.dart b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/method_channel/method_channel_firebase_app_check.dart index 96afb6f2c999..062bae9a10ac 100644 --- a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/method_channel/method_channel_firebase_app_check.dart +++ b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/method_channel/method_channel_firebase_app_check.dart @@ -104,6 +104,11 @@ class MethodChannelFirebaseAppCheck extends FirebaseAppCheckPlatform { debugToken = providerWindows.debugToken; } + String? recaptchaEnterpriseSiteKey; + if (providerAndroid is AndroidReCaptchaEnterpriseProvider) { + recaptchaEnterpriseSiteKey = providerAndroid.siteKey; + } + await _pigeonApi.activate( app.name, defaultTargetPlatform == TargetPlatform.android || kDebugMode @@ -121,6 +126,7 @@ class MethodChannelFirebaseAppCheck extends FirebaseAppCheckPlatform { ) : null, debugToken, + recaptchaEnterpriseSiteKey, ); } on PlatformException catch (e, s) { convertPlatformException(e, s); diff --git a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/pigeon/messages.pigeon.dart b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/pigeon/messages.pigeon.dart index 8916928599ce..8fb14b67fa11 100644 --- a/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/pigeon/messages.pigeon.dart +++ b/packages/firebase_app_check/firebase_app_check_platform_interface/lib/src/pigeon/messages.pigeon.dart @@ -1,23 +1,44 @@ // Copyright 2025, the Chromium project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.2), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon -// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers +// ignore_for_file: unused_import, unused_shown_name +// ignore_for_file: type=lint import 'dart:async'; -import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; +import 'dart:typed_data' show Float64List, Int32List, Int64List; -import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; +import 'package:meta/meta.dart' show immutable, protected, visibleForTesting; -PlatformException _createConnectionError(String channelName) { - return PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel: "$channelName".', - ); +Object? _extractReplyValueOrThrow( + List? replyList, + String channelName, { + required bool isNullValid, +}) { + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel: "$channelName".', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (!isNullValid && (replyList.isNotEmpty && replyList[0] == null)) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } + return replyList.firstOrNull; } + + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override @@ -43,156 +64,105 @@ class FirebaseAppCheckHostApi { /// Constructor for [FirebaseAppCheckHostApi]. The [binaryMessenger] named argument is /// available for dependency injection. If it is left null, the default /// BinaryMessenger will be used which routes to the host platform. - FirebaseAppCheckHostApi( - {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + FirebaseAppCheckHostApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) : pigeonVar_binaryMessenger = binaryMessenger, - pigeonVar_messageChannelSuffix = - messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; final BinaryMessenger? pigeonVar_binaryMessenger; static const MessageCodec pigeonChannelCodec = _PigeonCodec(); final String pigeonVar_messageChannelSuffix; - Future activate(String appName, String? androidProvider, - String? appleProvider, String? debugToken) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future activate(String appName, String? androidProvider, String? appleProvider, String? debugToken, String? recaptchaEnterpriseSiteKey) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = pigeonVar_channel - .send([appName, androidProvider, appleProvider, debugToken]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final Future pigeonVar_sendFuture = pigeonVar_channel.send([appName, androidProvider, appleProvider, debugToken, recaptchaEnterpriseSiteKey]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future getToken(String appName, bool forceRefresh) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getToken$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getToken$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([appName, forceRefresh]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return (pigeonVar_replyList[0] as String?); - } + final Future pigeonVar_sendFuture = pigeonVar_channel.send([appName, forceRefresh]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; + return pigeonVar_replyValue as String?; } - Future setTokenAutoRefreshEnabled( - String appName, bool isTokenAutoRefreshEnabled) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + Future setTokenAutoRefreshEnabled(String appName, bool isTokenAutoRefreshEnabled) async { + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.setTokenAutoRefreshEnabled$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([appName, isTokenAutoRefreshEnabled]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else { - return; - } + final Future pigeonVar_sendFuture = pigeonVar_channel.send([appName, isTokenAutoRefreshEnabled]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: true, + ) + ; } Future registerTokenListener(String appName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.registerTokenListener$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.registerTokenListener$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([appName]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final Future pigeonVar_sendFuture = pigeonVar_channel.send([appName]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as String; } Future getLimitedUseAppCheckToken(String appName) async { - final String pigeonVar_channelName = - 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getLimitedUseAppCheckToken$pigeonVar_messageChannelSuffix'; - final BasicMessageChannel pigeonVar_channel = - BasicMessageChannel( + final pigeonVar_channelName = 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.getLimitedUseAppCheckToken$pigeonVar_messageChannelSuffix'; + final pigeonVar_channel = BasicMessageChannel( pigeonVar_channelName, pigeonChannelCodec, binaryMessenger: pigeonVar_binaryMessenger, ); - final Future pigeonVar_sendFuture = - pigeonVar_channel.send([appName]); - final List? pigeonVar_replyList = - await pigeonVar_sendFuture as List?; - if (pigeonVar_replyList == null) { - throw _createConnectionError(pigeonVar_channelName); - } else if (pigeonVar_replyList.length > 1) { - throw PlatformException( - code: pigeonVar_replyList[0]! as String, - message: pigeonVar_replyList[1] as String?, - details: pigeonVar_replyList[2], - ); - } else if (pigeonVar_replyList[0] == null) { - throw PlatformException( - code: 'null-error', - message: 'Host platform returned null value for non-null return value.', - ); - } else { - return (pigeonVar_replyList[0] as String?)!; - } + final Future pigeonVar_sendFuture = pigeonVar_channel.send([appName]); + final pigeonVar_replyList = await pigeonVar_sendFuture as List?; + + final Object? pigeonVar_replyValue = _extractReplyValueOrThrow( + pigeonVar_replyList, + pigeonVar_channelName, + isNullValid: false, + ) + ; + return pigeonVar_replyValue! as String; } } diff --git a/packages/firebase_app_check/firebase_app_check_platform_interface/pigeons/messages.dart b/packages/firebase_app_check/firebase_app_check_platform_interface/pigeons/messages.dart index e84ff78ab5f4..e20e1bdfba0e 100644 --- a/packages/firebase_app_check/firebase_app_check_platform_interface/pigeons/messages.dart +++ b/packages/firebase_app_check/firebase_app_check_platform_interface/pigeons/messages.dart @@ -29,8 +29,10 @@ abstract class FirebaseAppCheckHostApi { String? androidProvider, String? appleProvider, String? debugToken, + String? recaptchaEnterpriseSiteKey, ); + @async String? getToken(String appName, bool forceRefresh); diff --git a/packages/firebase_app_check/firebase_app_check_platform_interface/test/method_channel_tests/method_channel_firebase_app_check_test.dart b/packages/firebase_app_check/firebase_app_check_platform_interface/test/method_channel_tests/method_channel_firebase_app_check_test.dart index 5f215cec19fc..45cf6427c0d7 100644 --- a/packages/firebase_app_check/firebase_app_check_platform_interface/test/method_channel_tests/method_channel_firebase_app_check_test.dart +++ b/packages/firebase_app_check/firebase_app_check_platform_interface/test/method_channel_tests/method_channel_firebase_app_check_test.dart @@ -5,6 +5,7 @@ import 'package:firebase_app_check_platform_interface/firebase_app_check_platform_interface.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter/services.dart'; import '../mock.dart'; @@ -44,5 +45,32 @@ void main() { expect(appCheck.setInitialValues(), appCheck); }); }); + + group('activate()', () { + test('passes recaptchaEnterpriseSiteKey on Android', () async { + final appCheck = MethodChannelFirebaseAppCheck(app: Firebase.app()); + + final List log = []; + + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMessageHandler( + 'dev.flutter.pigeon.firebase_app_check_platform_interface.FirebaseAppCheckHostApi.activate', + (message) async { + final list = const StandardMessageCodec().decodeMessage(message) as List; + log.add(list); + return const StandardMessageCodec().encodeMessage([null]); // Return success + }, + ); + + await appCheck.activate( + providerAndroid: const AndroidReCaptchaEnterpriseProvider(siteKey: 'my-site-key'), + ); + + expect(log.length, 1); + expect(log[0][0], '[DEFAULT]'); // appName + expect(log[0][1], 'recaptchaEnterprise'); // androidProvider + expect(log[0][4], 'my-site-key'); // recaptchaEnterpriseSiteKey + }); + }); }); }