[ios,android] WIP - moving auth to promises & fixing ios <-> android discrepancies

This commit is contained in:
Salakar 2017-03-14 19:04:16 +00:00
parent b18a7a0d6a
commit 0914a9341c
3 changed files with 335 additions and 229 deletions

View File

@ -66,7 +66,9 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
return TAG;
}
/**
* Add a new auth state listener - if one doesn't exist already
*/
@ReactMethod
public void addAuthStateListener() {
if (mAuthListener == null) {
@ -179,36 +181,109 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
});
}
/**
* signInWithEmailAndPassword
*
* @param email
* @param password
* @param promise
*/
@ReactMethod
public void signInWithEmail(final String email, final String password, final Callback callback) {
public void signInWithEmailAndPassword(final String email, final String password, final Promise promise) {
Log.d(TAG, "signInWithEmailAndPassword");
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
try {
if (task.isSuccessful()) {
userCallback(task.getResult().getUser(), callback);
} else {
userErrorCallback(task, callback);
}
} catch (Exception ex) {
userExceptionCallback(ex, callback);
}
public void onSuccess(AuthResult authResult) {
Log.d(TAG, "signInWithEmailAndPassword:onComplete:success");
promiseWithUser(authResult.getUser(), promise);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
WritableMap error = authExceptionToMap(exception);
Log.e(TAG, "signInWithEmailAndPassword:onComplete:failure", exception);
promise.reject(error.getString("code"), error.getString("message"), exception);
}
});
}
/**
* signInWithCustomToken
*
* @param token
* @param promise
*/
@ReactMethod
public void signInWithCustomToken(final String token, final Promise promise) {
Log.d(TAG, "signInWithCustomToken");
mAuth.signInWithCustomToken(token)
.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
@Override
public void onSuccess(AuthResult authResult) {
Log.d(TAG, "signInWithCustomToken:onComplete:success");
promiseWithUser(authResult.getUser(), promise);
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception exception) {
WritableMap error = authExceptionToMap(exception);
Log.e(TAG, "signInWithCustomToken:onComplete:failure", exception);
promise.reject(error.getString("code"), error.getString("message"), exception);
}
});
}
@ReactMethod
public void signInWithProvider(final String provider, final String authToken, final String authSecret, final Callback callback) {
if (provider.equals("facebook")) {
this.facebookLogin(authToken, callback);
} else if (provider.equals("google")) {
this.googleLogin(authToken, callback);
} else
// TODO
Utils.todoNote(TAG, "signInWithProvider", callback);
public void delete(final Promise promise) {
FirebaseUser user = mAuth.getCurrentUser();
Log.d(TAG, "delete");
if (user != null) {
user.delete()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "delete:onComplete:success");
promiseNoUser(promise, false);
} else {
Exception exception = task.getException();
WritableMap error = authExceptionToMap(exception);
Log.e(TAG, "delete:onComplete:failure", exception);
promise.reject(error.getString("code"), error.getString("message"), exception);
}
}
});
} else {
Log.e(TAG, "signInWithCustomToken:onComplete:failure:noCurrentUser");
promiseNoUser(promise, true);
}
}
/**
* signInWithCredential
* TODO
*
* @param provider
* @param authToken
* @param authSecret
* @param promise
*/
@ReactMethod
public void signInWithCredential(final String provider, final String authToken, final String authSecret, final Promise promise) {
switch (provider) {
case "facebook":
//facebookLogin(authToken, callback);
break;
case "google":
//googleLogin(authToken, callback);
default:
promise.reject("auth/invalid_provider", "The provider specified is invalid.");
}
}
@ReactMethod
@ -248,26 +323,6 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
Utils.todoNote(TAG, "linkWithProvider", callback);
}
@ReactMethod
public void signInWithCustomToken(final String customToken, final Callback callback) {
mAuth.signInWithCustomToken(customToken)
.addOnCompleteListener(new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCustomToken:onComplete:" + task.isSuccessful());
try {
if (task.isSuccessful()) {
userCallback(task.getResult().getUser(), callback);
} else {
userErrorCallback(task, callback);
}
} catch (Exception ex) {
userExceptionCallback(ex, callback);
}
}
});
}
@ReactMethod
public void reauthenticate(final String provider, final String authToken, final String authSecret, final Callback callback) {
// TODO:
@ -350,35 +405,6 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
});
}
@ReactMethod
public void delete(final Callback callback) {
FirebaseUser user = mAuth.getCurrentUser();
if (user != null) {
user.delete()
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
try {
if (task.isSuccessful()) {
Log.d(TAG, "User account deleted");
WritableMap resp = Arguments.createMap();
resp.putString("status", "complete");
resp.putString("msg", "User account deleted");
callback.invoke(null, resp);
} else {
userErrorCallback(task, callback);
}
} catch (Exception ex) {
userExceptionCallback(ex, callback);
}
}
});
} else {
callbackNoUser(callback, true);
}
}
@ReactMethod
public void sendEmailVerification(final Callback callback) {
FirebaseUser user = mAuth.getCurrentUser();
@ -638,17 +664,28 @@ public class RNFirebaseAuth extends ReactContextBaseJavaModule {
final Boolean verified = user.isEmailVerified();
final Uri photoUrl = user.getPhotoUrl();
userMap.putString("email", email);
userMap.putString("uid", uid);
userMap.putString("providerId", provider);
userMap.putBoolean("emailVerified", verified);
userMap.putBoolean("isAnonymous", user.isAnonymous());
if (email != null) {
userMap.putString("email", email);
} else {
userMap.putNull("email");
}
if (name != null) {
userMap.putString("name", name);
userMap.putString("displayName", name);
} else {
userMap.putNull("displayName");
}
if (photoUrl != null) {
userMap.putString("photoURL", photoUrl.toString());
} else {
userMap.putNull("photoURL");
}
return userMap;

View File

@ -8,40 +8,119 @@ typedef void (^UserWithTokenResponse)(NSDictionary *, NSError *);
RCT_EXPORT_MODULE(RNFirebaseAuth);
RCT_EXPORT_METHOD(signInAnonymously:
(RCTResponseSenderBlock) callBack)
{
@try {
[[FIRAuth auth] signInAnonymouslyWithCompletion
:^(FIRUser *user, NSError *error) {
if (!user) {
NSDictionary *evt = @{
@"eventName": AUTH_ANONYMOUS_ERROR_EVENT,
@"msg": [error localizedDescription]
};
/**
signOut
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return
*/
RCT_EXPORT_METHOD(signOut:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
FIRUser *user = [FIRAuth auth].currentUser;
[self sendJSEvent:AUTH_CHANGED_EVENT
props: evt];
callBack(@[evt]);
} else {
[self userCallback:callBack user:user];
}
}];
} @catch(NSException *ex) {
NSDictionary *eventError = @{
@"eventName": AUTH_ANONYMOUS_ERROR_EVENT,
@"msg": ex.reason
};
[self sendJSEvent:AUTH_ERROR_EVENT
props:eventError];
NSLog(@"An exception occurred: %@", ex);
callBack(@[eventError]);
if (user) {
NSError *error;
[[FIRAuth auth] signOut:&error];
if (!error) [self promiseNoUser:resolve rejecter:reject isError:NO];
// TODO authExceptionToDict
else reject(@"auth/unknown", @"An unknown error has occurred.", error);
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
}
/**
signInAnonymously
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return
*/
RCT_EXPORT_METHOD(signInAnonymously:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
[[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
if (error) {
// TODO authExceptionToDict
reject(@"auth/todo", [error localizedDescription], error);
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
}
/**
signInWithEmailAndPassword
@param NSString NSString email
@param NSString NSString password
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return return
*/
RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *)email pass:(NSString *)password resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
[[FIRAuth auth] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) {
// TODO authExceptionToDict
reject(@"auth/todo", [error localizedDescription], error);
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
}
/**
createUserWithEmailAndPassword
@param NSString NSString email
@param NSString NSString password
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return return
*/
RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *)email pass:(NSString *)password resolver:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
[[FIRAuth auth] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
if (error) {
// TODO authExceptionToDict
reject(@"auth/todo", [error localizedDescription], error);
} else {
[self promiseWithUser:resolve rejecter:reject user:user];
}
}];
}
/**
deleteUser
@param RCTPromiseResolveBlock resolve
@param RCTPromiseRejectBlock reject
@return return
*/
RCT_EXPORT_METHOD(delete:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject) {
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user deleteWithCompletion:^(NSError *_Nullable error) {
if (error) {
// TODO authExceptionToDict
reject(@"auth/unknown", @"An unknown error has occurred.", error);
} else {
[self promiseNoUser:resolve rejecter:reject isError:NO];
}
}];
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
}
// TODO ------------------------------------------------------- CLEAN UP --------------------------
// TODO ------------------------------------------------------- CLEAN UP --------------------------
// TODO ------------------------------------------------------- CLEAN UP --------------------------
// TODO ------------------------------------------------------- CLEAN UP --------------------------
RCT_EXPORT_METHOD(signInWithCustomToken:
(NSString *)customToken
callback:(RCTResponseSenderBlock) callback)
@ -92,24 +171,7 @@ RCT_EXPORT_METHOD(signInWithProvider:
}];
} @catch (NSException *exception) {
[RNFirebaseErrors handleException:exception
withCallback:callback];
}
}
RCT_EXPORT_METHOD(signOut:(RCTResponseSenderBlock)callback)
{
NSError *error;
[[FIRAuth auth] signOut:&error];
if (!error) {
// Sign-out succeeded
callback(@[[NSNull null], @YES]);
} else {
NSDictionary *err = @{
@"error": @"Signout error",
@"name": @([error code]),
@"description": [error description]
};
callback(@[err]);
withCallback:callback];
}
}
@ -117,8 +179,7 @@ RCT_EXPORT_METHOD(addAuthStateListener)
{
self->listening = true;
self->authListenerHandle =
[[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth,
FIRUser *_Nullable user) {
[[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
if (user != nil) {
// User is signed in.
@ -180,43 +241,6 @@ RCT_EXPORT_METHOD(getCurrentUser:(RCTResponseSenderBlock)callback)
}
}
RCT_EXPORT_METHOD(createUserWithEmail:(NSString *)email
pass:(NSString *)password
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth]
createUserWithEmail:email
password:password
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error) {
if (user != nil) {
[self userCallback:callback user:user];
} else {
NSDictionary *err = @{
@"error": @"createUserWithEmailError",
@"name": @([error code]),
@"description": [error localizedDescription]
};
callback(@[err]);
}
}];
}
RCT_EXPORT_METHOD(signInWithEmail:(NSString *)email
pass:(NSString *)password
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth] signInWithEmail:email
password:password
completion:^(FIRUser *user, NSError *error) {
if (user != nil) {
[self userCallback:callback user:user];
} else {
[self userErrorCallback:callback error:error user:user msg:@"signinError"];
}
}];
}
RCT_EXPORT_METHOD(updateUserEmail:(NSString *)email
callback:(RCTResponseSenderBlock) callback)
{
@ -280,23 +304,6 @@ RCT_EXPORT_METHOD(sendPasswordResetWithEmail:(NSString *)email
}];
}
RCT_EXPORT_METHOD(deleteUser:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user deleteWithCompletion:^(NSError *_Nullable error) {
if (error) {
[self userErrorCallback:callback error:error user:user msg:@"deleteUserError"];
} else {
callback(@[[NSNull null], @{@"result": @(true)}]);
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(getToken:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
@ -398,30 +405,10 @@ RCT_EXPORT_METHOD(updateUserProfile:(NSDictionary *)userProps
}
}
- (NSDictionary *) userPropsFromFIRUser:(FIRUser *) user
{
NSMutableDictionary *userProps = [@{
@"uid": user.uid,
@"email": user.email ? user.email : @"",
@"emailVerified": @(user.emailVerified),
@"anonymous": @(user.anonymous),
@"displayName": user.displayName ? user.displayName : @"",
@"refreshToken": user.refreshToken,
@"providerID": user.providerID
} mutableCopy];
if ([user valueForKey:@"photoURL"] != nil) {
[userProps setValue: [NSString stringWithFormat:@"%@", user.photoURL]
forKey:@"photoURL"];
}
return userProps;
}
- (void) userPropsFromFIRUserWithToken:(FIRUser *) user
andCallback:(UserWithTokenResponse) callback
{
NSMutableDictionary *userProps = [[self userPropsFromFIRUser:user] mutableCopy];
NSMutableDictionary *userProps = [[self firebaseUserToDict:user] mutableCopy];
[user getTokenWithCompletion:^(NSString * _Nullable token, NSError * _Nullable error) {
if (error != nil) {
return callback(nil, error);
@ -432,10 +419,7 @@ RCT_EXPORT_METHOD(updateUserProfile:(NSDictionary *)userProps
}];
}
- (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider
token:(NSString *)authToken
secret:(NSString *)authTokenSecret
{
- (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider token:(NSString *)authToken secret:(NSString *)authTokenSecret {
FIRAuthCredential *credential;
if ([provider compare:@"twitter" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIRTwitterAuthProvider credentialWithToken:authToken
@ -470,11 +454,6 @@ RCT_EXPORT_METHOD(updateUserProfile:(NSDictionary *)userProps
}
}
- (void) userCallback:(RCTResponseSenderBlock) callback
user:(FIRUser *) user {
NSDictionary *userProps = [self userPropsFromFIRUser:user];
callback(@[[NSNull null], userProps]);
}
- (void) noUserCallback:(RCTResponseSenderBlock) callback
isError:(Boolean) isError {
@ -494,10 +473,87 @@ RCT_EXPORT_METHOD(updateUserProfile:(NSDictionary *)userProps
msg:(NSString *) msg {
// An error happened.
NSDictionary *err = [RNFirebaseErrors handleFirebaseError:msg
error:error
withUser:user];
error:error
withUser:user];
callback(@[err]);
}
- (void) userCallback:(RCTResponseSenderBlock) callback user:(FIRUser *) user {
NSDictionary *userProps = [self firebaseUserToDict:user];
callback(@[[NSNull null], userProps]);
}
// END ------------------------------------------------------- CLEAN UP -^ -----------------------
// END ------------------------------------------------------- CLEAN UP --------------------------
// END ------------------------------------------------------- CLEAN UP --------------------------
// END ------------------------------------------------------- CLEAN UP --------------------------
- (NSDictionary *) authExceptionToDict:(NSError *) error {
// TODO
// NSDictionary *evt = @{ @"eventName": AUTH_ANONYMOUS_ERROR_EVENT,
// @"msg": [error localizedDescription] };
}
/**
Resolve or reject a promise based on isError value
@param resolve RCTPromiseResolveBlock
@param reject RCTPromiseRejectBlock
@param isError BOOL
*/
- (void) promiseNoUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject isError:(BOOL) isError {
if (isError) {
reject(@"auth/no_current_user", @"No user currently signed in.", nil);
} else {
resolve([NSNull null]);
}
}
/**
Resolve or reject a promise based on FIRUser value existance
@param resolve RCTPromiseResolveBlock
@param reject RCTPromiseRejectBlock
@param user FIRUser
*/
- (void) promiseWithUser:(RCTPromiseResolveBlock) resolve rejecter:(RCTPromiseRejectBlock) reject user:(FIRUser *) user {
if (user) {
NSDictionary *userDict = [self firebaseUserToDict:user];
resolve(userDict);
} else {
[self promiseNoUser:resolve rejecter:reject isError:YES];
}
}
/**
Converts a FIRUser instance into a dictionary to send via RNBridge
@param user FIRUser
@return NSDictionary
*/
- (NSDictionary *) firebaseUserToDict:(FIRUser *) user {
NSMutableDictionary *userDict = [
@{ @"uid": user.uid,
@"email": user.email ? user.email : [NSNull null],
@"emailVerified": @(user.emailVerified),
@"isAnonymous": @(user.anonymous),
@"displayName": user.displayName ? user.displayName : [NSNull null],
@"refreshToken": user.refreshToken,
@"providerId": [user.providerID lowercaseString]
}
mutableCopy
];
if ([user valueForKey:@"photoURL"] != nil) {
[userDict setValue: [NSString stringWithFormat:@"%@", user.photoURL] forKey:@"photoURL"];
}
return userDict;
}
@end

View File

@ -51,6 +51,18 @@ export default class User {
return this._user[prop];
}
/**
* Returns a user property or false if does not exist
* @param prop
* @returns {*}
* @private
*/
_valueOrFalse(prop) {
if (!this._user) return false;
if (!Object.hasOwnProperty.call(this._user, prop)) return false;
return this._user[prop];
}
/**
* PROPERTIES
*/
@ -68,7 +80,7 @@ export default class User {
}
get isAnonymous(): Boolean {
return !this._valueOrNull('email') && this._valueOrNull('providerId') === 'firebase';
return this._valueOrFalse('isAnonymous');
}
get photoURL(): String|null {
@ -89,6 +101,7 @@ export default class User {
*/
toJSON() {
return Object.assign({}, this._user);
return {
uid: this.uid,
email: this.email,
@ -105,7 +118,7 @@ export default class User {
* @return {Promise}
*/
delete(): Promise<Object> {
return promisify('delete', FirebaseAuth, 'auth/')();
return FirebaseAuth.delete();
}
/**