Skip to content

Commit b70ebdb

Browse files
committed
Refactor for varied platform availability
1 parent d3795a4 commit b70ebdb

File tree

1 file changed

+129
-123
lines changed

1 file changed

+129
-123
lines changed

FirebaseAuth/Sources/Swift/Utilities/AuthRecaptchaVerifier.swift

Lines changed: 129 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -12,93 +12,157 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// RecaptchaInterop is only available on iOS.
16-
#if os(iOS)
17-
import Foundation
15+
import Foundation
1816

19-
#if SWIFT_PACKAGE
20-
import FirebaseAuthInternal
21-
#endif
17+
#if SWIFT_PACKAGE
18+
import FirebaseAuthInternal
19+
#endif
2220

21+
#if os(iOS)
2322
import RecaptchaInterop
23+
#endif
2424

25-
@available(iOS 13, *)
26-
class AuthRecaptchaConfig {
27-
var siteKey: String?
28-
let enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus]
25+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
26+
class AuthRecaptchaConfig {
27+
var siteKey: String?
28+
let enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus]
2929

30-
init(siteKey: String? = nil,
31-
enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus]) {
32-
self.siteKey = siteKey
33-
self.enablementStatus = enablementStatus
34-
}
30+
init(siteKey: String? = nil,
31+
enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus]) {
32+
self.siteKey = siteKey
33+
self.enablementStatus = enablementStatus
3534
}
35+
}
3636

37-
@available(iOS 13, *)
38-
enum AuthRecaptchaEnablementStatus: String, CaseIterable {
39-
case enforce = "ENFORCE"
40-
case audit = "AUDIT"
41-
case off = "OFF"
37+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
38+
enum AuthRecaptchaEnablementStatus: String, CaseIterable {
39+
case enforce = "ENFORCE"
40+
case audit = "AUDIT"
41+
case off = "OFF"
4242

43-
// Convenience property for mapping values
44-
var stringValue: String { rawValue }
45-
}
43+
// Convenience property for mapping values
44+
var stringValue: String { rawValue }
45+
}
4646

47-
@available(iOS 13, *)
48-
enum AuthRecaptchaProvider: String, CaseIterable {
49-
case password = "EMAIL_PASSWORD_PROVIDER"
50-
case phone = "PHONE_PROVIDER"
47+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
48+
enum AuthRecaptchaProvider: String, CaseIterable {
49+
case password = "EMAIL_PASSWORD_PROVIDER"
50+
case phone = "PHONE_PROVIDER"
5151

52-
// Convenience property for mapping values
53-
var stringValue: String { rawValue }
54-
}
52+
// Convenience property for mapping values
53+
var stringValue: String { rawValue }
54+
}
5555

56-
@available(iOS 13, *)
57-
enum AuthRecaptchaAction: String {
58-
case defaultAction
59-
case signInWithPassword
60-
case getOobCode
61-
case signUpPassword
62-
case sendVerificationCode
63-
case mfaSmsSignIn
64-
case mfaSmsEnrollment
56+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
57+
enum AuthRecaptchaAction: String {
58+
case defaultAction
59+
case signInWithPassword
60+
case getOobCode
61+
case signUpPassword
62+
case sendVerificationCode
63+
case mfaSmsSignIn
64+
case mfaSmsEnrollment
6565

66-
// Convenience property for mapping values
67-
var stringValue: String { rawValue }
68-
}
66+
// Convenience property for mapping values
67+
var stringValue: String { rawValue }
68+
}
6969

70-
@available(iOS 13, *)
71-
class AuthRecaptchaVerifier {
72-
weak var auth: Auth?
73-
private var agentConfig: AuthRecaptchaConfig?
74-
private var tenantConfigs: [String: AuthRecaptchaConfig] = [:]
70+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
71+
class AuthRecaptchaVerifier {
72+
weak var auth: Auth?
73+
private var agentConfig: AuthRecaptchaConfig?
74+
private var tenantConfigs: [String: AuthRecaptchaConfig] = [:]
75+
#if os(iOS)
7576
private var recaptchaClient: RCARecaptchaClientProtocol?
76-
private let recaptchaVersion = "RECAPTCHA_ENTERPRISE"
77+
#endif
78+
private let recaptchaVersion = "RECAPTCHA_ENTERPRISE"
79+
80+
private func siteKey() -> String? {
81+
if let tenantID = auth?.tenantID {
82+
if let config = tenantConfigs[tenantID] {
83+
return config.siteKey
84+
}
85+
return nil
86+
}
87+
return agentConfig?.siteKey
88+
}
7789

78-
private func siteKey() -> String? {
90+
func enablementStatus(forProvider provider: AuthRecaptchaProvider)
91+
-> AuthRecaptchaEnablementStatus {
92+
if let tenantID = auth?.tenantID,
93+
let tenantConfig = tenantConfigs[tenantID],
94+
let status = tenantConfig.enablementStatus[provider] {
95+
return status
96+
} else if let agentConfig = agentConfig,
97+
let status = agentConfig.enablementStatus[provider] {
98+
return status
99+
} else {
100+
return AuthRecaptchaEnablementStatus.off
101+
}
102+
}
103+
104+
func retrieveRecaptchaConfig(forceRefresh: Bool) async throws {
105+
if !forceRefresh {
79106
if let tenantID = auth?.tenantID {
80-
if let config = tenantConfigs[tenantID] {
81-
return config.siteKey
107+
if tenantConfigs[tenantID] != nil {
108+
return
82109
}
83-
return nil
110+
} else if agentConfig != nil {
111+
return
84112
}
85-
return agentConfig?.siteKey
86113
}
87114

88-
func enablementStatus(forProvider provider: AuthRecaptchaProvider)
89-
-> AuthRecaptchaEnablementStatus {
90-
if let tenantID = auth?.tenantID,
91-
let tenantConfig = tenantConfigs[tenantID],
92-
let status = tenantConfig.enablementStatus[provider] {
93-
return status
94-
} else if let agentConfig = agentConfig,
95-
let status = agentConfig.enablementStatus[provider] {
96-
return status
97-
} else {
98-
return AuthRecaptchaEnablementStatus.off
115+
guard let auth = auth else {
116+
throw AuthErrorUtils.error(code: .recaptchaNotEnabled,
117+
message: "No requestConfiguration for Auth instance")
118+
}
119+
let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration)
120+
let response = try await auth.backend.call(with: request)
121+
AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.")
122+
try await parseRecaptchaConfigFromResponse(response: response)
123+
}
124+
125+
private func parseRecaptchaConfigFromResponse(response: GetRecaptchaConfigResponse) async throws {
126+
var enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus] = [:]
127+
var isRecaptchaEnabled = false
128+
if let enforcementState = response.enforcementState {
129+
for state in enforcementState {
130+
guard let providerString = state["provider"],
131+
let enforcementString = state["enforcementState"],
132+
let provider = AuthRecaptchaProvider(rawValue: providerString),
133+
let enforcement = AuthRecaptchaEnablementStatus(rawValue: enforcementString) else {
134+
continue // Skip to the next state in the loop
135+
}
136+
enablementStatus[provider] = enforcement
137+
if enforcement != .off {
138+
isRecaptchaEnabled = true
139+
}
140+
}
141+
}
142+
var siteKey = ""
143+
// Response's site key is of the format projects/<project-id>/keys/<site-key>'
144+
if isRecaptchaEnabled {
145+
if let recaptchaKey = response.recaptchaKey {
146+
let keys = recaptchaKey.components(separatedBy: "/")
147+
if keys.count != 4 {
148+
throw AuthErrorUtils.error(code: .recaptchaNotEnabled, message: "Invalid siteKey")
149+
}
150+
siteKey = keys[3]
99151
}
100152
}
153+
let config = AuthRecaptchaConfig(siteKey: siteKey, enablementStatus: enablementStatus)
154+
155+
if let tenantID = auth?.tenantID {
156+
tenantConfigs[tenantID] = config
157+
} else {
158+
agentConfig = config
159+
}
160+
}
161+
}
101162

163+
#if os(iOS)
164+
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
165+
extension AuthRecaptchaVerifier {
102166
func verify(forceRefresh: Bool, action: AuthRecaptchaAction) async throws -> String {
103167
try await retrieveRecaptchaConfig(forceRefresh: forceRefresh)
104168
guard let siteKey = siteKey() else {
@@ -187,64 +251,6 @@
187251
}
188252
}
189253

190-
func retrieveRecaptchaConfig(forceRefresh: Bool) async throws {
191-
if !forceRefresh {
192-
if let tenantID = auth?.tenantID {
193-
if tenantConfigs[tenantID] != nil {
194-
return
195-
}
196-
} else if agentConfig != nil {
197-
return
198-
}
199-
}
200-
201-
guard let auth = auth else {
202-
throw AuthErrorUtils.error(code: .recaptchaNotEnabled,
203-
message: "No requestConfiguration for Auth instance")
204-
}
205-
let request = GetRecaptchaConfigRequest(requestConfiguration: auth.requestConfiguration)
206-
let response = try await auth.backend.call(with: request)
207-
AuthLog.logInfo(code: "I-AUT000029", message: "reCAPTCHA config retrieval succeeded.")
208-
try await parseRecaptchaConfigFromResponse(response: response)
209-
}
210-
211-
private func parseRecaptchaConfigFromResponse(response: GetRecaptchaConfigResponse) async throws {
212-
var enablementStatus: [AuthRecaptchaProvider: AuthRecaptchaEnablementStatus] = [:]
213-
var isRecaptchaEnabled = false
214-
if let enforcementState = response.enforcementState {
215-
for state in enforcementState {
216-
guard let providerString = state["provider"],
217-
let enforcementString = state["enforcementState"],
218-
let provider = AuthRecaptchaProvider(rawValue: providerString),
219-
let enforcement = AuthRecaptchaEnablementStatus(rawValue: enforcementString) else {
220-
continue // Skip to the next state in the loop
221-
}
222-
enablementStatus[provider] = enforcement
223-
if enforcement != .off {
224-
isRecaptchaEnabled = true
225-
}
226-
}
227-
}
228-
var siteKey = ""
229-
// Response's site key is of the format projects/<project-id>/keys/<site-key>'
230-
if isRecaptchaEnabled {
231-
if let recaptchaKey = response.recaptchaKey {
232-
let keys = recaptchaKey.components(separatedBy: "/")
233-
if keys.count != 4 {
234-
throw AuthErrorUtils.error(code: .recaptchaNotEnabled, message: "Invalid siteKey")
235-
}
236-
siteKey = keys[3]
237-
}
238-
}
239-
let config = AuthRecaptchaConfig(siteKey: siteKey, enablementStatus: enablementStatus)
240-
241-
if let tenantID = auth?.tenantID {
242-
tenantConfigs[tenantID] = config
243-
} else {
244-
agentConfig = config
245-
}
246-
}
247-
248254
func injectRecaptchaFields(request: any AuthRPCRequest,
249255
provider: AuthRecaptchaProvider,
250256
action: AuthRecaptchaAction) async throws {
@@ -257,4 +263,4 @@
257263
}
258264
}
259265
}
260-
#endif // os(iOS)
266+
#endif

0 commit comments

Comments
 (0)