Skip to content

Commit 010df27

Browse files
committed
Consume login client from data client library
1 parent 84637c5 commit 010df27

File tree

5 files changed

+137
-166
lines changed

5 files changed

+137
-166
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ dependencies {
2828
implementation 'com.jakewharton.rxbinding2:rxbinding-design:2.1.1'
2929
implementation 'com.facebook.fresco:fresco:1.13.0'
3030
implementation 'com.drewnoakes:metadata-extractor:2.11.0'
31-
implementation 'com.dmitrybrant:wikimedia-android-data-client:0.0.12'
31+
implementation 'com.dmitrybrant:wikimedia-android-data-client:0.0.16'
3232

3333
// UI
3434
implementation 'fr.avianey.com.viewpagerindicator:library:2.4.1.1@aar'

app/src/main/java/fr/free/nrw/commons/auth/AccountUtil.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,17 @@
33
import android.accounts.Account;
44
import android.accounts.AccountManager;
55
import android.content.Context;
6-
import androidx.annotation.Nullable;
76

7+
import androidx.annotation.Nullable;
88
import fr.free.nrw.commons.BuildConfig;
99
import timber.log.Timber;
1010

1111
public class AccountUtil {
1212

1313
public static final String AUTH_COOKIE = "authCookie";
1414
public static final String AUTH_TOKEN_TYPE = "CommonsAndroid";
15-
private final Context context;
1615

17-
public AccountUtil(Context context) {
18-
this.context = context;
16+
public AccountUtil() {
1917
}
2018

2119
/**
@@ -49,5 +47,4 @@ public static String getPassword(Context context) {
4947
private static AccountManager accountManager(Context context) {
5048
return AccountManager.get(context);
5149
}
52-
5350
}

app/src/main/java/fr/free/nrw/commons/auth/LoginActivity.java

Lines changed: 91 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package fr.free.nrw.commons.auth;
22

3-
import android.accounts.Account;
43
import android.accounts.AccountAuthenticatorActivity;
54
import android.accounts.AccountAuthenticatorResponse;
65
import android.accounts.AccountManager;
@@ -22,14 +21,17 @@
2221

2322
import com.google.android.material.textfield.TextInputLayout;
2423

25-
import java.io.IOException;
26-
import java.util.Locale;
24+
import org.wikipedia.AppAdapter;
25+
import org.wikipedia.dataclient.WikiSite;
26+
import org.wikipedia.login.LoginClient;
27+
import org.wikipedia.login.LoginResult;
2728

2829
import javax.inject.Inject;
2930
import javax.inject.Named;
3031

3132
import androidx.annotation.ColorRes;
3233
import androidx.annotation.NonNull;
34+
import androidx.annotation.Nullable;
3335
import androidx.annotation.StringRes;
3436
import androidx.appcompat.app.AlertDialog;
3537
import androidx.appcompat.app.AppCompatDelegate;
@@ -52,16 +54,12 @@
5254
import fr.free.nrw.commons.theme.NavigationBaseActivity;
5355
import fr.free.nrw.commons.utils.ConfigUtils;
5456
import fr.free.nrw.commons.utils.ViewUtil;
55-
import io.reactivex.Observable;
56-
import io.reactivex.android.schedulers.AndroidSchedulers;
5757
import io.reactivex.disposables.CompositeDisposable;
58-
import io.reactivex.schedulers.Schedulers;
5958
import timber.log.Timber;
6059

6160
import static android.view.KeyEvent.KEYCODE_ENTER;
6261
import static android.view.View.VISIBLE;
6362
import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE;
64-
import static fr.free.nrw.commons.auth.AccountUtil.AUTH_TOKEN_TYPE;
6563

6664
public class LoginActivity extends AccountAuthenticatorActivity {
6765

@@ -99,18 +97,15 @@ public class LoginActivity extends AccountAuthenticatorActivity {
9997
@BindView(R.id.two_factor_container)
10098
TextInputLayout twoFactorContainer;
10199

100+
private LoginClient loginClient;
101+
@Nullable
102+
private String firstStepToken;
103+
102104
ProgressDialog progressDialog;
103105
private AppCompatDelegate delegate;
104106
private LoginTextWatcher textWatcher = new LoginTextWatcher();
105107
private CompositeDisposable compositeDisposable = new CompositeDisposable();
106108

107-
private Boolean loginCurrentlyInProgress = false;
108-
private Boolean errorMessageShown = false;
109-
private String resultantError;
110-
private static final String RESULTANT_ERROR = "resultantError";
111-
private static final String ERROR_MESSAGE_SHOWN = "errorMessageShown";
112-
private static final String LOGGING_IN = "loggingIn";
113-
114109
@Override
115110
public void onCreate(Bundle savedInstanceState) {
116111
super.onCreate(savedInstanceState);
@@ -244,33 +239,87 @@ protected void onDestroy() {
244239

245240
@OnClick(R.id.login_button)
246241
public void performLogin() {
247-
loginCurrentlyInProgress = true;
248242
Timber.d("Login to start!");
249243
final String username = usernameEdit.getText().toString();
250244
final String rawUsername = usernameEdit.getText().toString().trim();
251245
final String password = passwordEdit.getText().toString();
252246
String twoFactorCode = twoFactorEdit.getText().toString();
253247

254248
showLoggingProgressBar();
255-
compositeDisposable.add(Observable.fromCallable(() -> login(username, password, twoFactorCode))
256-
.subscribeOn(Schedulers.io())
257-
.observeOn(AndroidSchedulers.mainThread())
258-
.subscribe(result -> handleLogin(username, rawUsername, password, result)));
249+
doLogin(username, password, twoFactorCode);
259250
}
260251

261-
private String login(String username, String password, String twoFactorCode) {
262-
try {
263-
if (twoFactorCode.isEmpty()) {
264-
return mwApi.login(username, password);
265-
} else {
266-
return mwApi.login(username, password, twoFactorCode);
252+
private void doLogin(String username, String password, String twoFactorCode) {
253+
if (loginClient == null) {
254+
loginClient = new LoginClient();
255+
}
256+
progressDialog.show();
257+
258+
WikiSite wiki = new WikiSite(Uri.parse(AppAdapter.get().getMediaWikiBaseUrl()));
259+
if (!twoFactorCode.isEmpty()) {
260+
try {
261+
loginClient.login(wiki,
262+
username, password, null, twoFactorCode, firstStepToken, getCallback());
263+
} catch (Throwable throwable) {
264+
throwable.printStackTrace();
267265
}
268-
} catch (IOException e) {
269-
// Do something better!
270-
return "NetworkFailure";
266+
} else {
267+
loginClient.request(wiki, username, password, getCallback());
271268
}
272269
}
273270

271+
private LoginClient.LoginCallback getCallback() {
272+
return new LoginClient.LoginCallback() {
273+
@Override
274+
public void success(@NonNull LoginResult result) {
275+
if (!progressDialog.isShowing()) {
276+
// no longer attached to activity!
277+
return;
278+
}
279+
progressDialog.dismiss();
280+
if (result.pass()) {
281+
282+
Bundle extras = getIntent().getExtras();
283+
AccountAuthenticatorResponse response = extras == null ? null
284+
: extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
285+
286+
sessionManager.updateAccount(response, result);
287+
288+
onLoginSuccess();
289+
290+
} else if (result.fail()) {
291+
showMessageAndCancelDialog(result.getMessage());
292+
}
293+
}
294+
295+
@Override
296+
public void twoFactorPrompt(@NonNull Throwable caught, @Nullable String token) {
297+
if (!progressDialog.isShowing()) {
298+
// no longer attached to activity!
299+
return;
300+
}
301+
progressDialog.dismiss();
302+
firstStepToken = token;
303+
askUserForTwoFactorAuth();
304+
}
305+
306+
@Override
307+
public void passwordResetPrompt(@Nullable String token) {
308+
forgotPassword();
309+
}
310+
311+
@Override
312+
public void error(@NonNull Throwable caught) {
313+
if (!progressDialog.isShowing()) {
314+
// no longer attached to activity!
315+
return;
316+
}
317+
progressDialog.dismiss();
318+
showMessageAndCancelDialog(R.string.error_occurred);
319+
}
320+
};
321+
}
322+
274323
/**
275324
* This function is called when user skips the login.
276325
* It redirects the user to Explore Activity.
@@ -281,18 +330,6 @@ private void performSkipLogin() {
281330
finish();
282331
}
283332

284-
private void handleLogin(String username, String rawUsername, String password, String result) {
285-
Timber.d("Login done!");
286-
if (result.equals("PASS")) {
287-
handlePassResult(username, rawUsername, password);
288-
} else {
289-
loginCurrentlyInProgress = false;
290-
errorMessageShown = true;
291-
resultantError = result;
292-
handleOtherResults(result);
293-
}
294-
}
295-
296333
private void showLoggingProgressBar() {
297334
progressDialog = new ProgressDialog(this);
298335
progressDialog.setIndeterminate(true);
@@ -302,67 +339,11 @@ private void showLoggingProgressBar() {
302339
progressDialog.show();
303340
}
304341

305-
private void handlePassResult(String username, String rawUsername, String password) {
342+
private void onLoginSuccess() {
306343
showSuccessAndDismissDialog();
307-
requestAuthToken();
308-
AccountAuthenticatorResponse response = null;
309-
310-
Bundle extras = getIntent().getExtras();
311-
if (extras != null) {
312-
Timber.d("Bundle of extras: %s", extras);
313-
response = extras.getParcelable(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE);
314-
if (response != null) {
315-
Bundle authResult = new Bundle();
316-
authResult.putString(AccountManager.KEY_ACCOUNT_NAME, username);
317-
authResult.putString(AccountManager.KEY_ACCOUNT_TYPE, BuildConfig.ACCOUNT_TYPE);
318-
response.onResult(authResult);
319-
}
320-
}
321-
322-
sessionManager.createAccount(response, username, rawUsername, password);
323344
startMainActivity();
324345
}
325346

326-
protected void requestAuthToken() {
327-
AccountManager accountManager = AccountManager.get(this);
328-
Account curAccount = sessionManager.getCurrentAccount();
329-
if (curAccount != null) {
330-
accountManager.setAuthToken(curAccount, AUTH_TOKEN_TYPE, mwApi.getAuthCookie());
331-
}
332-
}
333-
334-
/**
335-
* Match known failure message codes and provide messages.
336-
*
337-
* @param result String
338-
*/
339-
private void handleOtherResults(String result) {
340-
if (result.equals("NetworkFailure")) {
341-
// Matches NetworkFailure which is created by the doInBackground method
342-
showMessageAndCancelDialog(R.string.login_failed_network);
343-
} else if (result.toLowerCase(Locale.getDefault()).contains("nosuchuser".toLowerCase()) || result.toLowerCase().contains("noname".toLowerCase())) {
344-
// Matches nosuchuser, nosuchusershort, noname
345-
showMessageAndCancelDialog(R.string.login_failed_wrong_credentials);
346-
emptySensitiveEditFields();
347-
} else if (result.toLowerCase(Locale.getDefault()).contains("wrongpassword".toLowerCase())) {
348-
// Matches wrongpassword, wrongpasswordempty
349-
showMessageAndCancelDialog(R.string.login_failed_wrong_credentials);
350-
emptySensitiveEditFields();
351-
} else if (result.toLowerCase(Locale.getDefault()).contains("throttle".toLowerCase())) {
352-
// Matches unknown throttle error codes
353-
showMessageAndCancelDialog(R.string.login_failed_throttled);
354-
} else if (result.toLowerCase(Locale.getDefault()).contains("userblocked".toLowerCase())) {
355-
// Matches login-userblocked
356-
showMessageAndCancelDialog(R.string.login_failed_blocked);
357-
} else if (result.equals("2FA")) {
358-
askUserForTwoFactorAuth();
359-
} else {
360-
// Occurs with unhandled login failure codes
361-
Timber.d("Login failed with reason: %s", result);
362-
showMessageAndCancelDialog(R.string.login_failed_generic);
363-
}
364-
}
365-
366347
@Override
367348
protected void onStart() {
368349
super.onStart();
@@ -402,30 +383,6 @@ public MenuInflater getMenuInflater() {
402383
return getDelegate().getMenuInflater();
403384
}
404385

405-
@Override
406-
protected void onSaveInstanceState(Bundle outState) {
407-
super.onSaveInstanceState(outState);
408-
outState.putBoolean(LOGGING_IN, loginCurrentlyInProgress);
409-
outState.putBoolean(ERROR_MESSAGE_SHOWN, errorMessageShown);
410-
outState.putString(RESULTANT_ERROR, resultantError);
411-
}
412-
413-
@Override
414-
protected void onRestoreInstanceState(Bundle savedInstanceState) {
415-
super.onRestoreInstanceState(savedInstanceState);
416-
loginCurrentlyInProgress = savedInstanceState.getBoolean(LOGGING_IN, false);
417-
errorMessageShown = savedInstanceState.getBoolean(ERROR_MESSAGE_SHOWN, false);
418-
if (loginCurrentlyInProgress) {
419-
performLogin();
420-
}
421-
if (errorMessageShown) {
422-
resultantError = savedInstanceState.getString(RESULTANT_ERROR);
423-
if (resultantError != null) {
424-
handleOtherResults(resultantError);
425-
}
426-
}
427-
}
428-
429386
public void askUserForTwoFactorAuth() {
430387
progressDialog.dismiss();
431388
twoFactorContainer.setVisibility(VISIBLE);
@@ -440,16 +397,18 @@ public void showMessageAndCancelDialog(@StringRes int resId) {
440397
}
441398
}
442399

400+
public void showMessageAndCancelDialog(String error) {
401+
showMessage(error, R.color.secondaryDarkColor);
402+
if (progressDialog != null) {
403+
progressDialog.cancel();
404+
}
405+
}
406+
443407
public void showSuccessAndDismissDialog() {
444408
showMessage(R.string.login_success, R.color.primaryDarkColor);
445409
progressDialog.dismiss();
446410
}
447411

448-
public void emptySensitiveEditFields() {
449-
passwordEdit.setText("");
450-
twoFactorEdit.setText("");
451-
}
452-
453412
public void startMainActivity() {
454413
NavigationBaseActivity.startActivityWithFlags(this, MainActivity.class, Intent.FLAG_ACTIVITY_SINGLE_TOP);
455414
finish();
@@ -461,6 +420,12 @@ private void showMessage(@StringRes int resId, @ColorRes int colorResId) {
461420
errorMessageContainer.setVisibility(VISIBLE);
462421
}
463422

423+
private void showMessage(String message, @ColorRes int colorResId) {
424+
errorMessage.setText(message);
425+
errorMessage.setTextColor(ContextCompat.getColor(this, colorResId));
426+
errorMessageContainer.setVisibility(VISIBLE);
427+
}
428+
464429
private AppCompatDelegate getDelegate() {
465430
if (delegate == null) {
466431
delegate = AppCompatDelegate.create(this, null);

0 commit comments

Comments
 (0)