diff --git a/FirebaseAuth/Sources/ObjC/FIRRecaptchaBridge.m b/FirebaseAuth/Sources/ObjC/FIRRecaptchaBridge.m index c35397426c2..6ed445cf54e 100644 --- a/FirebaseAuth/Sources/ObjC/FIRRecaptchaBridge.m +++ b/FirebaseAuth/Sources/ObjC/FIRRecaptchaBridge.m @@ -18,83 +18,23 @@ #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h" #import "RecaptchaInterop/RecaptchaInterop.h" -// This is thread safe since it is only called by the AuthRecaptchaVerifier singleton. -static id recaptchaClient; - -static void retrieveToken(NSString *actionString, - NSString *fakeToken, - FIRAuthRecaptchaTokenCallback callback) { - Class RecaptchaActionClass = NSClassFromString(@"RecaptchaEnterprise.RCAAction"); - SEL customActionSelector = NSSelectorFromString(@"initWithCustomAction:"); - if (!RecaptchaActionClass) { - // Fall back to attempting to connect with pre-18.7.0 RecaptchaEnterprise. - RecaptchaActionClass = NSClassFromString(@"RecaptchaAction"); - } - - if (RecaptchaActionClass && - [RecaptchaActionClass instancesRespondToSelector:customActionSelector]) { - // Initialize with a custom action - id (*funcWithCustomAction)(id, SEL, NSString *) = (id(*)( - id, SEL, NSString *))[RecaptchaActionClass instanceMethodForSelector:customActionSelector]; - - id customAction = - funcWithCustomAction([RecaptchaActionClass alloc], customActionSelector, actionString); - if (customAction) { - [recaptchaClient execute:customAction - completion:^(NSString *_Nullable token, NSError *_Nullable error) { - if (!error) { - callback(token, nil, YES, YES); - return; - } else { - callback(fakeToken, nil, YES, YES); - } - }]; - } else { - // RecaptchaAction class creation failed. - callback(@"", nil, YES, NO); - } - +Class _Nonnull __fir_castToRecaptchaProtocolFromClass(Class _Nonnull klass) { + if ([klass conformsToProtocol:@protocol(RCARecaptchaProtocol)]) { + NSLog(@"RCARecaptchaProtocol - true"); } else { - // RecaptchaEnterprise not linked. - callback(@"", nil, NO, NO); + NSLog(@"RCARecaptchaProtocol - false"); } + return (Class)klass; } -void FIRRecaptchaGetToken(NSString *siteKey, - NSString *actionString, - NSString *fakeToken, - FIRAuthRecaptchaTokenCallback callback) { - if (recaptchaClient != nil) { - retrieveToken(actionString, fakeToken, callback); - return; - } - - // Why not use `conformsToProtocol`? - Class RecaptchaClass = NSClassFromString(@"RecaptchaEnterprise.RCARecaptcha"); - SEL selector = NSSelectorFromString(@"fetchClientWithSiteKey:completion:"); - if (!RecaptchaClass) { - // Fall back to attempting to connect with pre-18.7.0 RecaptchaEnterprise. - RecaptchaClass = NSClassFromString(@"Recaptcha"); - selector = NSSelectorFromString(@"getClientWithSiteKey:completion:"); - } - - if (RecaptchaClass && [RecaptchaClass respondsToSelector:selector]) { - void (*funcWithoutTimeout)(id, SEL, NSString *, - void (^)(id _Nullable recaptchaClient, - NSError *_Nullable error)) = - (void *)[RecaptchaClass methodForSelector:selector]; - funcWithoutTimeout(RecaptchaClass, selector, siteKey, - ^(id _Nonnull client, NSError *_Nullable error) { - if (error) { - callback(@"", error, YES, YES); - } else { - recaptchaClient = client; - retrieveToken(actionString, fakeToken, callback); - } - }); +Class _Nonnull __fir_castToRecaptchaActionProtocolFromClass( + Class _Nonnull klass) { + if ([klass conformsToProtocol:@protocol(RCAActionProtocol)]) { + NSLog(@"RCAActionProtocol - true"); } else { - // RecaptchaEnterprise not linked. - callback(@"", nil, NO, NO); + NSLog(@"RCAActionProtocol - false"); } + return (Class)klass; } + #endif diff --git a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h index fd255bf43d7..05de63862e0 100644 --- a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h +++ b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h @@ -17,17 +17,12 @@ #if TARGET_OS_IOS -typedef void (^FIRAuthRecaptchaTokenCallback)(NSString *_Nonnull token, - NSError *_Nullable error, - BOOL linked, - BOOL recaptchaActionCreated); +@protocol RCARecaptchaProtocol; +@protocol RCAActionProtocol; + +Class _Nonnull __fir_castToRecaptchaProtocolFromClass(Class _Nonnull klass); + +Class _Nonnull __fir_castToRecaptchaActionProtocolFromClass( + Class _Nonnull klass); -// Provide a bridge to the Objective-C protocol provided by the optional Recaptcha Enterprise -// dependency. Once the Recaptcha Enterprise provides a Swift interop protocol, this C and -// Objective-C code can be converted to Swift. Casting to a Objective-C protocol does not seem -// possible in Swift. The C API is a workaround for linkage problems with an Objective-C API. -void FIRRecaptchaGetToken(NSString *_Nonnull siteKey, - NSString *_Nonnull actionString, - NSString *_Nonnull fakeToken, - _Nonnull FIRAuthRecaptchaTokenCallback callback); #endif diff --git a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift index 09bf3b193d3..8fc78d8ea74 100644 --- a/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift +++ b/FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift @@ -177,6 +177,7 @@ } else if let recaptcha = NSClassFromString("Recaptcha") { // Fall back to attempting to connect with pre-18.7.0 RecaptchaEnterprise. do { + let recaptcha = __fir_castToRecaptchaProtocolFromClass(recaptcha) let client = try await recaptcha.getClient(withSiteKey: siteKey) recaptchaClient = client return await retrieveToken(actionString: actionString, fakeToken: fakeToken) @@ -192,18 +193,21 @@ private func retrieveToken(actionString: String, fakeToken: String) async -> (token: String, error: Error?, linked: Bool, actionCreated: Bool) { - let recaptchaAction = ( - NSClassFromString("RecaptchaEnterprise.RCAAction") ?? NSClassFromString("RecaptchaAction") - ) as? RCAActionProtocol.Type - - guard let recaptchaAction else { + if let recaptchaAction = + NSClassFromString("RecaptchaEnterprise.RCAAction") as? RCAActionProtocol.Type { + let action = recaptchaAction.init(customAction: actionString) + let token = try? await recaptchaClient!.execute(withAction: action) + return (token ?? "NO_RECAPTCHA", nil, true, true) + } else if let recaptchaAction = NSClassFromString("RecaptchaAction") { + // Fall back to attempting to connect with pre-18.7.0 RecaptchaEnterprise. + let recaptchaAction = __fir_castToRecaptchaActionProtocolFromClass(recaptchaAction) + let action = recaptchaAction.init(customAction: actionString) + let token = try? await recaptchaClient!.execute(withAction: action) + return (token ?? "NO_RECAPTCHA", nil, true, true) + } else { // RecaptchaEnterprise not linked. return ("", nil, false, false) } - - let action = recaptchaAction.init(customAction: actionString) - let token = try? await recaptchaClient!.execute(withAction: action) - return (token ?? "NO_RECAPTCHA", nil, true, true) } func retrieveRecaptchaConfig(forceRefresh: Bool) async throws {