From 6566328dc461c38c6000c64996c17883b9895d06 Mon Sep 17 00:00:00 2001 From: Zsika Phillip Date: Tue, 3 Apr 2018 17:19:51 -0700 Subject: Adds copy auth state API (#1018) * Adds copy auth state API * improvements * Addresses comments --- Firebase/Auth/Source/FIRAuth.m | 46 ++++++++++++++++++++++++++++ Firebase/Auth/Source/FIRAuthErrorUtils.h | 7 +++++ Firebase/Auth/Source/FIRAuthErrorUtils.m | 19 ++++++++++-- Firebase/Auth/Source/FIRAuthInternalErrors.h | 6 ++++ Firebase/Auth/Source/FIRUser.m | 6 ++-- Firebase/Auth/Source/FIRUser_Internal.h | 6 ++++ Firebase/Auth/Source/Public/FIRAuth.h | 13 ++++++++ Firebase/Auth/Source/Public/FIRAuthErrors.h | 5 +++ 8 files changed, 104 insertions(+), 4 deletions(-) (limited to 'Firebase/Auth') diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m index dc3154f..d4ced9c 100644 --- a/Firebase/Auth/Source/FIRAuth.m +++ b/Firebase/Auth/Source/FIRAuth.m @@ -1137,6 +1137,52 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; }); } +- (void)updateCurrentUser:(FIRUser *)user completion:(nullable FIRUserUpdateCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!user) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion([FIRAuthErrorUtils nullUserErrorWithMessage:nil]); + }); + } + return; + } + void (^updateUserBlock)(FIRUser *user) = ^(FIRUser *user) { + NSError *error; + [self updateCurrentUser:user byForce:YES savingToDisk:YES error:(&error)]; + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(nil); + }); + } + }; + if (![user.requestConfiguration.APIKey isEqualToString:self->_requestConfiguration.APIKey]) { + // If the API keys are different, then we need to confirm that the user belongs to the same + // project before proceeding. + user.requestConfiguration = self->_requestConfiguration; + [user reloadWithCompletion:^(NSError *_Nullable error) { + if (error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + return; + } + updateUserBlock(user); + }]; + } else { + updateUserBlock(user); + } + }); +} - (BOOL)signOut:(NSError *_Nullable __autoreleasing *_Nullable)error { __block BOOL result = YES; diff --git a/Firebase/Auth/Source/FIRAuthErrorUtils.h b/Firebase/Auth/Source/FIRAuthErrorUtils.h index c3fad0d..5b8205f 100644 --- a/Firebase/Auth/Source/FIRAuthErrorUtils.h +++ b/Firebase/Auth/Source/FIRAuthErrorUtils.h @@ -481,6 +481,13 @@ NS_ASSUME_NONNULL_BEGIN */ + (NSError *)URLResponseErrorWithCode:(NSString *)code message:(nullable NSString *)message; +/** @fn nullUserErrorWithMessage: + @brief Constructs an @c NSError with the code and message provided. + @param message Error message from the backend, if any. + @return The nullable NSError instance associated with the given error message, if one is found. + */ ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message; + /** @fn keychainErrorWithFunction:status: @brief Constructs an @c NSError with the @c FIRAuthErrorCodeKeychainError code. @param keychainFunction The keychain function which was invoked and yielded an unexpected diff --git a/Firebase/Auth/Source/FIRAuthErrorUtils.m b/Firebase/Auth/Source/FIRAuthErrorUtils.m index 3748048..f4dbb94 100644 --- a/Firebase/Auth/Source/FIRAuthErrorUtils.m +++ b/Firebase/Auth/Source/FIRAuthErrorUtils.m @@ -139,8 +139,9 @@ static NSString *const kFIRAuthErrorMessageNoSuchProvider = @"User was not linke /** @var kFIRAuthErrorMessageInvalidUserToken @brief Message for @c FIRAuthErrorCodeInvalidUserToken error code. */ -static NSString *const kFIRAuthErrorMessageInvalidUserToken = @"The user's credential is no longer " - "valid. The user must sign in again."; +static NSString *const kFIRAuthErrorMessageInvalidUserToken = @"This user's credential isn't valid " + "for this project. This can happen if the user's token has been tampered with, or if the user " + "doesn’t belong to the project associated with the API key used in your request."; /** @var kFIRAuthErrorMessageNetworkError @brief Message for @c FIRAuthErrorCodeNetworkError error code. @@ -400,6 +401,12 @@ static NSString *const kFIRAuthErrorMessageWebInternalError = @"An internal erro static NSString *const kFIRAuthErrorMessageAppVerificationUserInteractionFailure = @"The app " "verification process has failed, print and inspect the error details for more information"; +/** @var kFIRAuthErrorMessageNullUser + @brief Message for @c FIRAuthErrorCodeNullUser error code. + */ +static NSString *const kFIRAuthErrorMessageNullUser = @"A null user object was provided as the " + "argument for an operation which requires a non-null user object."; + /** @var kFIRAuthErrorMessageInternalError @brief Message for @c FIRAuthErrorCodeInternalError error code. */ @@ -520,6 +527,8 @@ static NSString *FIRAuthErrorDescription(FIRAuthErrorCode code) { return kFIRAuthErrorMessageAppVerificationUserInteractionFailure; case FIRAuthErrorCodeWebNetworkRequestFailed: return kFIRAuthErrorMessageWebRequestFailed; + case FIRAuthErrorCodeNullUser: + return kFIRAuthErrorMessageNullUser; case FIRAuthErrorCodeWebInternalError: return kFIRAuthErrorMessageWebInternalError; } @@ -639,6 +648,8 @@ static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) { return @"ERROR_APP_VERIFICATION_FAILED"; case FIRAuthErrorCodeWebNetworkRequestFailed: return @"ERROR_WEB_NETWORK_REQUEST_FAILED"; + case FIRAuthErrorCodeNullUser: + return @"ERROR_NULL_USER"; case FIRAuthErrorCodeWebInternalError: return @"ERROR_WEB_INTERNAL_ERROR"; } @@ -981,6 +992,10 @@ static NSString *const FIRAuthErrorCodeString(FIRAuthErrorCode code) { return nil; } ++ (NSError *)nullUserErrorWithMessage:(nullable NSString *)message { + return [self errorWithCode:FIRAuthInternalErrorCodeNullUser message:message]; +} + + (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; return [self errorWithCode:FIRAuthInternalErrorCodeKeychainError userInfo:@{ diff --git a/Firebase/Auth/Source/FIRAuthInternalErrors.h b/Firebase/Auth/Source/FIRAuthInternalErrors.h index d2905cc..fd08022 100644 --- a/Firebase/Auth/Source/FIRAuthInternalErrors.h +++ b/Firebase/Auth/Source/FIRAuthInternalErrors.h @@ -370,6 +370,12 @@ typedef NS_ENUM(NSInteger, FIRAuthInternalErrorCode) { FIRAuthInternalErrorCodeAppNotVerified = FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeAppNotVerified, + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthInternalErrorCodeNullUser = + FIRAuthPublicErrorCodeFlag | FIRAuthErrorCodeNullUser, + /** @var FIRAuthInternalErrorCodeRPCRequestEncodingError @brief Indicates an error encoding the RPC request. @remarks This is typically due to some sort of unexpected input value. diff --git a/Firebase/Auth/Source/FIRUser.m b/Firebase/Auth/Source/FIRUser.m index fc7930f..1b10976 100644 --- a/Firebase/Auth/Source/FIRUser.m +++ b/Firebase/Auth/Source/FIRUser.m @@ -251,6 +251,7 @@ static void callInMainThreadWithAuthDataResultAndError( refreshToken:refreshToken]; FIRUser *user = [[self alloc] initWithTokenService:tokenService]; user.auth = auth; + user.requestConfiguration = auth.requestConfiguration; [user internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { if (error) { callback(nil, error); @@ -316,6 +317,8 @@ static void callInMainThreadWithAuthDataResultAndError( [aDecoder decodeObjectOfClass:[FIRSecureTokenService class] forKey:kTokenServiceCodingKey]; FIRUserMetadata *metadata = [aDecoder decodeObjectOfClass:[FIRUserMetadata class] forKey:kMetadataCodingKey]; + NSString *APIKey = + [aDecoder decodeObjectOfClass:[FIRUserMetadata class] forKey:kAPIKeyCodingKey]; if (!userID || !tokenService) { return nil; } @@ -334,6 +337,7 @@ static void callInMainThreadWithAuthDataResultAndError( _providerData = providerData; _phoneNumber = phoneNumber; _metadata = metadata ?: [[FIRUserMetadata alloc] initWithCreationDate:nil lastSignInDate:nil]; + _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey]; } return self; } @@ -349,8 +353,6 @@ static void callInMainThreadWithAuthDataResultAndError( [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey]; [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey]; [aCoder encodeObject:_metadata forKey:kMetadataCodingKey]; - // The API key is encoded even it is not used in decoding to be compatible with previous versions - // of the library. [aCoder encodeObject:_auth.requestConfiguration.APIKey forKey:kAPIKeyCodingKey]; [aCoder encodeObject:_tokenService forKey:kTokenServiceCodingKey]; } diff --git a/Firebase/Auth/Source/FIRUser_Internal.h b/Firebase/Auth/Source/FIRUser_Internal.h index 9a069bb..4f89c00 100644 --- a/Firebase/Auth/Source/FIRUser_Internal.h +++ b/Firebase/Auth/Source/FIRUser_Internal.h @@ -17,6 +17,7 @@ #import "FIRUser.h" @class FIRAuth; +@class FIRAuthRequestConfiguration; NS_ASSUME_NONNULL_BEGIN @@ -42,6 +43,11 @@ typedef void(^FIRRetrieveUserCallback)(FIRUser *_Nullable user, NSError *_Nullab */ @property(nonatomic, weak) FIRAuth *auth; +/** @property auth + @brief A strong reference to a requestConfiguration instance associated with this user instance. + */ +@property(nonatomic, strong) FIRAuthRequestConfiguration *requestConfiguration; + /** @var accessTokenExpirationDate @brief The expiration date of the cached access token. */ diff --git a/Firebase/Auth/Source/Public/FIRAuth.h b/Firebase/Auth/Source/Public/FIRAuth.h index aefba57..7d5ea42 100644 --- a/Firebase/Auth/Source/Public/FIRAuth.h +++ b/Firebase/Auth/Source/Public/FIRAuth.h @@ -32,6 +32,11 @@ NS_ASSUME_NONNULL_BEGIN +/** @typedef FIRUserUpdateCallback + @brief The type of block invoked when a request to update a current user is completed. + */ +typedef void (^FIRUserUpdateCallback)(NSError *_Nullable error) NS_SWIFT_NAME(UserUpdateCallback); + /** @typedef FIRAuthStateDidChangeListenerHandle @brief The type of handle returned by `FIRAuth.addAuthStateDidChangeListener:`. */ @@ -297,6 +302,14 @@ NS_SWIFT_NAME(Auth) */ - (instancetype)init NS_UNAVAILABLE; +/** @fn updateCurrentUser:completion: + @brief Sets the currentUser on the calling Auth instance to the provided user object. + @param user The user object to be set as the current user of the calling Auth instance. + @param completion Optionally; a block invoked after the user of the calling Auth instance has + been updated or an error was encountered. + */ +- (void)updateCurrentUser:(FIRUser *)user completion:(nullable FIRUserUpdateCallback)completion; + /** @fn fetchProvidersForEmail:completion: @brief Fetches the list of IdPs that can be used for signing in with the provided email address. Useful for an "identifier-first" sign-in flow. diff --git a/Firebase/Auth/Source/Public/FIRAuthErrors.h b/Firebase/Auth/Source/Public/FIRAuthErrors.h index b8e5fb6..4a1a6f1 100644 --- a/Firebase/Auth/Source/Public/FIRAuthErrors.h +++ b/Firebase/Auth/Source/Public/FIRAuthErrors.h @@ -299,6 +299,11 @@ typedef NS_ENUM(NSInteger, FIRAuthErrorCode) { */ FIRAuthErrorCodeWebInternalError = 17062, + /** Indicates that a non-null user was expected as an argmument to the operation but a null + user was provided. + */ + FIRAuthErrorCodeNullUser = 17067, + /** Indicates an error occurred while attempting to access the keychain. */ FIRAuthErrorCodeKeychainError = 17995, -- cgit v1.2.3