Skip to content

Commit 5876159

Browse files
committed
Properly handle existing email users
Change-Id: I15adb6fab8306420fa7ca6a9a837e2260691369e
1 parent a5ed59c commit 5876159

File tree

7 files changed

+125
-10
lines changed

7 files changed

+125
-10
lines changed

auth/src/main/java/com/firebase/ui/auth/provider/EmailProvider.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ public void startLogin(Activity activity) {
4040

4141
@Override
4242
public void onActivityResult(int requestCode, int resultCode, Intent data) {
43-
if (requestCode == RC_EMAIL_FLOW && resultCode == Activity.RESULT_OK) {
44-
mActivity.setResult(Activity.RESULT_OK, data);
43+
if (requestCode == RC_EMAIL_FLOW
44+
&& (resultCode == Activity.RESULT_OK || resultCode == Activity.RESULT_CANCELED)) {
45+
mActivity.setResult(resultCode, data);
4546
mActivity.finish();
4647
}
4748
}

auth/src/main/java/com/firebase/ui/auth/ui/email/WelcomeBackPasswordPrompt.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
import android.widget.EditText;
3535
import android.widget.TextView;
3636

37+
import com.firebase.ui.auth.ErrorCodes;
38+
import com.firebase.ui.auth.FirebaseUiException;
3739
import com.firebase.ui.auth.IdpResponse;
3840
import com.firebase.ui.auth.R;
3941
import com.firebase.ui.auth.data.model.FlowParameters;
@@ -45,6 +47,7 @@
4547
import com.firebase.ui.auth.util.ui.ImeHelper;
4648
import com.firebase.ui.auth.viewmodel.email.WelcomeBackPasswordHandler;
4749
import com.google.firebase.auth.AuthCredential;
50+
import com.google.firebase.auth.EmailAuthProvider;
4851
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
4952
import com.google.firebase.auth.FirebaseUser;
5053

@@ -138,12 +141,29 @@ private void onSignInOperation(@Nullable Resource<IdpResponse> resource) {
138141
break;
139142
case FAILURE:
140143
getDialogHolder().dismissDialog();
141-
String message = getString(getErrorMessage(resource.getException()));
142-
mPasswordLayout.setError(message);
144+
onSignInError(resource.getException());
143145
break;
144146
}
145147
}
146148

149+
private void onSignInError(Exception e) {
150+
if (e instanceof FirebaseUiException) {
151+
FirebaseUiException fue = (FirebaseUiException) e;
152+
if (fue.getErrorCode() == ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT) {
153+
// TODO: Are we sure password will be here
154+
String password = mPasswordField.getText().toString();
155+
AuthCredential credential = EmailAuthProvider.getCredential(mEmail, password);
156+
157+
IdpResponse response = new IdpResponse.Builder(credential).build();
158+
finish(RESULT_CANCELED, response.toIntent());
159+
return;
160+
}
161+
}
162+
163+
String message = getString(getErrorMessage(e));
164+
mPasswordLayout.setError(message);
165+
}
166+
147167
@StringRes
148168
private int getErrorMessage(Exception exception) {
149169
if (exception instanceof FirebaseAuthInvalidCredentialsException) {

auth/src/main/java/com/firebase/ui/auth/util/AnonymousUpgradeUtils.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66

77
import com.firebase.ui.auth.data.model.FlowParameters;
88
import com.firebase.ui.auth.ui.HelperActivityBase;
9+
import com.google.android.gms.tasks.Continuation;
910
import com.google.android.gms.tasks.Task;
11+
import com.google.firebase.FirebaseApp;
1012
import com.google.firebase.auth.AuthCredential;
1113
import com.google.firebase.auth.AuthResult;
1214
import com.google.firebase.auth.EmailAuthProvider;
1315
import com.google.firebase.auth.FirebaseAuth;
1416
import com.google.firebase.auth.FirebaseAuthUserCollisionException;
1517

18+
import java.util.UUID;
19+
1620
/**
1721
* Utilities to help with Anonymous user upgrade.
1822
*/
@@ -74,7 +78,25 @@ public static boolean isUpgradeFailure(FlowParameters parameters,
7478
&& canUpgradeAnonymous(parameters, auth);
7579
}
7680

77-
private static boolean canUpgradeAnonymous(FlowParameters parameters, FirebaseAuth auth) {
81+
@NonNull
82+
public static Task<Boolean> validateCredential(FirebaseApp app, AuthCredential credential) {
83+
// Create a new FirebaseApp for us to do this operation.
84+
// TODO: is this expensive?
85+
String randomName = UUID.randomUUID().toString();
86+
FirebaseApp scratchApp = FirebaseApp.initializeApp(
87+
app.getApplicationContext(), app.getOptions(), randomName);
88+
FirebaseAuth scratchAuth = FirebaseAuth.getInstance(scratchApp);
89+
90+
return scratchAuth.signInWithCredential(credential)
91+
.continueWith(new Continuation<AuthResult, Boolean>() {
92+
@Override
93+
public Boolean then(@NonNull Task<AuthResult> task) throws Exception {
94+
return task.isSuccessful();
95+
}
96+
});
97+
}
98+
99+
public static boolean canUpgradeAnonymous(FlowParameters parameters, FirebaseAuth auth) {
78100
return parameters.enableAnonymousUpgrade
79101
&& auth.getCurrentUser() != null
80102
&& auth.getCurrentUser().isAnonymous();

auth/src/main/java/com/firebase/ui/auth/util/AuthHelper.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ public AuthHelper(FlowParameters params) {
2121
mFlowParams = params;
2222
}
2323

24+
public FirebaseApp getFirebaseApp() {
25+
return FirebaseApp.getInstance(mFlowParams.appName);
26+
}
27+
2428
public FirebaseAuth getFirebaseAuth() {
25-
return FirebaseAuth.getInstance(FirebaseApp.getInstance(mFlowParams.appName));
29+
return FirebaseAuth.getInstance(getFirebaseApp());
2630
}
2731

2832
@Nullable

auth/src/main/java/com/firebase/ui/auth/util/data/ProviderUtils.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,27 @@ public String then(@NonNull Task<ProviderQueryResult> task) {
130130
}
131131
});
132132
}
133+
134+
public static Task<Boolean> hasProvider(FirebaseAuth auth,
135+
String email,
136+
final String provider) {
137+
138+
return auth.fetchProvidersForEmail(email)
139+
.continueWith(new Continuation<ProviderQueryResult, Boolean>() {
140+
@Override
141+
public Boolean then(@NonNull Task<ProviderQueryResult> task) throws Exception {
142+
if (task.isSuccessful()) {
143+
// TODO?
144+
return false;
145+
}
146+
147+
List<String> providers = task.getResult().getProviders();
148+
if (providers == null || providers.isEmpty()) {
149+
return false;
150+
}
151+
152+
return providers.contains(provider);
153+
}
154+
});
155+
}
133156
}

auth/src/main/java/com/firebase/ui/auth/viewmodel/AuthViewModelBase.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
public class AuthViewModelBase extends ViewModelBase<FlowParameters> {
1919

2020
private CredentialsClient mCredentialsClient;
21+
private FirebaseApp mApp;
2122
private FirebaseAuth mAuth;
2223
private PhoneAuthProvider mPhoneAuth;
2324

@@ -29,8 +30,8 @@ protected AuthViewModelBase(Application application) {
2930

3031
@Override
3132
protected void onCreate() {
32-
FirebaseApp app = FirebaseApp.getInstance(getArguments().appName);
33-
mAuth = FirebaseAuth.getInstance(app);
33+
mApp = FirebaseApp.getInstance(getArguments().appName);
34+
mAuth = FirebaseAuth.getInstance(mApp);
3435
mPhoneAuth = PhoneAuthProvider.getInstance(mAuth);
3536
mCredentialsClient = GoogleApiUtils.getCredentialsClient(getApplication());
3637
}
@@ -39,6 +40,10 @@ protected FirebaseAuth getAuth() {
3940
return mAuth;
4041
}
4142

43+
protected FirebaseApp getApp() {
44+
return mApp;
45+
}
46+
4247
protected PhoneAuthProvider getPhoneAuth() {
4348
return mPhoneAuth;
4449
}

auth/src/main/java/com/firebase/ui/auth/viewmodel/email/WelcomeBackPasswordHandler.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
import android.support.annotation.Nullable;
88
import android.support.annotation.RestrictTo;
99

10+
import com.firebase.ui.auth.ErrorCodes;
11+
import com.firebase.ui.auth.FirebaseUiException;
1012
import com.firebase.ui.auth.IdpResponse;
1113
import com.firebase.ui.auth.data.model.Resource;
1214
import com.firebase.ui.auth.data.model.User;
1315
import com.firebase.ui.auth.data.remote.ProfileMerger;
1416
import com.firebase.ui.auth.ui.TaskFailureLogger;
17+
import com.firebase.ui.auth.util.AnonymousUpgradeUtils;
1518
import com.firebase.ui.auth.viewmodel.AuthViewModelBase;
1619
import com.google.android.gms.tasks.Continuation;
1720
import com.google.android.gms.tasks.OnCompleteListener;
@@ -66,8 +69,21 @@ public void startSignIn(@NonNull final String email,
6669
.build();
6770
}
6871

69-
// Kick off the flow including signing in, linking accounts, and saving with SmartLock
70-
getAuth().signInWithEmailAndPassword(email, password)
72+
// Before signing in, check to see if this is an anonymous upgrade and, if so, if we will
73+
// produce a conflict.
74+
checkAnonymousConflict(email, password)
75+
.continueWithTask(new Continuation<Void, Task<AuthResult>>() {
76+
@Override
77+
public Task<AuthResult> then(@NonNull Task<Void> task) throws Exception {
78+
// If validation failed, re-throw the exception
79+
if (!task.isSuccessful()) {
80+
throw task.getException();
81+
}
82+
83+
// Kick off the flow including signing in, linking accounts, and saving with SmartLock
84+
return getAuth().signInWithEmailAndPassword(email, password);
85+
}
86+
})
7187
.addOnFailureListener(new TaskFailureLogger(TAG, "signInWithEmailAndPassword failed."))
7288
.continueWithTask(new Continuation<AuthResult, Task<AuthResult>>() {
7389
@Override
@@ -99,6 +115,30 @@ public void onComplete(@NonNull Task<AuthResult> task) {
99115
});
100116
}
101117

118+
private Task<Void> checkAnonymousConflict(String email, String password) {
119+
if (!AnonymousUpgradeUtils.canUpgradeAnonymous(getArguments(), getAuth())) {
120+
return Tasks.forResult(null);
121+
}
122+
123+
final AuthCredential credential = EmailAuthProvider.getCredential(email, password);
124+
return AnonymousUpgradeUtils.validateCredential(getApp(), credential)
125+
.continueWith(new Continuation<Boolean, Void>() {
126+
@Override
127+
public Void then(@NonNull Task<Boolean> task) throws Exception {
128+
if (task.isSuccessful() && task.getResult()) {
129+
// Definitely conflict
130+
throw new FirebaseUiException(ErrorCodes.ANONYMOUS_UPGRADE_MERGE_CONFLICT);
131+
} else if (!task.isSuccessful()) {
132+
// Unknown error
133+
throw new FirebaseUiException(ErrorCodes.UNKNOWN_ERROR);
134+
} else {
135+
// No conflict
136+
return null;
137+
}
138+
}
139+
});
140+
}
141+
102142
/**
103143
* Get the observable state of the sign in operation.
104144
*/

0 commit comments

Comments
 (0)