Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Auth] Add support for upcoming Recaptcha changes #14201

Merged
merged 14 commits into from
Feb 3, 2025
2 changes: 1 addition & 1 deletion FirebaseAuth.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ supports email and password accounts, as well as several 3rd party authenticatio
s.dependency 'GoogleUtilities/AppDelegateSwizzler', '~> 8.0'
s.dependency 'GoogleUtilities/Environment', '~> 8.0'
s.dependency 'GTMSessionFetcher/Core', '>= 3.4', '< 5.0'
s.ios.dependency 'RecaptchaInterop', '~> 100.0'
s.ios.dependency 'RecaptchaInterop', '~> 101.0'
s.test_spec 'unit' do |unit_tests|
unit_tests.scheme = { :code_coverage => true }
# Unit tests can't run on watchOS.
Expand Down
4 changes: 4 additions & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Unreleased
- [changed] Using reCAPTCHA Enterprise and Firebase Auth requires reCAPTCHA
Enterprise X.Y.Z or later.

# 11.6.0
- [added] Added reCAPTCHA Enterprise support for app verification during phone
authentication for Firebase Authentication (#14114)
Expand Down
88 changes: 0 additions & 88 deletions FirebaseAuth/Sources/ObjC/FIRRecaptchaBridge.m

This file was deleted.

33 changes: 0 additions & 33 deletions FirebaseAuth/Sources/Public/FirebaseAuth/FIRRecaptchaBridge.h

This file was deleted.

1 change: 0 additions & 1 deletion FirebaseAuth/Sources/Public/FirebaseAuth/FirebaseAuth.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@
#import "FIRGoogleAuthProvider.h"
#import "FIRMultiFactor.h"
#import "FIRPhoneAuthProvider.h"
#import "FIRRecaptchaBridge.h"
#import "FIRTwitterAuthProvider.h"
93 changes: 65 additions & 28 deletions FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,38 +125,75 @@
// No recaptcha on internal build system.
return actionString
#else
return try await withCheckedThrowingContinuation { continuation in
FIRRecaptchaGetToken(siteKey, actionString,
"NO_RECAPTCHA") { (token: String, error: Error?,
linked: Bool, actionCreated: Bool) in
guard linked else {
continuation.resume(throwing: AuthErrorUtils.recaptchaSDKNotLinkedError())
return
}
guard actionCreated else {
continuation.resume(throwing: AuthErrorUtils.recaptchaActionCreationFailed())
return
}
if let error {
continuation.resume(throwing: error)
return
} else {
if token == "NO_RECAPTCHA" {
AuthLog.logInfo(code: "I-AUT000031",
message: "reCAPTCHA token retrieval failed. NO_RECAPTCHA sent as the fake code.")
} else {
AuthLog.logInfo(
code: "I-AUT000030",
message: "reCAPTCHA token retrieval succeeded."
)
}
continuation.resume(returning: token)
}
}

let (token, error, linked, actionCreated) = await recaptchaToken(
siteKey: siteKey,
actionString: actionString,
fakeToken: "NO_RECAPTCHA"
)

guard linked else {
throw AuthErrorUtils.recaptchaSDKNotLinkedError()
}
guard actionCreated else {
throw AuthErrorUtils.recaptchaActionCreationFailed()
}
if let error {
throw error
}
if token == "NO_RECAPTCHA" {
AuthLog.logInfo(code: "I-AUT000031",
message: "reCAPTCHA token retrieval failed. NO_RECAPTCHA sent as the fake code.")
} else {
AuthLog.logInfo(
code: "I-AUT000030",
message: "reCAPTCHA token retrieval succeeded."
)
}
return token
#endif // !(COCOAPODS || SWIFT_PACKAGE)
}

private static var recaptchaClient: (any RCARecaptchaClientProtocol)?

private func recaptchaToken(siteKey: String,
actionString: String,
fakeToken: String) async -> (token: String, error: Error?,
linked: Bool, actionCreated: Bool) {
if recaptchaClient != nil {
return await retrieveToken(actionString: actionString, fakeToken: fakeToken)
}

if let recaptcha =
NSClassFromString("RecaptchaEnterprise.RCARecaptcha") as? RCARecaptchaProtocol.Type {
do {
// TODO(ncooke3): This should be `fetchClient(withSiteKey:)`.
let client = try await recaptcha.getClient(withSiteKey: siteKey)
recaptchaClient = client
return await retrieveToken(actionString: actionString, fakeToken: fakeToken)
} catch {
return ("", error, true, true)
}
} else {
// RecaptchaEnterprise not linked.
return ("", nil, false, false)
}
}

private func retrieveToken(actionString: String,
fakeToken: String) async -> (token: String, error: Error?,
linked: Bool, actionCreated: Bool) {
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 {
// RecaptchaEnterprise not linked.
return ("", nil, false, false)
}
}

func retrieveRecaptchaConfig(forceRefresh: Bool) async throws {
if !forceRefresh {
if let tenantID = auth?.tenantID {
Expand Down
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ let package = Package(
.package(
url: "https://github.com/google/interop-ios-for-google-sdks.git",
"100.0.0" ..< "101.0.0"
// "101.0.0" ..< "102.0.0"
),
.package(url: "https://github.com/google/app-check.git",
"11.0.1" ..< "12.0.0"),
Expand Down
Loading