Skip to content

Commit ccd08e6

Browse files
committed
Port ObjC bridge to Swift
1 parent c36c220 commit ccd08e6

File tree

1 file changed

+74
-29
lines changed

1 file changed

+74
-29
lines changed

FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -125,38 +125,83 @@
125125
// No recaptcha on internal build system.
126126
return actionString
127127
#else
128-
return try await withCheckedThrowingContinuation { continuation in
129-
FIRRecaptchaGetToken(siteKey, actionString,
130-
"NO_RECAPTCHA") { (token: String, error: Error?,
131-
linked: Bool, actionCreated: Bool) in
132-
guard linked else {
133-
continuation.resume(throwing: AuthErrorUtils.recaptchaSDKNotLinkedError())
134-
return
135-
}
136-
guard actionCreated else {
137-
continuation.resume(throwing: AuthErrorUtils.recaptchaActionCreationFailed())
138-
return
139-
}
140-
if let error {
141-
continuation.resume(throwing: error)
142-
return
143-
} else {
144-
if token == "NO_RECAPTCHA" {
145-
AuthLog.logInfo(code: "I-AUT000031",
146-
message: "reCAPTCHA token retrieval failed. NO_RECAPTCHA sent as the fake code.")
147-
} else {
148-
AuthLog.logInfo(
149-
code: "I-AUT000030",
150-
message: "reCAPTCHA token retrieval succeeded."
151-
)
152-
}
153-
continuation.resume(returning: token)
154-
}
155-
}
156-
}
128+
129+
let (token, error, linked, actionCreated) = await recaptchaToken(siteKey: siteKey, actionString: actionString, fakeToken: "NO_RECAPTCHA")
130+
131+
guard linked else {
132+
throw AuthErrorUtils.recaptchaSDKNotLinkedError()
133+
}
134+
guard actionCreated else {
135+
throw AuthErrorUtils.recaptchaActionCreationFailed()
136+
}
137+
if let error {
138+
throw error
139+
}
140+
if token == "NO_RECAPTCHA" {
141+
AuthLog.logInfo(code: "I-AUT000031",
142+
message: "reCAPTCHA token retrieval failed. NO_RECAPTCHA sent as the fake code.")
143+
} else {
144+
AuthLog.logInfo(
145+
code: "I-AUT000030",
146+
message: "reCAPTCHA token retrieval succeeded."
147+
)
148+
}
149+
return token
157150
#endif // !(COCOAPODS || SWIFT_PACKAGE)
158151
}
159152

153+
private static var recaptchaClient: (any RCARecaptchaClientProtocol)?
154+
155+
private func recaptchaToken(
156+
siteKey: String,
157+
actionString: String,
158+
fakeToken: String
159+
) async -> (token: String, error: Error?, linked: Bool, actionCreated: Bool) {
160+
if recaptchaClient != nil {
161+
return await retrieveToken(actionString: actionString, fakeToken: fakeToken)
162+
}
163+
164+
if let recaptcha = NSClassFromString("RecaptchaEnterprise.RCARecaptcha") as? RCARecaptchaProtocol.Type {
165+
do {
166+
// TODO(ncooke3): This should be `fetchClient(withSiteKey:)`.
167+
let client = try await recaptcha.getClient(withSiteKey: siteKey)
168+
recaptchaClient = client
169+
return await retrieveToken(actionString: actionString, fakeToken: fakeToken)
170+
} catch {
171+
return ("", error, true, true);
172+
}
173+
} else if let recaptcha = NSClassFromString("Recaptcha") {
174+
// Fall back to attempting to connect with pre-18.7.0 RecaptchaEnterprise.
175+
let client = try await recaptcha.getClient(withSiteKey: siteKey)
176+
recaptchaClient = client
177+
return await retrieveToken(actionString: actionString, fakeToken: fakeToken)
178+
} catch {
179+
return ("", error, true, true);
180+
}
181+
} else {
182+
// RecaptchaEnterprise not linked.
183+
return ("", nil, false, false)
184+
}
185+
}
186+
187+
private func retrieveToken(
188+
actionString: String,
189+
fakeToken: String
190+
) async -> (token: String, error: Error?, linked: Bool, actionCreated: Bool) {
191+
let recaptchaAction = (
192+
NSClassFromString("RecaptchaEnterprise.RCAAction") ?? NSClassFromString("RecaptchaAction")
193+
) as? RCAActionProtocol.Type
194+
195+
guard let recaptchaAction else {
196+
// RecaptchaEnterprise not linked.
197+
return ("", nil, false, false)
198+
}
199+
200+
let action = recaptchaAction.init(customAction: actionString)
201+
let token = try? await recaptchaClient!.execute(withAction: action)
202+
return (token ?? "NO_RECAPTCHA", nil, true, true)
203+
}
204+
160205
func retrieveRecaptchaConfig(forceRefresh: Bool) async throws {
161206
if !forceRefresh {
162207
if let tenantID = auth?.tenantID {

0 commit comments

Comments
 (0)