Skip to content

Commit 4720f42

Browse files
committed
fix Audit mode fallback failure
1 parent a6115f9 commit 4720f42

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

FirebaseAuth/Sources/Swift/AuthProvider/PhoneAuthProvider.swift

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ import Foundation
2222
@objc(FIRPhoneAuthProvider) open class PhoneAuthProvider: NSObject {
2323
/// A string constant identifying the phone identity provider.
2424
@objc public static let id = "phone"
25+
@objc private static let kRecaptchaVersion = "RECAPTCHA_ENTERPRISE"
26+
@objc private static let kClientType = "CLIENT_TYPE_IOS"
27+
@objc private static let kFakeCaptchaResponse = "NO_RECAPTCHA"
28+
2529
#if os(iOS)
2630
/// Returns an instance of `PhoneAuthProvider` for the default `Auth` object.
2731
@objc(provider) open class func provider() -> PhoneAuthProvider {
@@ -250,7 +254,8 @@ import Foundation
250254
phoneNumber: phoneNumber,
251255
retryOnInvalidAppCredential: retryOnInvalidAppCredential,
252256
multiFactorSession: nil,
253-
uiDelegate: uiDelegate)
257+
uiDelegate: uiDelegate,
258+
auditFallback: true)
254259
}
255260
}
256261

@@ -262,13 +267,18 @@ import Foundation
262267
/// finished.
263268
func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String,
264269
retryOnInvalidAppCredential: Bool,
265-
uiDelegate: AuthUIDelegate?) async throws
270+
uiDelegate: AuthUIDelegate?,
271+
auditFallback: Bool = false) async throws
266272
-> String? {
267273
let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate)
268274
let request = SendVerificationCodeRequest(phoneNumber: phoneNumber,
269275
codeIdentity: codeIdentity,
270276
requestConfiguration: auth
271277
.requestConfiguration)
278+
if auditFallback {
279+
request.injectRecaptchaFields(recaptchaResponse: PhoneAuthProvider.kFakeCaptchaResponse, recaptchaVersion: PhoneAuthProvider.kRecaptchaVersion)
280+
}
281+
//TODO inject fake_token when .audit
272282
do {
273283
let response = try await auth.backend.call(with: request)
274284
return response.verificationID
@@ -278,12 +288,13 @@ import Foundation
278288
phoneNumber: phoneNumber,
279289
retryOnInvalidAppCredential: retryOnInvalidAppCredential,
280290
multiFactorSession: nil,
281-
uiDelegate: uiDelegate
291+
uiDelegate: uiDelegate,
292+
auditFallback: auditFallback
282293
)
283294
}
284295
}
285296

286-
/// Starts the flow to verify the client via silent push notification.
297+
/// Starts the flow to verify the client via silent push notification. This is used in both .Audit and .Enforce mode
287298
/// - Parameter retryOnInvalidAppCredential: Whether of not the flow should be retried if an
288299
/// AuthErrorCodeInvalidAppCredential error is returned from the backend.
289300
/// - Parameter phoneNumber: The phone number to be verified.
@@ -339,24 +350,28 @@ import Foundation
339350
return response.responseInfo?.sessionInfo
340351
}
341352
} catch {
353+
// For Audit fallback only after rCE check failed
342354
return try await handleVerifyErrorWithRetry(
343355
error: error,
344356
phoneNumber: phoneNumber,
345357
retryOnInvalidAppCredential: retryOnInvalidAppCredential,
346358
multiFactorSession: session,
347-
uiDelegate: uiDelegate
359+
uiDelegate: uiDelegate,
360+
auditFallback: true
348361
)
349362
}
350363
}
351364

352365
/// Starts the flow to verify the client via silent push notification.
366+
/// This method is called in Audit fallback flow with "NO_RECAPTCHA" fake token and Off flow
353367
/// - Parameter retryOnInvalidAppCredential: Whether of not the flow should be retried if an
354368
/// AuthErrorCodeInvalidAppCredential error is returned from the backend.
355369
/// - Parameter phoneNumber: The phone number to be verified.
356370
private func verifyClAndSendVerificationCode(toPhoneNumber phoneNumber: String,
357371
retryOnInvalidAppCredential: Bool,
358372
multiFactorSession session: MultiFactorSession?,
359-
uiDelegate: AuthUIDelegate?) async throws
373+
uiDelegate: AuthUIDelegate?,
374+
auditFallback: Bool = false) async throws
360375
-> String? {
361376
if let settings = auth.settings,
362377
settings.isAppVerificationDisabledForTesting {
@@ -370,20 +385,27 @@ import Foundation
370385
return response.verificationID
371386
}
372387
guard let session else {
388+
// Phone MFA flow
373389
return try await verifyClAndSendVerificationCode(
374390
toPhoneNumber: phoneNumber,
375391
retryOnInvalidAppCredential: retryOnInvalidAppCredential,
376-
uiDelegate: uiDelegate
392+
uiDelegate: uiDelegate,
393+
auditFallback: auditFallback
377394
)
378395
}
396+
// MFA flows
379397
let codeIdentity = try await verifyClient(withUIDelegate: uiDelegate)
380398
let startMFARequestInfo = AuthProtoStartMFAPhoneRequestInfo(phoneNumber: phoneNumber,
381399
codeIdentity: codeIdentity)
400+
if auditFallback {
401+
startMFARequestInfo.injectRecaptchaFields(recaptchaResponse: PhoneAuthProvider.kFakeCaptchaResponse, recaptchaVersion: PhoneAuthProvider.kRecaptchaVersion, clientType: PhoneAuthProvider.kClientType)
402+
}
382403
do {
383404
if let idToken = session.idToken {
384405
let request = StartMFAEnrollmentRequest(idToken: idToken,
385406
enrollmentInfo: startMFARequestInfo,
386407
requestConfiguration: auth.requestConfiguration)
408+
// TODO if mode is audit, inject recaptcha field with no_recaptcha
387409
let response = try await auth.backend.call(with: request)
388410
return response.phoneSessionInfo?.sessionInfo
389411
} else {
@@ -401,23 +423,27 @@ import Foundation
401423
phoneNumber: phoneNumber,
402424
retryOnInvalidAppCredential: retryOnInvalidAppCredential,
403425
multiFactorSession: session,
404-
uiDelegate: uiDelegate
426+
uiDelegate: uiDelegate,
427+
auditFallback: auditFallback
405428
)
406429
}
407430
}
408431

432+
/// This method is only called when Audit failed on rCE on invalid-app-credential exception
409433
private func handleVerifyErrorWithRetry(error: Error,
410434
phoneNumber: String,
411435
retryOnInvalidAppCredential: Bool,
412436
multiFactorSession session: MultiFactorSession?,
413-
uiDelegate: AuthUIDelegate?) async throws -> String? {
437+
uiDelegate: AuthUIDelegate?,
438+
auditFallback: Bool = false) async throws -> String? {
414439
if (error as NSError).code == AuthErrorCode.invalidAppCredential.rawValue {
415440
if retryOnInvalidAppCredential {
416441
auth.appCredentialManager.clearCredential()
417442
return try await verifyClAndSendVerificationCode(toPhoneNumber: phoneNumber,
418443
retryOnInvalidAppCredential: false,
419444
multiFactorSession: session,
420-
uiDelegate: uiDelegate)
445+
uiDelegate: uiDelegate,
446+
auditFallback: auditFallback)
421447
}
422448
throw AuthErrorUtils.unexpectedResponse(deserializedResponse: nil, underlyingError: error)
423449
}

0 commit comments

Comments
 (0)