Skip to content

Commit 752cbca

Browse files
authored
fix(auth, ios): serialize Sign in with Apple to prevent crash on overlapping requests (#18172)
1 parent 501168a commit 752cbca

1 file changed

Lines changed: 63 additions & 19 deletions

File tree

packages/firebase_auth/firebase_auth/ios/firebase_auth/Sources/firebase_auth/FLTFirebaseAuthPlugin.m

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ @interface FLTFirebaseAuthPlugin ()
9797
@property(strong, nonatomic) void (^appleCompletion)
9898
(PigeonUserCredential *_Nullable, FlutterError *_Nullable);
9999
@property(strong, nonatomic) AuthPigeonFirebaseApp *appleArguments;
100+
/// YES while an `ASAuthorizationController` Sign in with Apple flow is active.
101+
@property(nonatomic, assign) BOOL appleSignInRequestInFlight;
100102

101103
@end
102104

@@ -380,16 +382,25 @@ static void handleSignInWithApple(FLTFirebaseAuthPlugin *object, FIRAuthDataResu
380382
NSString *authorizationCode, NSError *error) {
381383
void (^completion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) =
382384
object.appleCompletion;
383-
if (completion == nil) return;
385+
if (completion == nil) {
386+
object.appleSignInRequestInFlight = NO;
387+
return;
388+
}
384389

385390
if (error != nil) {
386391
if (error.code == FIRAuthErrorCodeSecondFactorRequired) {
392+
object.appleCompletion = nil;
393+
object.appleSignInRequestInFlight = NO;
387394
[object handleMultiFactorError:object.appleArguments completion:completion withError:error];
388395
} else {
396+
object.appleCompletion = nil;
397+
object.appleSignInRequestInFlight = NO;
389398
completion(nil, [FLTFirebaseAuthPlugin convertToFlutterError:error]);
390399
}
391400
return;
392401
}
402+
object.appleCompletion = nil;
403+
object.appleSignInRequestInFlight = NO;
393404
completion([PigeonParser getPigeonUserCredentialFromAuthResult:authResult
394405
authorizationCode:authorizationCode],
395406
nil);
@@ -406,6 +417,15 @@ - (void)authorizationController:(ASAuthorizationController *)controller
406417

407418
if (appleIDCredential.identityToken == nil) {
408419
NSLog(@"Unable to fetch identity token.");
420+
void (^completion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) =
421+
self.appleCompletion;
422+
self.appleCompletion = nil;
423+
self.appleSignInRequestInFlight = NO;
424+
if (completion != nil) {
425+
completion(nil, [FlutterError errorWithCode:kErrCodeInvalidCredential
426+
message:kErrMsgInvalidCredential
427+
details:nil]);
428+
}
409429
return;
410430
}
411431

@@ -459,47 +479,62 @@ - (void)authorizationController:(ASAuthorizationController *)controller
459479
handleSignInWithApple(self, authResult, authorizationCode, error);
460480
}];
461481
}
482+
} else {
483+
void (^completion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) =
484+
self.appleCompletion;
485+
self.appleCompletion = nil;
486+
self.appleSignInRequestInFlight = NO;
487+
if (completion != nil) {
488+
completion(nil, [FlutterError errorWithCode:kErrCodeInvalidCredential
489+
message:kErrMsgInvalidCredential
490+
details:nil]);
491+
}
462492
}
463493
}
464494

465495
- (void)authorizationController:(ASAuthorizationController *)controller
466496
didCompleteWithError:(NSError *)error API_AVAILABLE(macos(10.15), ios(13.0)) {
497+
void (^completion)(PigeonUserCredential *_Nullable, FlutterError *_Nullable) =
498+
self.appleCompletion;
499+
self.appleCompletion = nil;
500+
self.appleSignInRequestInFlight = NO;
501+
467502
NSLog(@"Sign in with Apple errored: %@", error);
503+
if (completion == nil) {
504+
return;
505+
}
506+
468507
switch (error.code) {
469508
case ASAuthorizationErrorCanceled:
470-
self.appleCompletion(
471-
nil, [FlutterError errorWithCode:@"canceled"
472-
message:@"The user canceled the authorization attempt."
473-
details:nil]);
509+
completion(nil, [FlutterError errorWithCode:@"canceled"
510+
message:@"The user canceled the authorization attempt."
511+
details:nil]);
474512
break;
475513

476514
case ASAuthorizationErrorInvalidResponse:
477-
self.appleCompletion(
478-
nil,
479-
[FlutterError errorWithCode:@"invalid-response"
480-
message:@"The authorization request received an invalid response."
481-
details:nil]);
515+
completion(nil, [FlutterError
516+
errorWithCode:@"invalid-response"
517+
message:@"The authorization request received an invalid response."
518+
details:nil]);
482519
break;
483520

484521
case ASAuthorizationErrorNotHandled:
485-
self.appleCompletion(nil,
486-
[FlutterError errorWithCode:@"not-handled"
487-
message:@"The authorization request wasn’t handled."
488-
details:nil]);
522+
completion(nil, [FlutterError errorWithCode:@"not-handled"
523+
message:@"The authorization request wasn’t handled."
524+
details:nil]);
489525
break;
490526

491527
case ASAuthorizationErrorFailed:
492-
self.appleCompletion(nil, [FlutterError errorWithCode:@"failed"
493-
message:@"The authorization attempt failed."
494-
details:nil]);
528+
completion(nil, [FlutterError errorWithCode:@"failed"
529+
message:@"The authorization attempt failed."
530+
details:nil]);
495531
break;
496532

497533
case ASAuthorizationErrorUnknown:
498534
default:
499-
self.appleCompletion(nil, [FLTFirebaseAuthPlugin convertToFlutterError:error]);
535+
completion(nil, [FLTFirebaseAuthPlugin convertToFlutterError:error]);
500536
break;
501537
}
502-
self.appleCompletion = nil;
503538
}
504539

505540
- (void)handleInternalError:(nonnull void (^)(PigeonUserCredential *_Nullable,
@@ -570,10 +605,19 @@ static void launchAppleSignInRequest(FLTFirebaseAuthPlugin *object, AuthPigeonFi
570605
void (^_Nonnull completion)(PigeonUserCredential *_Nullable,
571606
FlutterError *_Nullable)) {
572607
if (@available(iOS 13.0, macOS 10.15, *)) {
608+
if (object.appleSignInRequestInFlight) {
609+
completion(nil,
610+
[FlutterError errorWithCode:@"operation-not-allowed"
611+
message:@"A Sign in with Apple request is already in progress."
612+
details:nil]);
613+
return;
614+
}
615+
573616
NSString *nonce = [object randomNonce:32];
574617
object.currentNonce = nonce;
575618
object.appleCompletion = completion;
576619
object.appleArguments = app;
620+
object.appleSignInRequestInFlight = YES;
577621

578622
ASAuthorizationAppleIDProvider *appleIDProvider = [[ASAuthorizationAppleIDProvider alloc] init];
579623

0 commit comments

Comments
 (0)