|
|
@@ -18,8 +18,17 @@
|
|
|
|
|
|
#import "FIRAuth_Internal.h"
|
|
|
|
|
|
+#if __has_include(<UIKit/UIKit.h>)
|
|
|
+#import <UIKit/UIKit.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+#import <FirebaseAuthInterop/FIRAuthInterop.h>
|
|
|
#import <FirebaseCore/FIRAppAssociationRegistration.h>
|
|
|
#import <FirebaseCore/FIRAppInternal.h>
|
|
|
+#import <FirebaseCore/FIRComponent.h>
|
|
|
+#import <FirebaseCore/FIRComponentContainer.h>
|
|
|
+#import <FirebaseCore/FIRComponentRegistrant.h>
|
|
|
+#import <FirebaseCore/FIRCoreConfigurable.h>
|
|
|
#import <FirebaseCore/FIRLogger.h>
|
|
|
#import <FirebaseCore/FIROptions.h>
|
|
|
#import <GoogleUtilities/GULAppEnvironmentUtil.h>
|
|
|
@@ -63,7 +72,6 @@
|
|
|
#import "FIRVerifyPhoneNumberResponse.h"
|
|
|
|
|
|
#if TARGET_OS_IOS
|
|
|
-#import <UIKit/UIKit.h>
|
|
|
#import "FIRAuthAPNSToken.h"
|
|
|
#import "FIRAuthAPNSTokenManager.h"
|
|
|
#import "FIRAuthAppCredentialManager.h"
|
|
|
@@ -218,9 +226,9 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
|
|
|
#pragma mark - FIRAuth
|
|
|
|
|
|
#if TARGET_OS_IOS
|
|
|
-@interface FIRAuth () <FIRAuthAppDelegateHandler>
|
|
|
+@interface FIRAuth () <FIRAuthAppDelegateHandler, FIRAuthInterop, FIRComponentRegistrant, FIRCoreConfigurable, FIRComponentLifecycleMaintainer>
|
|
|
#else
|
|
|
-@interface FIRAuth ()
|
|
|
+@interface FIRAuth () <FIRAuthInterop, FIRComponentRegistrant, FIRCoreConfigurable, FIRComponentLifecycleMaintainer>
|
|
|
#endif
|
|
|
|
|
|
/** @property firebaseAppId
|
|
|
@@ -300,42 +308,12 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
|
|
|
}
|
|
|
|
|
|
+ (void)load {
|
|
|
- static dispatch_once_t onceToken;
|
|
|
- dispatch_once(&onceToken, ^{
|
|
|
- gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init];
|
|
|
-
|
|
|
- NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
|
|
+ [FIRComponentContainer registerAsComponentRegistrant:self];
|
|
|
+ [FIRApp registerAsConfigurable:self];
|
|
|
+}
|
|
|
|
|
|
- // Ensures the @c FIRAuth instance for a given app gets loaded as soon as the app is ready.
|
|
|
- [defaultCenter addObserverForName:kFIRAppReadyToConfigureSDKNotification
|
|
|
- object:[FIRApp class]
|
|
|
- queue:nil
|
|
|
- usingBlock:^(NSNotification *notification) {
|
|
|
- [FIRAuth authWithApp:[FIRApp appNamed:notification.userInfo[kFIRAppNameKey]]];
|
|
|
- }];
|
|
|
- // Ensures the saved user is cleared when the app is deleted.
|
|
|
- [defaultCenter addObserverForName:kFIRAppDeleteNotification
|
|
|
- object:[FIRApp class]
|
|
|
- queue:nil
|
|
|
- usingBlock:^(NSNotification *notification) {
|
|
|
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
|
|
|
- // This doesn't stop any request already issued, see b/27704535 .
|
|
|
- NSString *appName = notification.userInfo[kFIRAppNameKey];
|
|
|
- NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:appName];
|
|
|
- if (keychainServiceName) {
|
|
|
- [self deleteKeychainServiceNameForAppName:appName];
|
|
|
- FIRAuthKeychain *keychain = [[FIRAuthKeychain alloc] initWithService:keychainServiceName];
|
|
|
- NSString *userKey = [NSString stringWithFormat:kUserKey, appName];
|
|
|
- [keychain removeDataForKey:userKey error:NULL];
|
|
|
- }
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- [[NSNotificationCenter defaultCenter]
|
|
|
- postNotificationName:FIRAuthStateDidChangeNotification
|
|
|
- object:nil];
|
|
|
- });
|
|
|
- });
|
|
|
- }];
|
|
|
- });
|
|
|
++ (void)initialize {
|
|
|
+ gKeychainServiceNameForAppName = [[NSMutableDictionary alloc] init];
|
|
|
}
|
|
|
|
|
|
+ (FIRAuth *)auth {
|
|
|
@@ -352,11 +330,10 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
|
|
|
}
|
|
|
|
|
|
+ (FIRAuth *)authWithApp:(FIRApp *)app {
|
|
|
- return [FIRAppAssociationRegistration registeredObjectWithHost:app
|
|
|
- key:NSStringFromClass(self)
|
|
|
- creationBlock:^FIRAuth *_Nullable() {
|
|
|
- return [[FIRAuth alloc] initWithApp:app];
|
|
|
- }];
|
|
|
+ // Get the instance of Auth from the container, which will create or return the cached instance
|
|
|
+ // associated with this app.
|
|
|
+ id<FIRAuthInterop> auth = FIR_COMPONENT(FIRAuthInterop, app.container);
|
|
|
+ return (FIRAuth *)auth;
|
|
|
}
|
|
|
|
|
|
- (instancetype)initWithApp:(FIRApp *)app {
|
|
|
@@ -365,62 +342,19 @@ static NSMutableDictionary *gKeychainServiceNameForAppName;
|
|
|
if (self) {
|
|
|
_app = app;
|
|
|
__weak FIRAuth *weakSelf = self;
|
|
|
+
|
|
|
+ // TODO: Remove this block once Firestore, Database, and Storage move to the new interop API.
|
|
|
app.getTokenImplementation = ^(BOOL forceRefresh, FIRTokenCallback callback) {
|
|
|
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
|
|
|
- FIRAuth *strongSelf = weakSelf;
|
|
|
- // Enable token auto-refresh if not aleady enabled.
|
|
|
- if (strongSelf && !strongSelf->_autoRefreshTokens) {
|
|
|
- FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled.");
|
|
|
- strongSelf->_autoRefreshTokens = YES;
|
|
|
- [strongSelf scheduleAutoTokenRefresh];
|
|
|
-
|
|
|
- #if TARGET_OS_IOS // TODO: Is a similar mechanism needed on macOS?
|
|
|
- strongSelf->_applicationDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter]
|
|
|
- addObserverForName:UIApplicationDidBecomeActiveNotification
|
|
|
- object:nil
|
|
|
- queue:nil
|
|
|
- usingBlock:^(NSNotification *notification) {
|
|
|
- FIRAuth *strongSelf = weakSelf;
|
|
|
- if (strongSelf) {
|
|
|
- strongSelf->_isAppInBackground = NO;
|
|
|
- if (!strongSelf->_autoRefreshScheduled) {
|
|
|
- [weakSelf scheduleAutoTokenRefresh];
|
|
|
- }
|
|
|
- }
|
|
|
- }];
|
|
|
- strongSelf->_applicationDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter]
|
|
|
- addObserverForName:UIApplicationDidEnterBackgroundNotification
|
|
|
- object:nil
|
|
|
- queue:nil
|
|
|
- usingBlock:^(NSNotification *notification) {
|
|
|
- FIRAuth *strongSelf = weakSelf;
|
|
|
- if (strongSelf) {
|
|
|
- strongSelf->_isAppInBackground = YES;
|
|
|
- }
|
|
|
- }];
|
|
|
- #endif
|
|
|
- }
|
|
|
- // Call back with 'nil' if there is no current user.
|
|
|
- if (!strongSelf || !strongSelf->_currentUser) {
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- callback(nil, nil);
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
- // Call back with current user token.
|
|
|
- [strongSelf->_currentUser internalGetTokenForcingRefresh:forceRefresh
|
|
|
- callback:^(NSString *_Nullable token,
|
|
|
- NSError *_Nullable error) {
|
|
|
- dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
- callback(token, error);
|
|
|
- });
|
|
|
- }];
|
|
|
- });
|
|
|
+ // In the meantime, redirect call to the interop method that provides this functionality.
|
|
|
+ __weak FIRAuth *weakSelf = self;
|
|
|
+ [weakSelf getTokenForcingRefresh:forceRefresh withCallback:callback];
|
|
|
};
|
|
|
+
|
|
|
+ // TODO: Remove this block once Firestore, Database, and Storage move to the new interop API.
|
|
|
app.getUIDImplementation = ^NSString *_Nullable() {
|
|
|
__block NSString *uid;
|
|
|
dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
|
|
|
- uid = [weakSelf getUID];
|
|
|
+ uid = [weakSelf getUserID];
|
|
|
});
|
|
|
return uid;
|
|
|
};
|
|
|
@@ -1878,7 +1812,105 @@ static NSDictionary<NSString *, NSString *> *FIRAuthParseURL(NSString *urlString
|
|
|
return YES;
|
|
|
}
|
|
|
|
|
|
-- (nullable NSString *)getUID {
|
|
|
+#pragma mark - Interoperability
|
|
|
+
|
|
|
++ (nonnull NSArray<FIRComponent *> *)componentsToRegister {
|
|
|
+ FIRComponentCreationBlock authCreationBlock =
|
|
|
+ ^id _Nullable(FIRComponentContainer *_Nonnull container, BOOL *_Nonnull isCacheable) {
|
|
|
+ *isCacheable = YES;
|
|
|
+ return [[FIRAuth alloc] initWithApp:container.app];
|
|
|
+ };
|
|
|
+ FIRComponent *authInterop = [FIRComponent componentWithProtocol:@protocol(FIRAuthInterop)
|
|
|
+ creationBlock:authCreationBlock];
|
|
|
+ return @[authInterop];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - FIRCoreConfigurable
|
|
|
+
|
|
|
++ (void)configureWithApp:(nonnull FIRApp *)app {
|
|
|
+ // TODO: Evaluate what actually needs to be configured here instead of initializing a full
|
|
|
+ // instance.
|
|
|
+ // Ensures the @c FIRAuth instance for a given app gets loaded as soon as the app is ready.
|
|
|
+ [FIRAuth authWithApp:app];
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - FIRComponentLifecycleMaintainer
|
|
|
+
|
|
|
+- (void)appWillBeDeleted:(nonnull FIRApp *)app {
|
|
|
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
|
|
|
+ // This doesn't stop any request already issued, see b/27704535 .
|
|
|
+ NSString *keychainServiceName = [FIRAuth keychainServiceNameForAppName:app.name];
|
|
|
+ if (keychainServiceName) {
|
|
|
+ [[self class] deleteKeychainServiceNameForAppName:app.name];
|
|
|
+ FIRAuthKeychain *keychain = [[FIRAuthKeychain alloc] initWithService:keychainServiceName];
|
|
|
+ NSString *userKey = [NSString stringWithFormat:kUserKey, app.name];
|
|
|
+ [keychain removeDataForKey:userKey error:NULL];
|
|
|
+ }
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ // TODO: Move over to fire an event instead, once ready.
|
|
|
+ [[NSNotificationCenter defaultCenter] postNotificationName:FIRAuthStateDidChangeNotification
|
|
|
+ object:nil];
|
|
|
+ });
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+#pragma mark - FIRAuthInterop
|
|
|
+
|
|
|
+- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(FIRTokenCallback)callback {
|
|
|
+ __weak FIRAuth *weakSelf = self;
|
|
|
+ dispatch_async(FIRAuthGlobalWorkQueue(), ^{
|
|
|
+ FIRAuth *strongSelf = weakSelf;
|
|
|
+ // Enable token auto-refresh if not aleady enabled.
|
|
|
+ if (strongSelf && !strongSelf->_autoRefreshTokens) {
|
|
|
+ FIRLogInfo(kFIRLoggerAuth, @"I-AUT000002", @"Token auto-refresh enabled.");
|
|
|
+ strongSelf->_autoRefreshTokens = YES;
|
|
|
+ [strongSelf scheduleAutoTokenRefresh];
|
|
|
+
|
|
|
+#if TARGET_OS_IOS || TARGET_OS_TV // TODO: Is a similar mechanism needed on macOS?
|
|
|
+ strongSelf->_applicationDidBecomeActiveObserver = [[NSNotificationCenter defaultCenter]
|
|
|
+ addObserverForName:UIApplicationDidBecomeActiveNotification
|
|
|
+ object:nil
|
|
|
+ queue:nil
|
|
|
+ usingBlock:^(NSNotification *notification) {
|
|
|
+ FIRAuth *strongSelf = weakSelf;
|
|
|
+ if (strongSelf) {
|
|
|
+ strongSelf->_isAppInBackground = NO;
|
|
|
+ if (!strongSelf->_autoRefreshScheduled) {
|
|
|
+ [weakSelf scheduleAutoTokenRefresh];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }];
|
|
|
+ strongSelf->_applicationDidEnterBackgroundObserver = [[NSNotificationCenter defaultCenter]
|
|
|
+ addObserverForName:UIApplicationDidEnterBackgroundNotification
|
|
|
+ object:nil
|
|
|
+ queue:nil
|
|
|
+ usingBlock:^(NSNotification *notification) {
|
|
|
+ FIRAuth *strongSelf = weakSelf;
|
|
|
+ if (strongSelf) {
|
|
|
+ strongSelf->_isAppInBackground = YES;
|
|
|
+ }
|
|
|
+ }];
|
|
|
+#endif
|
|
|
+ }
|
|
|
+ // Call back with 'nil' if there is no current user.
|
|
|
+ if (!strongSelf || !strongSelf->_currentUser) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ callback(nil, nil);
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // Call back with current user token.
|
|
|
+ [strongSelf->_currentUser internalGetTokenForcingRefresh:forceRefresh
|
|
|
+ callback:^(NSString *_Nullable token,
|
|
|
+ NSError *_Nullable error) {
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ callback(token, error);
|
|
|
+ });
|
|
|
+ }];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+- (nullable NSString *)getUserID {
|
|
|
return _currentUser.uid;
|
|
|
}
|
|
|
|