Skip to content

Commit

Permalink
Try to address prewarming issue by catching keychain errors instead o…
Browse files Browse the repository at this point in the history
…f using `isProtectedDataAvailable` (#9898)

* Another attempt at fixing prewarming issues.

* Fix style.

* Check the correct error code.

* Add changelog and fix style.

* Prevent retain cycle?

* Prevent retain cycle?

* Address review comment.

* Move observer removal into block.

* Update version number in changelog.
  • Loading branch information
rosalyntan authored Jun 14, 2022
1 parent 16b9b4d commit e8828e8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 34 deletions.
3 changes: 3 additions & 0 deletions FirebaseAuth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# 9.2.0
- [fixed] Catch keychain errors instead of using the `isProtectedDataAvailable` API for handling prewarming issue. (#9869)

# 9.0.0
- [fixed] **Breaking change:** Fixed an ObjC-to-Swift API conversion error where `getStoredUser(forAccessGroup:)` returned a non-optional type. This change is breaking for Swift users only (#8599).
- [fixed] Fixed an iOS 15 keychain access issue related to prewarming. (#8695)
Expand Down
76 changes: 42 additions & 34 deletions FirebaseAuth/Sources/Auth/FIRAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -496,46 +496,12 @@ - (nullable instancetype)initWithAPIKey:(NSString *)APIKey
[GULSceneDelegateSwizzler proxyOriginalSceneDelegate];
#endif // TARGET_OS_IOS

#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
static Class applicationClass = nil;
// iOS App extensions should not call [UIApplication sharedApplication], even if UIApplication
// responds to it.
if (![GULAppEnvironmentUtil isAppExtension]) {
Class cls = NSClassFromString(@"UIApplication");
if (cls && [cls respondsToSelector:@selector(sharedApplication)]) {
applicationClass = cls;
}
}
UIApplication *application = [applicationClass sharedApplication];
if ([application respondsToSelector:@selector(isProtectedDataAvailable)]) {
if ([application isProtectedDataAvailable]) {
[self protectedDataInitialization];
} else {
// Add listener for UIApplicationProtectedDataDidBecomeAvailable.
self->_protectedDataDidBecomeAvailableObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationProtectedDataDidBecomeAvailable
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
[self protectedDataInitialization];
}];
}
} else {
[self protectedDataInitialization];
}
#else
[self protectedDataInitialization];
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
}
return self;
}

- (void)protectedDataInitialization {
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
[[NSNotificationCenter defaultCenter] removeObserver:_protectedDataDidBecomeAvailableObserver
name:UIApplicationProtectedDataDidBecomeAvailable
object:nil];
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
// Continue with the rest of initialization in the work thread.
__weak FIRAuth *weakSelf = self;
dispatch_async(FIRAuthGlobalWorkQueue(), ^{
Expand Down Expand Up @@ -564,17 +530,41 @@ - (void)protectedDataInitialization {
[strongSelf updateCurrentUser:user byForce:NO savingToDisk:NO error:&error];
self->_lastNotifiedUserToken = user.rawAccessToken;
} else {
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
if (error.code == FIRAuthErrorCodeKeychainError) {
// If there's a keychain error, assume it is due to the keychain being accessed
// before the device is unlocked as a result of prewarming, and listen for the
// UIApplicationProtectedDataDidBecomeAvailable notification.
[strongSelf addProtectedDataDidBecomeAvailableObserver];
}
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
@"Error loading saved user when starting up: %@", error);
}
} else {
[strongSelf internalUseUserAccessGroup:storedUserAccessGroup error:&error];
if (error) {
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
if (error.code == FIRAuthErrorCodeKeychainError) {
// If there's a keychain error, assume it is due to the keychain being accessed
// before the device is unlocked as a result of prewarming, and listen for the
// UIApplicationProtectedDataDidBecomeAvailable notification.
[strongSelf addProtectedDataDidBecomeAvailableObserver];
}
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
FIRLogError(kFIRLoggerAuth, @"I-AUT000001",
@"Error loading saved user when starting up: %@", error);
}
}
} else {
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
if (error.code == FIRAuthErrorCodeKeychainError) {
// If there's a keychain error, assume it is due to the keychain being accessed
// before the device is unlocked as a result of prewarming, and listen for the
// UIApplicationProtectedDataDidBecomeAvailable notification.
[strongSelf addProtectedDataDidBecomeAvailableObserver];
}
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
FIRLogError(kFIRLoggerAuth, @"I-AUT000001", @"Error loading saved user when starting up: %@",
error);
}
Expand Down Expand Up @@ -613,6 +603,24 @@ - (void)protectedDataInitialization {
});
}

#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST
- (void)addProtectedDataDidBecomeAvailableObserver {
__weak FIRAuth *weakSelf = self;
self->_protectedDataDidBecomeAvailableObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationProtectedDataDidBecomeAvailable
object:nil
queue:nil
usingBlock:^(NSNotification *notification) {
FIRAuth *strongSelf = weakSelf;
[[NSNotificationCenter defaultCenter]
removeObserver:strongSelf->_protectedDataDidBecomeAvailableObserver
name:UIApplicationProtectedDataDidBecomeAvailable
object:nil];
[strongSelf protectedDataInitialization];
}];
}
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_MACCATALYST

- (void)dealloc {
@synchronized(self) {
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
Expand Down

0 comments on commit e8828e8

Please sign in to comment.