[auth] Support updatePhoneNumber

This commit is contained in:
Joel Arvidsson
2018-09-10 14:56:33 +02:00
parent 02dfc7a1f9
commit a272910119
4 changed files with 137 additions and 31 deletions

View File

@@ -711,6 +711,63 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
}
/**
* updatePhoneNumber
*
* @param provider
* @param authToken
* @param authSecret
* @param promise
*/
@ReactMethod
private void updatePhoneNumber(
String appName,
String provider,
String authToken,
String authSecret,
final Promise promise
) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
FirebaseUser user = firebaseAuth.getCurrentUser();
if(!provider.equals("phone")) {
promise.reject(
"auth/invalid-credential",
"The supplied auth credential does not have a phone provider."
);
}
PhoneAuthCredential credential = getPhoneAuthCredential(authToken, authSecret);
if (credential == null) {
promise.reject(
"auth/invalid-credential",
"The supplied auth credential is malformed, has expired or is not currently supported."
);
} else if (user == null) {
promiseNoUser(promise, false);
Log.e(TAG, "updatePhoneNumber:failure:noCurrentUser");
} else {
Log.d(TAG, "updatePhoneNumber");
user
.updatePhoneNumber(credential)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "updatePhoneNumber:onComplete:success");
promiseWithUser(firebaseAuth.getCurrentUser(), promise);
} else {
Exception exception = task.getException();
Log.e(TAG, "updatePhoneNumber:onComplete:failure", exception);
promiseRejectAuthException(promise, exception);
}
}
});
}
}
/**
* updateProfile
*
@@ -1452,16 +1509,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
case "oauth":
return OAuthProvider.getCredential(provider, authToken, authSecret);
case "phone":
// If the phone number is auto-verified quickly, then the verificationId can be null
// We cached the credential as part of the verifyPhoneNumber request to be re-used here
// if possible
if (authToken == null && mCredential != null) {
PhoneAuthCredential credential = mCredential;
// Reset the cached credential
mCredential = null;
return credential;
}
return PhoneAuthProvider.getCredential(authToken, authSecret);
return getPhoneAuthCredential(authToken, authSecret);
case "password":
// authToken = email
// authSecret = password
@@ -1475,6 +1523,25 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
}
}
/**
* Returns an instance of PhoneAuthCredential, potentially cached
*/
private PhoneAuthCredential getPhoneAuthCredential(
String authToken,
String authSecret
) {
// If the phone number is auto-verified quickly, then the verificationId can be null
// We cached the credential as part of the verifyPhoneNumber request to be re-used here
// if possible
if (authToken == null && mCredential != null) {
PhoneAuthCredential credential = mCredential;
// Reset the cached credential
mCredential = null;
return credential;
}
return PhoneAuthProvider.getCredential(authToken, authSecret);
}
@ReactMethod
public void getToken(String appName, Boolean forceRefresh, final Promise promise) {
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);

View File

@@ -445,6 +445,48 @@ RCT_EXPORT_METHOD(updatePassword:
}
}
/**
updatePhoneNumber
@param NSString password
@param NSString provider
@param NSString authToken
@param NSString authSecret
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return
*/
RCT_EXPORT_METHOD(updatePhoneNumber:(NSString *) appDisplayName
provider:(NSString *) provider
token:(NSString *) authToken
secret:(NSString *) authSecret
resolver:(RCTPromiseResolveBlock) resolve
rejecter:(RCTPromiseRejectBlock) reject) {
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
if (user) {
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
if (credential == nil) {
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
}
[user updatePhoneNumberCredential:credential completion:^(NSError *_Nullable error) {
if (error) {
[self promiseRejectAuthException:reject error:error];
} else {
FIRUser *userAfterUpdate = [FIRAuth authWithApp:firApp].currentUser;
[self promiseWithUser:resolve rejecter:reject user:userAfterUpdate];
}
}];
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
}
/**
updateProfile

View File

@@ -250,6 +250,24 @@ export default class User {
});
}
/**
* Update the current user's phone number
*
* @param {AuthCredential} credential Auth credential with the _new_ phone number
* @return {Promise}
*/
updatePhoneNumber(credential: AuthCredential): Promise<void> {
return getNativeModule(this._auth)
.updatePhoneNumber(
credential.providerId,
credential.token,
credential.secret
)
.then(user => {
this._auth._setUser(user);
});
}
/**
* Update the current user's profile
* @param {Object} updates An object containing the keys listed [here](https://firebase.google.com/docs/auth/ios/manage-users#update_a_users_profile)
@@ -318,15 +336,6 @@ export default class User {
);
}
updatePhoneNumber() {
throw new Error(
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
'User',
'updatePhoneNumber'
)
);
}
get refreshToken(): string {
throw new Error(
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('User', 'refreshToken')

View File

@@ -461,18 +461,6 @@ describe('auth().currentUser', () => {
});
});
describe('updatePhoneNumber()', () => {
it('should throw an unsupported error', async () => {
await firebase.auth().signInAnonymouslyAndRetrieveData();
(() => {
firebase.auth().currentUser.updatePhoneNumber();
}).should.throw(
'User.updatePhoneNumber() is unsupported by the native Firebase SDKs.'
);
await firebase.auth().signOut();
});
});
describe('refreshToken', () => {
it('should throw an unsupported error', async () => {
await firebase.auth().signInAnonymouslyAndRetrieveData();