Skip to content
This repository was archived by the owner on Feb 6, 2025. It is now read-only.

Commit 706a58b

Browse files
Merge pull request #156 from wordpress-mobile/woo/issue-13321-magic-link-suspicious-emails
Use Magic Link for WordPress.com suspicious emails
2 parents cb4a9fe + 4bbf0b2 commit 706a58b

11 files changed

+96
-60
lines changed

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginAnalyticsListener.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ interface LoginAnalyticsListener {
5959
fun trackSubmitClicked()
6060
fun trackRequestMagicLinkClick()
6161
fun trackLoginWithPasswordClick()
62+
fun trackLoginWithWpComUsernamePasswordClick()
6263
fun trackShowHelpClick()
6364
fun trackDismissDialog()
6465
fun trackSelectEmailField()

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginBaseFormFragment.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ protected void startProgress(boolean cancellable) {
243243
mBottomButton.setEnabled(false);
244244
}
245245

246+
if (mProgressDialog != null) {
247+
mProgressDialog.setOnCancelListener(null);
248+
mProgressDialog.cancel();
249+
}
250+
246251
mProgressDialog =
247252
ProgressDialog.show(getActivity(), "", getActivity().getString(getProgressBarText()), true, cancellable,
248253
new DialogInterface.OnCancelListener() {

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginEmailFragment.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.wordpress.android.login;
22

3+
import static android.app.Activity.RESULT_OK;
4+
35
import android.app.PendingIntent;
46
import android.content.ActivityNotFoundException;
57
import android.content.Context;
@@ -53,15 +55,11 @@
5355
import org.wordpress.android.util.EditTextUtils;
5456
import org.wordpress.android.util.HtmlUtils;
5557
import org.wordpress.android.util.NetworkUtils;
56-
import org.wordpress.android.util.ToastUtils;
57-
import org.wordpress.android.util.ToastUtils.Duration;
5858

5959
import java.util.ArrayList;
6060
import java.util.regex.Matcher;
6161
import java.util.regex.Pattern;
6262

63-
import static android.app.Activity.RESULT_OK;
64-
6563
import dagger.android.support.AndroidSupportInjection;
6664

6765
public class LoginEmailFragment extends LoginBaseFormFragment<LoginListener> implements TextWatcher,
@@ -572,12 +570,9 @@ public void onAuthOptionsFetched(OnAuthOptionsFetched event) {
572570
// Will be true if in the Woo app and currently in the WPcom login
573571
// flow. We need to check this to know if we should display the
574572
// 'No WPcom account found' error screen.
575-
boolean isWooWPcomLoginFlow = false;
576-
if (mLoginListener != null
577-
&& mLoginListener.getLoginMode() == LoginMode.WOO_LOGIN_MODE
578-
&& !mOptionalSiteCredsLayout) {
579-
isWooWPcomLoginFlow = true;
580-
}
573+
boolean isWooWPcomLoginFlow = mLoginListener != null
574+
&& mLoginListener.getLoginMode() == LoginMode.WOO_LOGIN_MODE
575+
&& !mOptionalSiteCredsLayout;
581576

582577
if (mIsSignupFromLoginEnabled || isWooWPcomLoginFlow) {
583578
if (mLoginListener != null) {
@@ -589,11 +584,14 @@ public void onAuthOptionsFetched(OnAuthOptionsFetched event) {
589584
}
590585
break;
591586
case EMAIL_LOGIN_NOT_ALLOWED:
592-
// As a security measure, this user needs to log in using an username and password
587+
// As a security measure, this user can't sign in using their email/password
588+
// combination. Ask them to use Magic Link instead.
593589
mAnalyticsListener.trackFailure("Login with username required");
594-
ToastUtils.showToast(getContext(), R.string.error_user_username_instead_of_email, Duration.LONG);
595590
if (mLoginListener != null) {
596-
mLoginListener.loginViaWpcomUsernameInstead();
591+
mLoginListener.useMagicLinkInstead(email,
592+
false,
593+
false,
594+
MagicLinkFallbackButton.UsernameAndPassword);
597595
}
598596
break;
599597
case GENERIC_ERROR:

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginEmailPasswordFragment.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,11 @@ public void onClick(View v) {
193193

194194
final Button magicLinkButton = rootView.findViewById(R.id.login_get_email_link);
195195
magicLinkButton.setVisibility(mAllowMagicLink ? View.VISIBLE : View.GONE);
196-
magicLinkButton.setOnClickListener(new OnClickListener() {
197-
@Override public void onClick(View v) {
198-
if (mLoginListener != null) {
199-
mAnalyticsListener.trackRequestMagicLinkClick();
200-
mLoginListener.useMagicLinkInstead(mEmailAddress, mVerifyMagicLinkEmail);
201-
}
196+
magicLinkButton.setOnClickListener(v -> {
197+
if (mLoginListener != null) {
198+
mAnalyticsListener.trackRequestMagicLinkClick();
199+
mLoginListener.useMagicLinkInstead(mEmailAddress, mVerifyMagicLinkEmail,
200+
true, MagicLinkFallbackButton.None);
202201
}
203202
});
204203

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginListener.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void gotUnregisteredSocialAccount(String email, String displayName, String idTok
3737
void onTermsOfServiceClicked();
3838

3939
// Login Request Magic Link callbacks
40-
void showMagicLinkSentScreen(String email, boolean allowPassword);
40+
void showMagicLinkSentScreen(String email, MagicLinkFallbackButton fallbackButton);
4141
void usePasswordInstead(String email);
4242
void helpMagicLinkRequest(String email);
4343

@@ -47,7 +47,8 @@ void gotUnregisteredSocialAccount(String email, String displayName, String idTok
4747

4848
// Login email password callbacks
4949
void forgotPassword(String url);
50-
void useMagicLinkInstead(String email, boolean verifyEmail);
50+
void useMagicLinkInstead(String email, boolean verifyEmail,
51+
boolean requestAtStart, MagicLinkFallbackButton fallbackButton);
5152
void needs2fa(String email, String password);
5253
void needs2fa(String email, String password, String userId, String webauthnNonce,
5354
String nonceAuthenticator, String nonceBackup, String noncePush,

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginMagicLinkRequestFragment.java

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public class LoginMagicLinkRequestFragment extends Fragment {
5252
private static final String ARG_IS_JETPACK_CONNECT = "ARG_IS_JETPACK_CONNECT";
5353
private static final String ARG_JETPACK_CONNECT_SOURCE = "ARG_JETPACK_CONNECT_SOURCE";
5454
private static final String ARG_VERIFY_MAGIC_LINK_EMAIL = "ARG_VERIFY_MAGIC_LINK_EMAIL";
55-
private static final String ARG_ALLOW_PASSWORD = "ARG_ALLOW_PASSWORD";
55+
private static final String ARG_FALLBACK_BUTTON = "ARG_FALLBACK_BUTTON";
5656
private static final String ARG_FORCE_REQUEST_AT_START = "ARG_FORCE_REQUEST_AT_START";
5757

5858
private static final String ERROR_KEY = "error";
@@ -70,7 +70,7 @@ public class LoginMagicLinkRequestFragment extends Fragment {
7070
private boolean mInProgress;
7171
private boolean mIsJetpackConnect;
7272
private boolean mVerifyMagicLinkEmail;
73-
private boolean mAllowPassword;
73+
private MagicLinkFallbackButton mFallbackButton;
7474
private boolean mForceRequestAtStart;
7575

7676
@Inject protected Dispatcher mDispatcher;
@@ -80,12 +80,13 @@ public class LoginMagicLinkRequestFragment extends Fragment {
8080
public static LoginMagicLinkRequestFragment newInstance(String email, AuthEmailPayloadScheme scheme,
8181
boolean isJetpackConnect, String jetpackConnectSource,
8282
boolean verifyEmail) {
83-
return newInstance(email, scheme, isJetpackConnect, jetpackConnectSource, verifyEmail, true, false);
83+
return newInstance(email, scheme, isJetpackConnect, jetpackConnectSource,
84+
verifyEmail, MagicLinkFallbackButton.Password, false);
8485
}
8586

8687
public static LoginMagicLinkRequestFragment newInstance(String email, AuthEmailPayloadScheme scheme,
8788
boolean isJetpackConnect, String jetpackConnectSource,
88-
boolean verifyEmail, boolean allowPassword,
89+
boolean verifyEmail, MagicLinkFallbackButton fallbackButton,
8990
boolean forceRequestAtStart) {
9091
LoginMagicLinkRequestFragment fragment = new LoginMagicLinkRequestFragment();
9192
Bundle args = new Bundle();
@@ -94,7 +95,7 @@ public static LoginMagicLinkRequestFragment newInstance(String email, AuthEmailP
9495
args.putBoolean(ARG_IS_JETPACK_CONNECT, isJetpackConnect);
9596
args.putString(ARG_JETPACK_CONNECT_SOURCE, jetpackConnectSource);
9697
args.putBoolean(ARG_VERIFY_MAGIC_LINK_EMAIL, verifyEmail);
97-
args.putBoolean(ARG_ALLOW_PASSWORD, allowPassword);
98+
args.putSerializable(ARG_FALLBACK_BUTTON, fallbackButton);
9899
args.putBoolean(ARG_FORCE_REQUEST_AT_START, forceRequestAtStart);
99100
fragment.setArguments(args);
100101
return fragment;
@@ -121,7 +122,7 @@ public void onCreate(Bundle savedInstanceState) {
121122
mIsJetpackConnect = getArguments().getBoolean(ARG_IS_JETPACK_CONNECT);
122123
mJetpackConnectSource = getArguments().getString(ARG_JETPACK_CONNECT_SOURCE);
123124
mVerifyMagicLinkEmail = getArguments().getBoolean(ARG_VERIFY_MAGIC_LINK_EMAIL);
124-
mAllowPassword = getArguments().getBoolean(ARG_ALLOW_PASSWORD);
125+
mFallbackButton = (MagicLinkFallbackButton) getArguments().getSerializable(ARG_FALLBACK_BUTTON);
125126
mForceRequestAtStart = getArguments().getBoolean(ARG_FORCE_REQUEST_AT_START);
126127
}
127128

@@ -132,23 +133,33 @@ public void onCreate(Bundle savedInstanceState) {
132133
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
133134
View view = inflater.inflate(R.layout.login_magic_link_request_screen, container, false);
134135
mRequestMagicLinkButton = view.findViewById(R.id.login_request_magic_link);
135-
mRequestMagicLinkButton.setOnClickListener(new View.OnClickListener() {
136-
@Override
137-
public void onClick(View v) {
138-
mAnalyticsListener.trackRequestMagicLinkClick();
139-
dispatchMagicLinkRequest();
140-
}
136+
mRequestMagicLinkButton.setOnClickListener(v -> {
137+
mAnalyticsListener.trackRequestMagicLinkClick();
138+
dispatchMagicLinkRequest();
141139
});
142140

143-
final Button passwordButton = view.findViewById(R.id.login_enter_password);
144-
passwordButton.setVisibility(mAllowPassword ? View.VISIBLE : View.GONE);
145-
passwordButton.setOnClickListener(new View.OnClickListener() {
146-
@Override
147-
public void onClick(View v) {
148-
mAnalyticsListener.trackLoginWithPasswordClick();
149-
if (mLoginListener != null) {
150-
mLoginListener.usePasswordInstead(mEmail);
151-
}
141+
final Button fallbackButtonView = view.findViewById(R.id.login_magic_link_fallback_button);
142+
fallbackButtonView.setVisibility(mFallbackButton == MagicLinkFallbackButton.None ? View.GONE : View.VISIBLE);
143+
fallbackButtonView.setText(mFallbackButton == MagicLinkFallbackButton.UsernameAndPassword
144+
? R.string.login_use_wpcom_username_instead
145+
: R.string.or_type_your_password);
146+
147+
fallbackButtonView.setOnClickListener(v -> {
148+
switch (mFallbackButton) {
149+
case Password:
150+
mAnalyticsListener.trackLoginWithPasswordClick();
151+
if (mLoginListener != null) {
152+
mLoginListener.usePasswordInstead(mEmail);
153+
}
154+
break;
155+
case UsernameAndPassword:
156+
mAnalyticsListener.trackLoginWithWpComUsernamePasswordClick();
157+
if (mLoginListener != null) {
158+
mLoginListener.loginViaWpcomUsernameInstead();
159+
}
160+
break;
161+
case None:
162+
throw new IllegalStateException("Button should not be visible");
152163
}
153164
});
154165

@@ -365,7 +376,7 @@ public void onAuthEmailSent(OnAuthEmailSent event) {
365376
fragmentManager.popBackStack();
366377
}
367378
}
368-
mLoginListener.showMagicLinkSentScreen(mEmail, mAllowPassword);
379+
mLoginListener.showMagicLinkSentScreen(mEmail, mFallbackButton);
369380
}
370381
}
371382
}

WordPressLoginFlow/src/main/java/org/wordpress/android/login/LoginMagicLinkSentFragment.java

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,24 @@ public class LoginMagicLinkSentFragment extends Fragment {
2929
public static final String TAG = "login_magic_link_sent_fragment_tag";
3030

3131
private static final String ARG_EMAIL_ADDRESS = "ARG_EMAIL_ADDRESS";
32-
private static final String ARG_ALLOW_PASSWORD = "ARG_ALLOW_PASSWORD";
32+
private static final String ARG_FALLBACK_BUTTON = "ARG_FALLBACK_BUTTON";
3333

3434
private LoginListener mLoginListener;
3535

3636
private String mEmail;
37-
private boolean mAllowPassword;
37+
private MagicLinkFallbackButton mFallbackButton;
3838

3939
@Inject protected LoginAnalyticsListener mAnalyticsListener;
4040

4141
public static LoginMagicLinkSentFragment newInstance(String email) {
42-
return newInstance(email, true);
42+
return newInstance(email, MagicLinkFallbackButton.Password);
4343
}
4444

45-
public static LoginMagicLinkSentFragment newInstance(String email, boolean allowPassword) {
45+
public static LoginMagicLinkSentFragment newInstance(String email, MagicLinkFallbackButton fallbackButton) {
4646
LoginMagicLinkSentFragment fragment = new LoginMagicLinkSentFragment();
4747
Bundle args = new Bundle();
4848
args.putString(ARG_EMAIL_ADDRESS, email);
49-
args.putBoolean(ARG_ALLOW_PASSWORD, allowPassword);
49+
args.putSerializable(ARG_FALLBACK_BUTTON, fallbackButton);
5050
fragment.setArguments(args);
5151
return fragment;
5252
}
@@ -56,7 +56,7 @@ public void onCreate(Bundle savedInstanceState) {
5656
super.onCreate(savedInstanceState);
5757
if (getArguments() != null) {
5858
mEmail = getArguments().getString(ARG_EMAIL_ADDRESS);
59-
mAllowPassword = getArguments().getBoolean(ARG_ALLOW_PASSWORD);
59+
mFallbackButton = (MagicLinkFallbackButton) getArguments().getSerializable(ARG_FALLBACK_BUTTON);
6060
}
6161

6262
setHasOptionsMenu(true);
@@ -75,15 +75,28 @@ public void onClick(View v) {
7575
}
7676
});
7777

78-
final Button passwordButton = view.findViewById(R.id.login_enter_password);
79-
passwordButton.setVisibility(mAllowPassword ? View.VISIBLE : View.GONE);
80-
passwordButton.setOnClickListener(new View.OnClickListener() {
81-
@Override
82-
public void onClick(View v) {
83-
mAnalyticsListener.trackLoginWithPasswordClick();
84-
if (mLoginListener != null) {
85-
mLoginListener.usePasswordInstead(mEmail);
86-
}
78+
final Button fallbackButtonView = view.findViewById(R.id.login_magic_link_fallback_button);
79+
fallbackButtonView.setVisibility(mFallbackButton == MagicLinkFallbackButton.None ? View.GONE : View.VISIBLE);
80+
fallbackButtonView.setText(mFallbackButton == MagicLinkFallbackButton.UsernameAndPassword
81+
? R.string.login_use_wpcom_username_instead
82+
: R.string.or_type_your_password);
83+
84+
fallbackButtonView.setOnClickListener(v -> {
85+
switch (mFallbackButton) {
86+
case Password:
87+
mAnalyticsListener.trackLoginWithPasswordClick();
88+
if (mLoginListener != null) {
89+
mLoginListener.usePasswordInstead(mEmail);
90+
}
91+
break;
92+
case UsernameAndPassword:
93+
mAnalyticsListener.trackLoginWithWpComUsernamePasswordClick();
94+
if (mLoginListener != null) {
95+
mLoginListener.loginViaWpcomUsernameInstead();
96+
}
97+
break;
98+
case None:
99+
throw new IllegalStateException("Button should not be visible");
87100
}
88101
});
89102

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.wordpress.android.login
2+
3+
enum class MagicLinkFallbackButton {
4+
None,
5+
Password,
6+
UsernameAndPassword
7+
}

WordPressLoginFlow/src/main/res/layout/login_magic_link_request_screen.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
android:text="@string/login_magic_links_label" />
3434

3535
<com.google.android.material.button.MaterialButton
36-
android:id="@+id/login_enter_password"
36+
android:id="@+id/login_magic_link_fallback_button"
3737
style="@style/Widget.LoginFlow.Button.Tertiary"
3838
android:layout_width="wrap_content"
3939
android:layout_height="wrap_content"

WordPressLoginFlow/src/main/res/layout/login_magic_link_sent_screen.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
android:text="@string/magic_link_not_seeing_email_message" />
4141

4242
<com.google.android.material.button.MaterialButton
43-
android:id="@+id/login_enter_password"
43+
android:id="@+id/login_magic_link_fallback_button"
4444
style="@style/Widget.LoginFlow.Button.Tertiary"
4545
android:layout_width="wrap_content"
4646
android:layout_height="wrap_content"

0 commit comments

Comments
 (0)