123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452 |
-
-
- #import "FIRUser_Internal.h"
-
- #import <FirebaseCore/FIRLogger.h>
-
- #import "FIRAdditionalUserInfo_Internal.h"
- #import "FIRAuth.h"
- #import "FIRAuthCredential_Internal.h"
- #import "FIRAuthDataResult_Internal.h"
- #import "FIRAuthErrorUtils.h"
- #import "FIRAuthGlobalWorkQueue.h"
- #import "FIRAuthSerialTaskQueue.h"
- #import "FIRAuthOperationType.h"
- #import "FIRAuth_Internal.h"
- #import "FIRAuthBackend.h"
- #import "FIRAuthRequestConfiguration.h"
- #import "FIRAuthTokenResult_Internal.h"
- #import "FIRDeleteAccountRequest.h"
- #import "FIRDeleteAccountResponse.h"
- #import "FIREmailAuthProvider.h"
- #import "FIREmailPasswordAuthCredential.h"
- #import "FIRGameCenterAuthCredential.h"
- #import "FIRGetAccountInfoRequest.h"
- #import "FIRGetAccountInfoResponse.h"
- #import "FIRGetOOBConfirmationCodeRequest.h"
- #import "FIRGetOOBConfirmationCodeResponse.h"
- #import "FIRSecureTokenService.h"
- #import "FIRSetAccountInfoRequest.h"
- #import "FIRSetAccountInfoResponse.h"
- #import "FIRSignInWithGameCenterRequest.h"
- #import "FIRSignInWithGameCenterResponse.h"
- #import "FIRUserInfoImpl.h"
- #import "FIRUserMetadata_Internal.h"
- #import "FIRVerifyAssertionRequest.h"
- #import "FIRVerifyAssertionResponse.h"
- #import "FIRVerifyCustomTokenRequest.h"
- #import "FIRVerifyCustomTokenResponse.h"
- #import "FIRVerifyPasswordRequest.h"
- #import "FIRVerifyPasswordResponse.h"
- #import "FIRVerifyPhoneNumberRequest.h"
- #import "FIRVerifyPhoneNumberResponse.h"
-
- #if TARGET_OS_IOS
- #import "FIRPhoneAuthProvider.h"
- #import "AuthProviders/Phone/FIRPhoneAuthCredential_Internal.h"
- #endif
-
- NS_ASSUME_NONNULL_BEGIN
-
-
- static NSString *const kUserIDCodingKey = @"userID";
-
-
- static NSString *const kHasEmailPasswordCredentialCodingKey = @"hasEmailPassword";
-
-
- static NSString *const kAnonymousCodingKey = @"anonymous";
-
-
- static NSString *const kEmailCodingKey = @"email";
-
-
- static NSString *const kPhoneNumberCodingKey = @"phoneNumber";
-
-
- static NSString *const kEmailVerifiedCodingKey = @"emailVerified";
-
-
- static NSString *const kDisplayNameCodingKey = @"displayName";
-
-
- static NSString *const kPhotoURLCodingKey = @"photoURL";
-
-
- static NSString *const kProviderDataKey = @"providerData";
-
-
- static NSString *const kAPIKeyCodingKey = @"APIKey";
-
-
- static NSString *const kTokenServiceCodingKey = @"tokenService";
-
-
- static NSString *const kMetadataCodingKey = @"metadata";
-
-
- static NSString *const kMissingUsersErrorMessage = @"users";
-
-
- typedef void (^CallbackWithError)(NSError *_Nullable);
-
-
- typedef void (^CallbackWithUserAndError)(FIRUser *_Nullable, NSError *_Nullable);
-
-
- typedef void (^CallbackWithAuthDataResultAndError)(FIRAuthDataResult *_Nullable,
- NSError *_Nullable);
-
-
- static NSString *const kMissingPasswordReason = @"Missing Password";
-
-
- static void callInMainThreadWithError(_Nullable CallbackWithError callback,
- NSError *_Nullable error) {
- if (callback) {
- dispatch_async(dispatch_get_main_queue(), ^{
- callback(error);
- });
- }
- }
-
-
- static void callInMainThreadWithUserAndError(_Nullable CallbackWithUserAndError callback,
- FIRUser *_Nonnull user,
- NSError *_Nullable error) {
- if (callback) {
- dispatch_async(dispatch_get_main_queue(), ^{
- callback(error ? nil : user, error);
- });
- }
- }
-
-
- static void callInMainThreadWithAuthDataResultAndError(
- _Nullable CallbackWithAuthDataResultAndError callback,
- FIRAuthDataResult *_Nullable result,
- NSError *_Nullable error) {
- if (callback) {
- dispatch_async(dispatch_get_main_queue(), ^{
- callback(result, error);
- });
- }
- }
-
- @interface FIRUserProfileChangeRequest ()
-
-
- - (nullable instancetype)initWithUser:(FIRUser *)user NS_DESIGNATED_INITIALIZER;
-
- @end
-
- @interface FIRUser ()
-
-
- @property(nonatomic, readwrite) BOOL anonymous;
-
- @end
-
- @implementation FIRUser {
-
-
- BOOL _hasEmailPasswordCredential;
-
-
-
- NSDictionary<NSString *, FIRUserInfoImpl *> *_providerData;
-
-
-
- FIRAuthSerialTaskQueue *_taskQueue;
-
-
-
- FIRSecureTokenService *_tokenService;
- }
-
- #pragma mark - Properties
-
-
- @synthesize uid = _userID;
- @synthesize displayName = _displayName;
- @synthesize photoURL = _photoURL;
- @synthesize email = _email;
- @synthesize phoneNumber = _phoneNumber;
-
- #pragma mark -
-
- + (void)retrieveUserWithAuth:(FIRAuth *)auth
- accessToken:(nullable NSString *)accessToken
- accessTokenExpirationDate:(nullable NSDate *)accessTokenExpirationDate
- refreshToken:(nullable NSString *)refreshToken
- anonymous:(BOOL)anonymous
- callback:(FIRRetrieveUserCallback)callback {
- FIRSecureTokenService *tokenService =
- [[FIRSecureTokenService alloc] initWithRequestConfiguration:auth.requestConfiguration
- accessToken:accessToken
- accessTokenExpirationDate:accessTokenExpirationDate
- 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);
- return;
- }
- FIRGetAccountInfoRequest *getAccountInfoRequest =
- [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
- requestConfiguration:auth.requestConfiguration];
- [FIRAuthBackend getAccountInfo:getAccountInfoRequest
- callback:^(FIRGetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
-
- callback(nil, error);
- return;
- }
- user.anonymous = anonymous;
- [user updateWithGetAccountInfoResponse:response];
- callback(user, nil);
- }];
- }];
- }
-
- - (instancetype)initWithTokenService:(FIRSecureTokenService *)tokenService {
- self = [super init];
- if (self) {
- _providerData = @{ };
- _taskQueue = [[FIRAuthSerialTaskQueue alloc] init];
- _tokenService = tokenService;
- }
- return self;
- }
-
- #pragma mark - NSSecureCoding
-
- + (BOOL)supportsSecureCoding {
- return YES;
- }
-
- - (nullable instancetype)initWithCoder:(NSCoder *)aDecoder {
- NSString *userID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kUserIDCodingKey];
- BOOL hasAnonymousKey = [aDecoder containsValueForKey:kAnonymousCodingKey];
- BOOL anonymous = [aDecoder decodeBoolForKey:kAnonymousCodingKey];
- BOOL hasEmailPasswordCredential =
- [aDecoder decodeBoolForKey:kHasEmailPasswordCredentialCodingKey];
- NSString *displayName =
- [aDecoder decodeObjectOfClass:[NSString class] forKey:kDisplayNameCodingKey];
- NSURL *photoURL =
- [aDecoder decodeObjectOfClass:[NSURL class] forKey:kPhotoURLCodingKey];
- NSString *email =
- [aDecoder decodeObjectOfClass:[NSString class] forKey:kEmailCodingKey];
- NSString *phoneNumber =
- [aDecoder decodeObjectOfClass:[NSString class] forKey:kPhoneNumberCodingKey];
- BOOL emailVerified = [aDecoder decodeBoolForKey:kEmailVerifiedCodingKey];
- NSSet *providerDataClasses = [NSSet setWithArray:@[
- [NSDictionary class],
- [NSString class],
- [FIRUserInfoImpl class]
- ]];
- NSDictionary<NSString *, FIRUserInfoImpl *> *providerData =
- [aDecoder decodeObjectOfClasses:providerDataClasses forKey:kProviderDataKey];
- FIRSecureTokenService *tokenService =
- [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;
- }
- self = [self initWithTokenService:tokenService];
- if (self) {
- _userID = userID;
-
-
-
- _anonymous = hasAnonymousKey ? anonymous : (!hasEmailPasswordCredential && !providerData.count);
- _hasEmailPasswordCredential = hasEmailPasswordCredential;
- _email = email;
- _emailVerified = emailVerified;
- _displayName = displayName;
- _photoURL = photoURL;
- _providerData = providerData;
- _phoneNumber = phoneNumber;
- _metadata = metadata ?: [[FIRUserMetadata alloc] initWithCreationDate:nil lastSignInDate:nil];
- _requestConfiguration = [[FIRAuthRequestConfiguration alloc] initWithAPIKey:APIKey];
- }
- return self;
- }
-
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:_userID forKey:kUserIDCodingKey];
- [aCoder encodeBool:self.anonymous forKey:kAnonymousCodingKey];
- [aCoder encodeBool:_hasEmailPasswordCredential forKey:kHasEmailPasswordCredentialCodingKey];
- [aCoder encodeObject:_providerData forKey:kProviderDataKey];
- [aCoder encodeObject:_email forKey:kEmailCodingKey];
- [aCoder encodeObject:_phoneNumber forKey:kPhoneNumberCodingKey];
- [aCoder encodeBool:_emailVerified forKey:kEmailVerifiedCodingKey];
- [aCoder encodeObject:_photoURL forKey:kPhotoURLCodingKey];
- [aCoder encodeObject:_displayName forKey:kDisplayNameCodingKey];
- [aCoder encodeObject:_metadata forKey:kMetadataCodingKey];
- [aCoder encodeObject:_auth.requestConfiguration.APIKey forKey:kAPIKeyCodingKey];
- [aCoder encodeObject:_tokenService forKey:kTokenServiceCodingKey];
- }
-
- #pragma mark -
-
- - (void)setAuth:(nullable FIRAuth *)auth {
- _auth = auth;
- _tokenService.requestConfiguration = auth.requestConfiguration;
- }
-
- - (NSString *)providerID {
- return @"Firebase";
- }
-
- - (NSArray<id<FIRUserInfo>> *)providerData {
- return _providerData.allValues;
- }
-
-
- - (void)getAccountInfoRefreshingCache:(void(^)(FIRGetAccountInfoResponseUser *_Nullable user,
- NSError *_Nullable error))callback {
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) {
- if (error) {
- callback(nil, error);
- return;
- }
- FIRGetAccountInfoRequest *getAccountInfoRequest =
- [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
- requestConfiguration:self->_auth.requestConfiguration];
- [FIRAuthBackend getAccountInfo:getAccountInfoRequest
- callback:^(FIRGetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- callback(nil, error);
- return;
- }
- [self updateWithGetAccountInfoResponse:response];
- if (![self updateKeychain:&error]) {
- callback(nil, error);
- return;
- }
- callback(response.users.firstObject, nil);
- }];
- }];
- }
-
- - (void)updateWithGetAccountInfoResponse:(FIRGetAccountInfoResponse *)response {
- FIRGetAccountInfoResponseUser *user = response.users.firstObject;
- _userID = user.localID;
- _email = user.email;
- _emailVerified = user.emailVerified;
- _displayName = user.displayName;
- _photoURL = user.photoURL;
- _phoneNumber = user.phoneNumber;
- _hasEmailPasswordCredential = user.passwordHash.length > 0;
- _metadata =
- [[FIRUserMetadata alloc]initWithCreationDate:user.creationDate
- lastSignInDate:user.lastLoginDate];
- NSMutableDictionary<NSString *, FIRUserInfoImpl *> *providerData =
- [NSMutableDictionary dictionary];
- for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in user.providerUserInfo) {
- FIRUserInfoImpl *userInfo =
- [FIRUserInfoImpl userInfoWithGetAccountInfoResponseProviderUserInfo:providerUserInfo];
- if (userInfo) {
- providerData[providerUserInfo.providerID] = userInfo;
- }
- }
- _providerData = [providerData copy];
- }
-
-
- - (void)executeUserUpdateWithChanges:(void(^)(FIRGetAccountInfoResponseUser *,
- FIRSetAccountInfoRequest *))changeBlock
- callback:(nonnull FIRUserProfileChangeCallback)callback {
- [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
- [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
- NSError *_Nullable error) {
- if (error) {
- complete();
- callback(error);
- return;
- }
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- complete();
- callback(error);
- return;
- }
- FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration;
-
- FIRSetAccountInfoRequest *setAccountInfoRequest =
- [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:configuration];
- setAccountInfoRequest.accessToken = accessToken;
- changeBlock(user, setAccountInfoRequest);
-
- [FIRAuthBackend setAccountInfo:setAccountInfoRequest
- callback:^(FIRSetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- complete();
- callback(error);
- return;
- }
- if (response.IDToken && response.refreshToken) {
- FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc]
- initWithRequestConfiguration:configuration
- accessToken:response.IDToken
- accessTokenExpirationDate:response.approximateExpirationDate
- refreshToken:response.refreshToken];
- [self setTokenService:tokenService callback:^(NSError *_Nullable error) {
- complete();
- callback(error);
- }];
- return;
- }
- complete();
- callback(nil);
- }];
- }];
- }];
- }];
- }
-
-
- - (BOOL)updateKeychain:(NSError *_Nullable *_Nullable)error {
- return [_auth updateKeychainWithUser:self error:error];
- }
-
-
- - (void)setTokenService:(FIRSecureTokenService *)tokenService
- callback:(nonnull CallbackWithError)callback {
- [tokenService fetchAccessTokenForcingRefresh:NO
- callback:^(NSString *_Nullable token,
- NSError *_Nullable error,
- BOOL tokenUpdated) {
- if (error) {
- callback(error);
- return;
- }
- self->_tokenService = tokenService;
- if (![self updateKeychain:&error]) {
- callback(error);
- return;
- }
- callback(nil);
- }];
- }
-
- #pragma mark -
-
-
- - (void)updateEmail:(nullable NSString *)email
- password:(nullable NSString *)password
- callback:(nonnull FIRUserProfileChangeCallback)callback {
- if (password && ![password length]) {
- callback([FIRAuthErrorUtils weakPasswordErrorWithServerResponseReason:kMissingPasswordReason]);
- return;
- }
- BOOL hadEmailPasswordCredential = _hasEmailPasswordCredential;
- [self executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user,
- FIRSetAccountInfoRequest *request) {
- if (email) {
- request.email = email;
- }
- if (password) {
- request.password = password;
- }
- }
- callback:^(NSError *error) {
- if (error) {
- callback(error);
- return;
- }
- if (email) {
- self->_email = [email copy];
- }
- if (self->_email) {
- if (!hadEmailPasswordCredential) {
-
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- callback(error);
- return;
- }
- FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration;
- FIRGetAccountInfoRequest *getAccountInfoRequest =
- [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
- requestConfiguration:requestConfiguration];
- [FIRAuthBackend getAccountInfo:getAccountInfoRequest
- callback:^(FIRGetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- callback(error);
- return;
- }
- for (FIRGetAccountInfoResponseUser *userAccountInfo in response.users) {
-
-
- if (userAccountInfo.providerUserInfo.count > 0) {
- self.anonymous = NO;
- }
- for (FIRGetAccountInfoResponseProviderUserInfo *providerUserInfo in
- userAccountInfo.providerUserInfo) {
- if ([providerUserInfo.providerID isEqualToString:FIREmailAuthProviderID]) {
- self->_hasEmailPasswordCredential = YES;
- break;
- }
- }
- }
- [self updateWithGetAccountInfoResponse:response];
- if (![self updateKeychain:&error]) {
- callback(error);
- return;
- }
- callback(nil);
- }];
- }];
- return;
- }
- }
- if (![self updateKeychain:&error]) {
- callback(error);
- return;
- }
- callback(nil);
- }];
- }
-
- - (void)updateEmail:(NSString *)email completion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self updateEmail:email password:nil callback:^(NSError *_Nullable error) {
- callInMainThreadWithError(completion, error);
- }];
- });
- }
-
- - (void)updatePassword:(NSString *)password
- completion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self updateEmail:nil password:password callback:^(NSError *_Nullable error){
- callInMainThreadWithError(completion, error);
- }];
- });
- }
-
- #if TARGET_OS_IOS
-
- - (void)internalUpdateOrLinkPhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential
- isLinkOperation:(BOOL)isLinkOperation
- completion:(FIRUserProfileChangeCallback)completion {
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- completion(error);
- return;
- }
- FIRAuthOperationType operation =
- isLinkOperation ? FIRAuthOperationTypeLink : FIRAuthOperationTypeUpdate;
- FIRVerifyPhoneNumberRequest *request = [[FIRVerifyPhoneNumberRequest alloc]
- initWithVerificationID:phoneAuthCredential.verificationID
- verificationCode:phoneAuthCredential.verificationCode
- operation:operation
- requestConfiguration:self->_auth.requestConfiguration];
- request.accessToken = accessToken;
- [FIRAuthBackend verifyPhoneNumber:request
- callback:^(FIRVerifyPhoneNumberResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- completion(error);
- return;
- }
-
- [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- completion(error);
- return;
- }
- self.anonymous = NO;
- if (![self updateKeychain:&error]) {
- completion(error);
- return;
- }
- completion(nil);
- }];
- }];
- }];
- }
-
- - (void)updatePhoneNumberCredential:(FIRPhoneAuthCredential *)phoneAuthCredential
- completion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential
- isLinkOperation:NO
- completion:^(NSError *_Nullable error) {
- callInMainThreadWithError(completion, error);
- }];
- });
- }
- #endif
-
- - (FIRUserProfileChangeRequest *)profileChangeRequest {
- __block FIRUserProfileChangeRequest *result;
- dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- result = [[FIRUserProfileChangeRequest alloc] initWithUser:self];
- });
- return result;
- }
-
- - (void)setDisplayName:(NSString *)displayName {
- _displayName = [displayName copy];
- }
-
- - (void)setPhotoURL:(NSURL *)photoURL {
- _photoURL = [photoURL copy];
- }
-
- - (NSString *)rawAccessToken {
- return _tokenService.rawAccessToken;
- }
-
- - (NSDate *)accessTokenExpirationDate {
- return _tokenService.accessTokenExpirationDate;
- }
-
- #pragma mark -
-
- - (void)reloadWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self getAccountInfoRefreshingCache:^(FIRGetAccountInfoResponseUser *_Nullable user,
- NSError *_Nullable error) {
- callInMainThreadWithError(completion, error);
- }];
- });
- }
-
- #pragma mark -
-
- - (void)reauthenticateWithCredential:(FIRAuthCredential *)credential
- completion:(nullable FIRUserProfileChangeCallback)completion {
- FIRAuthDataResultCallback callback = ^(FIRAuthDataResult *_Nullable authResult,
- NSError *_Nullable error) {
- completion(error);
- };
- [self reauthenticateAndRetrieveDataWithCredential:credential completion:callback];
- }
-
- - (void)
- reauthenticateAndRetrieveDataWithCredential:(FIRAuthCredential *) credential
- completion:(nullable FIRAuthDataResultCallback) completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self->_auth internalSignInAndRetrieveDataWithCredential:credential
- isReauthentication:YES
- callback:^(FIRAuthDataResult *_Nullable
- authResult,
- NSError *_Nullable error) {
- if (error) {
-
-
- if (error.code == FIRAuthErrorCodeUserNotFound) {
- error = [FIRAuthErrorUtils userMismatchError];
- }
- callInMainThreadWithAuthDataResultAndError(completion, authResult, error);
- return;
- }
- if (![authResult.user.uid isEqual:[self->_auth getUserID]]) {
- callInMainThreadWithAuthDataResultAndError(completion, authResult,
- [FIRAuthErrorUtils userMismatchError]);
- return;
- }
-
- [self setTokenService:authResult.user->_tokenService callback:^(NSError *_Nullable error) {
- callInMainThreadWithAuthDataResultAndError(completion, authResult, error);
- }];
- }];
- });
- }
-
- - (nullable NSString *)refreshToken {
- __block NSString *result;
- dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- result = self->_tokenService.refreshToken;
- });
- return result;
- }
-
- - (void)getIDTokenWithCompletion:(nullable FIRAuthTokenCallback)completion {
-
-
- [self getIDTokenForcingRefresh:NO completion:completion];
- }
-
- - (void)getIDTokenForcingRefresh:(BOOL)forceRefresh
- completion:(nullable FIRAuthTokenCallback)completion {
- [self getIDTokenResultForcingRefresh:forceRefresh
- completion:^(FIRAuthTokenResult *_Nullable tokenResult,
- NSError *_Nullable error) {
-
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion(tokenResult.token, error);
- });
- }
- }];
- }
-
- - (void)getIDTokenResultWithCompletion:(nullable FIRAuthTokenResultCallback)completion {
- [self getIDTokenResultForcingRefresh:NO
- completion:^(FIRAuthTokenResult *_Nullable tokenResult,
- NSError *_Nullable error) {
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion(tokenResult, error);
- });
- }
- }];
- }
-
- - (void)getIDTokenResultForcingRefresh:(BOOL)forceRefresh
- completion:(nullable FIRAuthTokenResultCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self internalGetTokenForcingRefresh:forceRefresh
- callback:^(NSString *_Nullable token, NSError *_Nullable error) {
- FIRAuthTokenResult *tokenResult;
- if (token) {
- tokenResult = [self parseIDToken:token error:&error];
- }
- if (completion) {
- dispatch_async(dispatch_get_main_queue(), ^{
- completion(tokenResult, error);
- });
- }
- }];
- });
- }
-
-
- - (nullable FIRAuthTokenResult *)parseIDToken:(NSString *)token error:(NSError **)error {
-
-
- if (error) {
- *error = nil;
- }
- NSArray *tokenStringArray = [token componentsSeparatedByString:@"."];
-
-
- if (tokenStringArray.count != 3) {
- if (error) {
- *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil];
- }
- return nil;
- }
-
-
- NSString *idToken = tokenStringArray[1];
-
-
-
- NSMutableString *tokenPayload =
- [[idToken stringByReplacingOccurrencesOfString:@"_" withString:@"/"] mutableCopy];
-
-
- [tokenPayload replaceOccurrencesOfString:@"-"
- withString:@"+"
- options:kNilOptions
- range:NSMakeRange(0, tokenPayload.length)];
-
-
- while ((tokenPayload.length % 4) != 0) {
- [tokenPayload appendFormat:@"="];
- }
- NSData *decodedTokenPayloadData =
- [[NSData alloc] initWithBase64EncodedString:tokenPayload
- options:NSDataBase64DecodingIgnoreUnknownCharacters];
- if (!decodedTokenPayloadData) {
- if (error) {
- *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil];
- }
- return nil;
- }
- NSError *jsonError = nil;
- NSJSONReadingOptions options = NSJSONReadingMutableContainers|NSJSONReadingAllowFragments;
- NSDictionary *tokenPayloadDictionary =
- [NSJSONSerialization JSONObjectWithData:decodedTokenPayloadData
- options:options
- error:&jsonError];
- if (jsonError != nil) {
- if (error) {
- *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:jsonError];
- }
- return nil;
- }
-
- if (!tokenPayloadDictionary) {
- if (error) {
- *error = [FIRAuthErrorUtils malformedJWTErrorWithToken:token underlyingError:nil];
- }
- return nil;
- }
-
-
-
- NSDate *expDate =
- [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"exp"] doubleValue]];
- NSDate *authDate =
- [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"auth_time"] doubleValue]];
- NSDate *issuedDate =
- [NSDate dateWithTimeIntervalSince1970:[tokenPayloadDictionary[@"iat"] doubleValue]];
- FIRAuthTokenResult *result =
- [[FIRAuthTokenResult alloc] initWithToken:token
- expirationDate:expDate
- authDate:authDate
- issuedAtDate:issuedDate
- signInProvider:tokenPayloadDictionary[@"sign_in_provider"]
- claims:tokenPayloadDictionary];
- return result;
- }
-
-
- - (void)internalGetTokenWithCallback:(nonnull FIRAuthTokenCallback)callback {
- [self internalGetTokenForcingRefresh:NO callback:callback];
- }
-
- - (void)internalGetTokenForcingRefresh:(BOOL)forceRefresh
- callback:(nonnull FIRAuthTokenCallback)callback {
- [_tokenService fetchAccessTokenForcingRefresh:forceRefresh
- callback:^(NSString *_Nullable token,
- NSError *_Nullable error,
- BOOL tokenUpdated) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- callback(nil, error);
- return;
- }
- if (tokenUpdated) {
- if (![self updateKeychain:&error]) {
- callback(nil, error);
- return;
- }
- }
- callback(token, nil);
- }];
- }
-
- - (void)linkWithCredential:(FIRAuthCredential *)credential
- completion:(nullable FIRAuthResultCallback)completion {
- FIRAuthDataResultCallback callback = ^(FIRAuthDataResult *_Nullable authResult,
- NSError *_Nullable error) {
- completion(authResult.user, error);
- };
- [self linkAndRetrieveDataWithCredential:credential completion:callback];
- }
-
- - (void)linkAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
- completion:(nullable FIRAuthDataResultCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- if (self->_providerData[credential.provider]) {
- callInMainThreadWithAuthDataResultAndError(completion,
- nil,
- [FIRAuthErrorUtils providerAlreadyLinkedError]);
- return;
- }
- FIRAuthDataResult *result =
- [[FIRAuthDataResult alloc] initWithUser:self additionalUserInfo:nil];
- if ([credential isKindOfClass:[FIREmailPasswordAuthCredential class]]) {
- if (self->_hasEmailPasswordCredential) {
- callInMainThreadWithAuthDataResultAndError(completion,
- nil,
- [FIRAuthErrorUtils providerAlreadyLinkedError]);
- return;
- }
- FIREmailPasswordAuthCredential *emailPasswordCredential =
- (FIREmailPasswordAuthCredential *)credential;
- [self updateEmail:emailPasswordCredential.email
- password:emailPasswordCredential.password
- callback:^(NSError *error) {
- if (error) {
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- } else {
- callInMainThreadWithAuthDataResultAndError(completion, result, nil);
- }
- }];
- return;
- }
-
- if ([credential isKindOfClass:[FIRGameCenterAuthCredential class]]) {
- FIRGameCenterAuthCredential *gameCenterCredential = (FIRGameCenterAuthCredential *)credential;
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration;
- FIRSignInWithGameCenterRequest *gameCenterRequest =
- [[FIRSignInWithGameCenterRequest alloc] initWithPlayerID:gameCenterCredential.playerID
- publicKeyURL:gameCenterCredential.publicKeyURL
- signature:gameCenterCredential.signature
- salt:gameCenterCredential.salt
- timestamp:gameCenterCredential.timestamp
- displayName:gameCenterCredential.displayName
- requestConfiguration:requestConfiguration];
- gameCenterRequest.accessToken = accessToken;
-
- [FIRAuthBackend signInWithGameCenter:gameCenterRequest
- callback:^(FIRSignInWithGameCenterResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error){
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- } else {
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- return;
- }
-
- FIRGetAccountInfoRequest *getAccountInfoRequest =
- [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
- requestConfiguration:requestConfiguration];
- [FIRAuthBackend getAccountInfo:getAccountInfoRequest
- callback:^(FIRGetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- return;
- }
- self.anonymous = NO;
- [self updateWithGetAccountInfoResponse:response];
- if (![self updateKeychain:&error]) {
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- return;
- }
- callInMainThreadWithAuthDataResultAndError(completion, result, nil);
- }];
- }];
- }
- }];
- }];
- return;
- }
-
- #if TARGET_OS_IOS
- if ([credential isKindOfClass:[FIRPhoneAuthCredential class]]) {
- FIRPhoneAuthCredential *phoneAuthCredential = (FIRPhoneAuthCredential *)credential;
- [self internalUpdateOrLinkPhoneNumberCredential:phoneAuthCredential
- isLinkOperation:YES
- completion:^(NSError *_Nullable error) {
- if (error){
- callInMainThreadWithAuthDataResultAndError(completion, nil, error);
- } else {
- callInMainThreadWithAuthDataResultAndError(completion, result, nil);
- }
- }];
- return;
- }
- #endif
-
- [self->_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
- CallbackWithAuthDataResultAndError completeWithError =
- ^(FIRAuthDataResult *result, NSError *error) {
- complete();
- callInMainThreadWithAuthDataResultAndError(completion, result, error);
- };
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- completeWithError(nil, error);
- return;
- }
- FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration;
- FIRVerifyAssertionRequest *request =
- [[FIRVerifyAssertionRequest alloc] initWithProviderID:credential.provider
- requestConfiguration:requestConfiguration];
- [credential prepareVerifyAssertionRequest:request];
- request.accessToken = accessToken;
- [FIRAuthBackend verifyAssertion:request
- callback:^(FIRVerifyAssertionResponse *response, NSError *error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- completeWithError(nil, error);
- return;
- }
- FIRAdditionalUserInfo *additionalUserInfo =
- [FIRAdditionalUserInfo userInfoWithVerifyAssertionResponse:response];
- FIRAuthDataResult *result =
- [[FIRAuthDataResult alloc] initWithUser:self additionalUserInfo:additionalUserInfo];
-
- self->_tokenService = [[FIRSecureTokenService alloc]
- initWithRequestConfiguration:requestConfiguration
- accessToken:response.IDToken
- accessTokenExpirationDate:response.approximateExpirationDate
- refreshToken:response.refreshToken];
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- completeWithError(nil, error);
- return;
- }
- FIRGetAccountInfoRequest *getAccountInfoRequest =
- [[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
- requestConfiguration:requestConfiguration];
- [FIRAuthBackend getAccountInfo:getAccountInfoRequest
- callback:^(FIRGetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- completeWithError(nil, error);
- return;
- }
- self.anonymous = NO;
- [self updateWithGetAccountInfoResponse:response];
- if (![self updateKeychain:&error]) {
- completeWithError(nil, error);
- return;
- }
- completeWithError(result, nil);
- }];
- }];
- }];
- }];
- }];
- });
- }
-
- - (void)unlinkFromProvider:(NSString *)provider
- completion:(nullable FIRAuthResultCallback)completion {
- [_taskQueue enqueueTask:^(FIRAuthSerialTaskCompletionBlock _Nonnull complete) {
- CallbackWithError completeAndCallbackWithError = ^(NSError *error) {
- complete();
- callInMainThreadWithUserAndError(completion, self, error);
- };
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- completeAndCallbackWithError(error);
- return;
- }
- FIRAuthRequestConfiguration *requestConfiguration = self->_auth.requestConfiguration;
- FIRSetAccountInfoRequest *setAccountInfoRequest =
- [[FIRSetAccountInfoRequest alloc] initWithRequestConfiguration:requestConfiguration];
- setAccountInfoRequest.accessToken = accessToken;
-
- if ([provider isEqualToString:FIREmailAuthProviderID]) {
- if (!self->_hasEmailPasswordCredential) {
- completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]);
- return;
- }
- setAccountInfoRequest.deleteAttributes = @[ FIRSetAccountInfoUserAttributePassword ];
- } else {
- if (!self->_providerData[provider]) {
- completeAndCallbackWithError([FIRAuthErrorUtils noSuchProviderError]);
- return;
- }
- setAccountInfoRequest.deleteProviders = @[ provider ];
- }
-
- [FIRAuthBackend setAccountInfo:setAccountInfoRequest
- callback:^(FIRSetAccountInfoResponse *_Nullable response,
- NSError *_Nullable error) {
- if (error) {
- [self signOutIfTokenIsInvalidWithError:error];
- completeAndCallbackWithError(error);
- return;
- }
-
-
-
- NSMutableDictionary *mutableProviderData = [self->_providerData mutableCopy];
- [mutableProviderData removeObjectForKey:provider];
- self->_providerData = [mutableProviderData copy];
-
- if ([provider isEqualToString:FIREmailAuthProviderID]) {
- self->_hasEmailPasswordCredential = NO;
- }
- #if TARGET_OS_IOS
-
-
- if ([provider isEqualToString:FIRPhoneAuthProviderID]) {
- self->_phoneNumber = nil;
- }
- #endif
-
- if (response.IDToken && response.refreshToken) {
- FIRSecureTokenService *tokenService = [[FIRSecureTokenService alloc]
- initWithRequestConfiguration:requestConfiguration
- accessToken:response.IDToken
- accessTokenExpirationDate:response.approximateExpirationDate
- refreshToken:response.refreshToken];
- [self setTokenService:tokenService callback:^(NSError *_Nullable error) {
- completeAndCallbackWithError(error);
- }];
- return;
- }
- if (![self updateKeychain:&error]) {
- completeAndCallbackWithError(error);
- return;
- }
- completeAndCallbackWithError(nil);
- }];
- }];
- }];
- }
-
- - (void)sendEmailVerificationWithCompletion:(nullable FIRSendEmailVerificationCallback)completion {
- [self sendEmailVerificationWithNullableActionCodeSettings:nil completion:completion];
- }
-
- - (void)sendEmailVerificationWithActionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings
- completion:(nullable FIRSendEmailVerificationCallback)
- completion {
- [self sendEmailVerificationWithNullableActionCodeSettings:actionCodeSettings
- completion:completion];
- }
-
-
- - (void)sendEmailVerificationWithNullableActionCodeSettings:(nullable FIRActionCodeSettings *)
- actionCodeSettings
- completion:
- (nullable FIRSendEmailVerificationCallback)
- completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- callInMainThreadWithError(completion, error);
- return;
- }
- FIRAuthRequestConfiguration *configuration = self->_auth.requestConfiguration;
- FIRGetOOBConfirmationCodeRequest *request =
- [FIRGetOOBConfirmationCodeRequest verifyEmailRequestWithAccessToken:accessToken
- actionCodeSettings:actionCodeSettings
- requestConfiguration:configuration];
- [FIRAuthBackend getOOBConfirmationCode:request
- callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable
- response,
- NSError *_Nullable error) {
- [self signOutIfTokenIsInvalidWithError:error];
- callInMainThreadWithError(completion, error);
- }];
- }];
- });
- }
-
- - (void)deleteWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_async(FIRAuthGlobalWorkQueue(), ^{
- [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
- NSError *_Nullable error) {
- if (error) {
- callInMainThreadWithError(completion, error);
- return;
- }
- FIRDeleteAccountRequest *deleteUserRequest =
- [[FIRDeleteAccountRequest alloc] initWitLocalID:self->_userID
- accessToken:accessToken
- requestConfiguration:self->_auth.requestConfiguration];
- [FIRAuthBackend deleteAccount:deleteUserRequest callback:^(NSError *_Nullable error) {
- if (error) {
- callInMainThreadWithError(completion, error);
- return;
- }
- if (![self->_auth signOutByForceWithUserID:self->_userID error:&error]) {
- callInMainThreadWithError(completion, error);
- return;
- }
- callInMainThreadWithError(completion, error);
- }];
- }];
- });
- }
-
-
- - (void)signOutIfTokenIsInvalidWithError:(nullable NSError *)error {
- NSInteger errorCode = error.code;
- if (errorCode == FIRAuthErrorCodeUserNotFound ||
- errorCode == FIRAuthErrorCodeUserDisabled ||
- errorCode == FIRAuthErrorCodeInvalidUserToken ||
- errorCode == FIRAuthErrorCodeUserTokenExpired) {
- FIRLogNotice(kFIRLoggerAuth, @"I-AUT000016",
- @"Invalid user token detected, user is automatically signed out.");
- [_auth signOutByForceWithUserID:_userID error:NULL];
- }
- }
-
- @end
-
- @implementation FIRUserProfileChangeRequest {
-
-
- FIRUser *_user;
-
-
-
- NSString *_displayName;
-
-
-
- BOOL _displayNameSet;
-
-
-
- NSURL *_photoURL;
-
-
-
- BOOL _photoURLSet;
-
-
-
- BOOL _consumed;
- }
-
- - (nullable instancetype)initWithUser:(FIRUser *)user {
- self = [super init];
- if (self) {
- _user = user;
- }
- return self;
- }
-
- - (nullable NSString *)displayName {
- return _displayName;
- }
-
- - (void)setDisplayName:(nullable NSString *)displayName {
- dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- if (self->_consumed) {
- [NSException raise:NSInternalInconsistencyException
- format:@"%@",
- @"Invalid call to setDisplayName: after commitChangesWithCallback:."];
- return;
- }
- self->_displayNameSet = YES;
- self->_displayName = [displayName copy];
- });
- }
-
- - (nullable NSURL *)photoURL {
- return _photoURL;
- }
-
- - (void)setPhotoURL:(nullable NSURL *)photoURL {
- dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- if (self->_consumed) {
- [NSException raise:NSInternalInconsistencyException
- format:@"%@",
- @"Invalid call to setPhotoURL: after commitChangesWithCallback:."];
- return;
- }
- self->_photoURLSet = YES;
- self->_photoURL = [photoURL copy];
- });
- }
-
-
- - (BOOL)hasUpdates {
- return _displayNameSet || _photoURLSet;
- }
-
- - (void)commitChangesWithCompletion:(nullable FIRUserProfileChangeCallback)completion {
- dispatch_sync(FIRAuthGlobalWorkQueue(), ^{
- if (self->_consumed) {
- [NSException raise:NSInternalInconsistencyException
- format:@"%@",
- @"commitChangesWithCallback: should only be called once."];
- return;
- }
- self->_consumed = YES;
-
- if (![self hasUpdates]) {
- callInMainThreadWithError(completion, nil);
- return;
- }
- NSString *displayName = [self->_displayName copy];
- BOOL displayNameWasSet = self->_displayNameSet;
- NSURL *photoURL = [self->_photoURL copy];
- BOOL photoURLWasSet = self->_photoURLSet;
- [self->_user executeUserUpdateWithChanges:^(FIRGetAccountInfoResponseUser *user,
- FIRSetAccountInfoRequest *request) {
- if (photoURLWasSet) {
- request.photoURL = photoURL;
- }
- if (displayNameWasSet) {
- request.displayName = displayName;
- }
- }
- callback:^(NSError *_Nullable error) {
- if (error) {
- callInMainThreadWithError(completion, error);
- return;
- }
- if (displayNameWasSet) {
- [self->_user setDisplayName:displayName];
- }
- if (photoURLWasSet) {
- [self->_user setPhotoURL:photoURL];
- }
- if (![self->_user updateKeychain:&error]) {
- callInMainThreadWithError(completion, error);
- return;
- }
- callInMainThreadWithError(completion, nil);
- }];
- });
- }
-
- @end
-
- NS_ASSUME_NONNULL_END
|