diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m index ce18cea9bae..c7e6c239c4e 100644 --- a/Firebase/Auth/Source/FIRAuth.m +++ b/Firebase/Auth/Source/FIRAuth.m @@ -68,11 +68,6 @@ #pragma mark - Constants -NSString *const FIRAuthStateDidChangeInternalNotification = - @"FIRAuthStateDidChangeInternalNotification"; -NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = - @"FIRAuthStateDidChangeInternalNotificationTokenKey"; - #if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0 const NSNotificationName FIRAuthStateDidChangeNotification = @"FIRAuthStateDidChangeNotification"; #else @@ -1040,6 +1035,9 @@ - (void)notifyListenersOfAuthStateChangeWithUser:(FIRUser *)user token:(NSString [self scheduleAutoTokenRefresh]; } NSMutableDictionary *internalNotificationParameters = [NSMutableDictionary dictionary]; + if (self.app) { + internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationAppKey] = self.app; + } if (token.length) { internalNotificationParameters[FIRAuthStateDidChangeInternalNotificationTokenKey] = token; } diff --git a/Firebase/Auth/Source/FIRAuth_Internal.h b/Firebase/Auth/Source/FIRAuth_Internal.h index 245ce578427..c9d210a147f 100644 --- a/Firebase/Auth/Source/FIRAuth_Internal.h +++ b/Firebase/Auth/Source/FIRAuth_Internal.h @@ -28,22 +28,6 @@ NS_ASSUME_NONNULL_BEGIN -/** @var FIRAuthStateDidChangeInternalNotification - @brief The name of the @c NSNotificationCenter notification which is posted when the auth state - changes (e.g. a new token has been produced, a user logs in or out). The object parameter of - the notification is a dictionary possibly containing the key: - @c FIRAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not - contain this key it indicates a sign-out event took place. - */ -extern NSString *const FIRAuthStateDidChangeInternalNotification; - -/** @var FIRAuthStateDidChangeInternalNotificationTokenKey - @brief A key present in the dictionary object parameter of the - @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this - key will contain the new access token. - */ -extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; - @interface FIRAuth () /** @property requestConfiguration diff --git a/Firebase/Core/FIRApp.m b/Firebase/Core/FIRApp.m index 860bbd31ac1..db2915d9036 100644 --- a/Firebase/Core/FIRApp.m +++ b/Firebase/Core/FIRApp.m @@ -51,6 +51,14 @@ NSString *const kFIRAppDiagnosticsSDKNameKey = @"SDKName"; NSString *const kFIRAppDiagnosticsSDKVersionKey = @"SDKVersion"; +// Auth internal notification notification and key. +NSString *const FIRAuthStateDidChangeInternalNotification = + @"FIRAuthStateDidChangeInternalNotification"; +NSString *const FIRAuthStateDidChangeInternalNotificationAppKey = + @"FIRAuthStateDidChangeInternalNotificationAppKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = + @"FIRAuthStateDidChangeInternalNotificationTokenKey"; + /** * The URL to download plist files. */ diff --git a/Firebase/Core/Private/FIRAppInternal.h b/Firebase/Core/Private/FIRAppInternal.h index 54098d1b571..aa73d8dfa69 100644 --- a/Firebase/Core/Private/FIRAppInternal.h +++ b/Firebase/Core/Private/FIRAppInternal.h @@ -60,6 +60,29 @@ extern NSString *const kFIRAppIsDefaultAppKey; extern NSString *const kFIRAppNameKey; extern NSString *const kFIRGoogleAppIDKey; +/** @var FIRAuthStateDidChangeInternalNotification + @brief The name of the @c NSNotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FIRAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FIRAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FIRAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FIRAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FIRApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + /** @typedef FIRTokenCallback @brief The type of block which gets called when a token is ready. */ diff --git a/Firebase/Database/Api/FIRDatabase.m b/Firebase/Database/Api/FIRDatabase.m index 7466f4c9315..38ccd54e7c1 100644 --- a/Firebase/Database/Api/FIRDatabase.m +++ b/Firebase/Database/Api/FIRDatabase.m @@ -15,6 +15,7 @@ */ #import +#import "FIRAppInternal.h" #import "FIRLogger.h" #import "FIRDatabase.h" #import "FIRDatabase_Private.h" @@ -25,25 +26,7 @@ #import "FRepoInfo.h" #import "FIRDatabaseConfig.h" #import "FIRDatabaseReference_Private.h" - -/** - * This is a hack that defines all the methods we need from FIRApp/Options. At runtime we use reflection to get the - * default FIRApp instance if we need it. Since protocols don't carry any runtime information and selectors - * are invoked by name we can write code against this protocol as long as the method signatures don't change. - * - * TODO: Consider weak-linking the actual Firebase/Core framework or something. - */ - -extern NSString *const kFIRDefaultAppName; - -@protocol FIROptionsLike -@property(nonatomic, readonly, copy) NSString *databaseURL; -@end - -@protocol FIRAppLike -@property(nonatomic, readonly) id options; -@property(nonatomic, copy, readonly) NSString *name; -@end +#import "FIROptions.h" @interface FIRDatabase () @property (nonatomic, strong) FRepoInfo *repoInfo; @@ -77,23 +60,25 @@ + (NSMutableDictionary *)instances { } + (FIRDatabase *)database { - id app = [FIRDatabase getDefaultApp]; - if (app == nil) { - [NSException raise:@"FIRAppNotConfigured" format:@"Failed to get default FIRDatabase instance. Must call FIRApp.configure() before using FIRDatabase."]; + if (![FIRApp isDefaultAppConfigured]) { + [NSException raise:@"FIRAppNotConfigured" + format:@"Failed to get default Firebase Database instance. Must call `[FIRApp " + @"configure]` (`FirebaseApp.configure()` in Swift) before using " + @"Firebase Database."]; } - return [FIRDatabase databaseForApp:(FIRApp*)app]; + FIRApp *app = [FIRApp defaultApp]; + return [FIRDatabase databaseForApp:app]; } -+ (FIRDatabase *)databaseForApp:(id)app { ++ (FIRDatabase *)databaseForApp:(FIRApp *)app { if (app == nil) { [NSException raise:@"InvalidFIRApp" format:@"nil FIRApp instance passed to databaseForApp."]; } NSMutableDictionary *instances = [self instances]; @synchronized (instances) { - id appLike = (id)app; - FIRDatabase *database = instances[appLike.name]; + FIRDatabase *database = instances[app.name]; if (!database) { - NSString *databaseUrl = appLike.options.databaseURL; + NSString *databaseUrl = app.options.databaseURL; if (databaseUrl == nil) { [NSException raise:@"MissingDatabaseURL" format:@"Failed to get FIRDatabase instance: FIRApp object has no " "databaseURL in its FirebaseOptions object."]; @@ -106,20 +91,20 @@ + (FIRDatabase *)databaseForApp:(id)app { databaseUrl, [parsedUrl.path toString]]; } - id authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:appLike]; + id authTokenProvider = [FAuthTokenProvider authTokenProviderForApp:app]; // If this is the default app, don't set the session persistence key so that we use our // default ("default") instead of the FIRApp default ("[DEFAULT]") so that we // preserve the default location used by the legacy Firebase SDK. NSString *sessionIdentifier = @"default"; - if (![appLike.name isEqualToString:kFIRDefaultAppName]) { - sessionIdentifier = appLike.name; + if ([FIRApp isDefaultAppConfigured] && app == [FIRApp defaultApp]) { + sessionIdentifier = app.name; } FIRDatabaseConfig *config = [[FIRDatabaseConfig alloc] initWithSessionIdentifier:sessionIdentifier authTokenProvider:authTokenProvider]; - database = [[FIRDatabase alloc] initWithApp:appLike repoInfo:parsedUrl.repoInfo config:config]; - instances[appLike.name] = database; + database = [[FIRDatabase alloc] initWithApp:app repoInfo:parsedUrl.repoInfo config:config]; + instances[app.name] = database; } return database; @@ -148,12 +133,12 @@ + (void) setLoggingEnabled:(BOOL)enabled { } -- (id)initWithApp:(id )appLike repoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config { +- (id)initWithApp:(FIRApp *)app repoInfo:(FRepoInfo *)info config:(FIRDatabaseConfig *)config { self = [super init]; if (self != nil) { self->_repoInfo = info; self->_config = config; - self->_app = (FIRApp*) appLike; + self->_app = app; } return self; } @@ -204,7 +189,6 @@ - (void)goOnline { }); } - - (void)goOffline { [self ensureRepo]; @@ -213,19 +197,6 @@ - (void)goOffline { }); } -+ (id) getDefaultApp { - Class appClass = NSClassFromString(@"FIRApp"); - if (appClass == nil) { - [NSException raise:@"FailedToFindFIRApp" format:@"Failed to find FIRApp class."]; - return nil; - } else { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" - return [appClass performSelector:@selector(defaultApp)]; -#pragma clang diagnostic pop - } -} - - (void)setPersistenceEnabled:(BOOL)persistenceEnabled { [self assertUnfrozen:@"setPersistenceEnabled"]; self->_config.persistenceEnabled = persistenceEnabled; diff --git a/Firebase/Database/Login/FAuthTokenProvider.h b/Firebase/Database/Login/FAuthTokenProvider.h index dca0026f2cb..363b82f082c 100644 --- a/Firebase/Database/Login/FAuthTokenProvider.h +++ b/Firebase/Database/Login/FAuthTokenProvider.h @@ -19,6 +19,8 @@ #import "FTypedefs.h" #import "FTypedefs_Private.h" +@class FIRApp; + @protocol FAuthTokenProvider - (void) fetchTokenForcingRefresh:(BOOL)forceRefresh withCallback:(fbt_void_nsstring_nserror)callback; @@ -29,7 +31,7 @@ @interface FAuthTokenProvider : NSObject -+ (id) authTokenProviderForApp:(id)app; ++ (id) authTokenProviderForApp:(FIRApp *)app; - (instancetype)init NS_UNAVAILABLE; diff --git a/Firebase/Database/Login/FAuthTokenProvider.m b/Firebase/Database/Login/FAuthTokenProvider.m index f3c2a61f66f..8d656095938 100644 --- a/Firebase/Database/Login/FAuthTokenProvider.m +++ b/Firebase/Database/Login/FAuthTokenProvider.m @@ -16,65 +16,22 @@ #import "FAuthTokenProvider.h" #import "FUtilities.h" +#import "FIRAppInternal.h" #import "FIRLogger.h" #import "FIRDatabaseQuery_Private.h" #import "FIRNoopAuthTokenProvider.h" -static NSString *const FIRAuthStateDidChangeInternalNotification = @"FIRAuthStateDidChangeInternalNotification"; -static NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = @"FIRAuthStateDidChangeInternalNotificationTokenKey"; - - -/** - * This is a hack that defines all the methods we need from FIRFirebaseApp. At runtime we use reflection to get an - * actual instance of FIRFirebaseApp. Since protocols don't carry any runtime information and selectors are invoked - * by name we can write code against this protocol as long as the method signatures of FIRFirebaseApp don't change. - */ -@protocol FIRFirebaseAppLike - -- (void)getTokenForcingRefresh:(BOOL)forceRefresh withCallback:(void (^)(NSString *_Nullable token, NSError *_Nullable error))callback; - -@end - - -/** - * This is a hack that defines all the methods we need from FIRAuth. - */ -@protocol FIRFirebaseAuthLike - -- (id) app; - -@end - -/** - * This is a hack that copies the definitions of Firebase Auth error codes. If the error codes change in the original code, this - * will break at runtime due to undefined behavior! - */ -typedef NS_ENUM(NSUInteger, FIRErrorCode) { - /*! @var FIRErrorCodeNoAuth - @brief Represents the case where an auth-related message was sent to a @c FIRFirebaseApp - instance which has no associated @c FIRAuth instance. - */ - FIRErrorCodeNoAuth, - - /*! @var FIRErrorCodeNoSignedInUser - @brief Represents the case where an attempt was made to fetch a token when there is no signed - in user. - */ - FIRErrorCodeNoSignedInUser, -}; - - @interface FAuthStateListenerWrapper : NSObject @property (nonatomic, copy) fbt_void_nsstring listener; -@property (nonatomic, weak) id app; +@property (nonatomic, weak) FIRApp *app; @end @implementation FAuthStateListenerWrapper -- (instancetype) initWithListener:(fbt_void_nsstring)listener app:(id)app { +- (instancetype) initWithListener:(fbt_void_nsstring)listener app:(FIRApp *)app { self = [super init]; if (self != nil) { self->_listener = listener; @@ -88,9 +45,9 @@ - (instancetype) initWithListener:(fbt_void_nsstring)listener app:(id auth = notification.object; - if (auth.app == self->_app) { - NSDictionary *userInfo = notification.userInfo; + NSDictionary *userInfo = notification.userInfo; + FIRApp *authApp = userInfo[FIRAuthStateDidChangeInternalNotificationAppKey]; + if (authApp == self.app) { NSString *token = userInfo[FIRAuthStateDidChangeInternalNotificationTokenKey]; dispatch_async([FIRDatabaseQuery sharedQueue], ^{ self.listener(token); @@ -107,17 +64,17 @@ - (void) dealloc { @interface FIRFirebaseAuthTokenProvider : NSObject -@property (nonatomic, strong) id app; +@property (nonatomic, strong) FIRApp *app; /** Strong references to the auth listeners as they are only weak in FIRFirebaseApp */ @property (nonatomic, strong) NSMutableArray *authListeners; -- (instancetype) initWithFirebaseApp:(id)app; +- (instancetype) initWithFirebaseApp:(FIRApp *)app; @end @implementation FIRFirebaseAuthTokenProvider -- (instancetype) initWithFirebaseApp:(id)app { +- (instancetype) initWithFirebaseApp:(FIRApp *)app { self = [super init]; if (self != nil) { self->_app = app; @@ -130,19 +87,7 @@ - (void) fetchTokenForcingRefresh:(BOOL)forceRefresh withCallback:(fbt_void_nsst // TODO: Don't fetch token if there is no current user [self.app getTokenForcingRefresh:forceRefresh withCallback:^(NSString * _Nullable token, NSError * _Nullable error) { dispatch_async([FIRDatabaseQuery sharedQueue], ^{ - if (error != nil) { - if (error.code == FIRErrorCodeNoAuth) { - FFLog(@"I-RDB073001", @"Firebase Auth is not configured, not going to use authentication."); - callback(nil, nil); - } else if (error.code == FIRErrorCodeNoSignedInUser) { - // No signed in user is an expected case, callback as success with no token - callback(nil, nil); - } else { - callback(nil, error); - } - } else { - callback(token, nil); - } + callback(token, error); }); }]; } diff --git a/Firebase/Database/Public/FIRDatabase.h b/Firebase/Database/Public/FIRDatabase.h index fd4535f1170..a67f96d6e1a 100644 --- a/Firebase/Database/Public/FIRDatabase.h +++ b/Firebase/Database/Public/FIRDatabase.h @@ -51,7 +51,7 @@ FIR_SWIFT_NAME(Database) * @param app The FIRApp to get a FIRDatabase for. * @return A FIRDatabase instance. */ -+ (FIRDatabase *) databaseForApp:(FIRApp*)app FIR_SWIFT_NAME(database(app:)); ++ (FIRDatabase *) databaseForApp:(FIRApp *)app FIR_SWIFT_NAME(database(app:)); /** The FIRApp instance to which this FIRDatabase belongs. */ @property (weak, readonly, nonatomic) FIRApp *app;