implemented Push 2FA (approve request on official client)

This commit is contained in:
Mariotaku Lee 2015-11-14 22:33:36 +08:00
parent 3b16568474
commit b720abe8b2
6 changed files with 55 additions and 17 deletions

View File

@ -44,7 +44,7 @@ dependencies {
compile 'com.android.support:support-v4:23.1.0'
compile 'com.bluelinelabs:logansquare:1.1.0'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.github.mariotaku.RestFu:library:0.9.6'
compile 'com.github.mariotaku.RestFu:library:0.9.7'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
compile 'com.github.mariotaku:SQLiteQB:88291f3a28'
compile 'com.github.mariotaku.LoganSquareExtension:core:b6f53c9a4d'

View File

@ -93,8 +93,8 @@ dependencies {
compile 'com.soundcloud.android:android-crop:1.0.1@aar'
compile 'com.hannesdorfmann.parcelableplease:annotation:1.0.1'
compile 'com.github.mariotaku:PickNCrop:1dff3ed574'
compile 'com.github.mariotaku.RestFu:library:0.9.6'
compile 'com.github.mariotaku.RestFu:okhttp:0.9.6'
compile 'com.github.mariotaku.RestFu:library:0.9.7'
compile 'com.github.mariotaku.RestFu:okhttp:0.9.7'
compile 'com.diogobernardino:williamchart:2.0.1'
compile 'com.lnikkila:extendedtouchview:0.1.0'
compile 'com.google.dagger:dagger:2.0.1'

View File

@ -56,6 +56,7 @@ import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.meizu.flyme.reflect.StatusBarProxy;
@ -84,6 +85,7 @@ import org.mariotaku.twidere.util.ContentValuesCreator;
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator;
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.AuthenticationException;
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.AuthenticityTokenException;
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.LoginVerificationException;
import org.mariotaku.twidere.util.OAuthPasswordAuthenticator.WrongUserPassException;
import org.mariotaku.twidere.util.ParseUtils;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
@ -459,6 +461,8 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show();
} else if (result.exception instanceof WrongUserPassException) {
Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show();
} else if (result.exception instanceof LoginVerificationException) {
Toast.makeText(this, R.string.login_verification_failed, Toast.LENGTH_SHORT).show();
} else if (result.exception instanceof AuthenticationException) {
showErrorMessage(this, getString(R.string.action_signing_in), result.exception.getCause(), true);
} else {
@ -790,7 +794,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
String challengeResponse;
@Override
public String getLoginVerification() {
public String getLoginVerification(final String challengeType) {
// Dismiss current progress dialog
publishProgress(new Runnable() {
@Override
@ -807,6 +811,7 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
public void run() {
InputLoginVerificationDialogFragment df = new InputLoginVerificationDialogFragment();
df.setCallback(InputLoginVerificationCallback.this);
df.setChallengeType(challengeType);
df.show(activity.getSupportFragmentManager(), null);
}
});
@ -840,9 +845,10 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
}
public static class InputLoginVerificationDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener {
public static class InputLoginVerificationDialogFragment extends BaseSupportDialogFragment implements DialogInterface.OnClickListener, DialogInterface.OnShowListener {
private SignInTask.InputLoginVerificationCallback callback;
private String challengeType;
public void setCallback(SignInTask.InputLoginVerificationCallback callback) {
this.callback = callback;
@ -862,7 +868,9 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
builder.setView(R.layout.dialog_login_verification_code);
builder.setPositiveButton(android.R.string.ok, this);
builder.setNegativeButton(android.R.string.cancel, this);
return builder.create();
final AlertDialog dialog = builder.create();
dialog.setOnShowListener(this);
return dialog;
}
@Override
@ -880,6 +888,24 @@ public class SignInActivity extends BaseAppCompatActivity implements OnClickList
}
}
}
public void setChallengeType(String challengeType) {
this.challengeType = challengeType;
}
@Override
public void onShow(DialogInterface dialog) {
final AlertDialog alertDialog = (AlertDialog) dialog;
final TextView verificationHint = (TextView) alertDialog.findViewById(R.id.verification_hint);
final EditText editVerification = (EditText) alertDialog.findViewById(R.id.edit_verification_code);
if ("Push".equalsIgnoreCase(challengeType)) {
verificationHint.setText(R.string.login_verification_push_hint);
editVerification.setVisibility(View.GONE);
} else {
verificationHint.setText(R.string.login_verification_pin_hint);
editVerification.setVisibility(View.VISIBLE);
}
}
}
static class SignInResponse {

View File

@ -19,6 +19,7 @@
package org.mariotaku.twidere.util;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.squareup.okhttp.HttpUrl;
@ -53,6 +54,7 @@ import org.mariotaku.twidere.model.RequestType;
import java.io.IOException;
import java.io.Reader;
import java.net.CookieManager;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -84,8 +86,8 @@ public class OAuthPasswordAuthenticator implements Constants {
}
final String location = response.header("Location");
final Response.Builder builder = response.newBuilder();
if (!TextUtils.isEmpty(location)) {
final HttpUrl originalLocation = HttpUrl.parse(location);
if (!TextUtils.isEmpty(location) && !endpoint.checkEndpoint(location)) {
final HttpUrl originalLocation = HttpUrl.get(URI.create("https://api.twitter.com/").resolve(location));
final HttpUrl.Builder locationBuilder = HttpUrl.parse(endpoint.getUrl()).newBuilder();
for (String pathSegments : originalLocation.pathSegments()) {
locationBuilder.addPathSegment(pathSegments);
@ -130,12 +132,14 @@ public class OAuthPasswordAuthenticator implements Constants {
throw new WrongUserPassException();
}
// Go to password verification flow
final String challengeType = authorizeResponseData.verification.challengeType;
final String loginVerification = loginVerificationCallback.getLoginVerification(challengeType);
final AuthorizeRequestData verificationData = getVerificationData(authorizeResponseData,
loginVerificationCallback.getLoginVerification());
loginVerification);
authorizeResponseData = getAuthorizeResponseData(requestToken,
verificationData, username, password);
if (TextUtils.isEmpty(authorizeResponseData.oauthPin)) {
throw new VerificationCodeException();
throw new LoginVerificationException();
}
return oauth.getAccessToken(requestToken, authorizeResponseData.oauthPin);
} catch (final IOException | NullPointerException | TwitterException e) {
@ -144,7 +148,7 @@ public class OAuthPasswordAuthenticator implements Constants {
}
private AuthorizeRequestData getVerificationData(AuthorizeResponseData authorizeResponseData,
String challengeResponse) throws IOException, VerificationCodeException {
@Nullable String challengeResponse) throws IOException, LoginVerificationException {
RestHttpResponse response = null;
try {
final AuthorizeRequestData data = new AuthorizeRequestData();
@ -159,7 +163,9 @@ public class OAuthPasswordAuthenticator implements Constants {
final ArrayList<Pair<String, String>> requestHeaders = new ArrayList<>();
requestHeaders.add(Pair.create("User-Agent", userAgent));
params.add(Pair.create("challenge_response", challengeResponse));
if (!TextUtils.isEmpty(challengeResponse)) {
params.add(Pair.create("challenge_response", challengeResponse));
}
final FormTypedBody authorizationResultBody = new FormTypedBody(params);
final RestHttpRequest.Builder authorizeResultBuilder = new RestHttpRequest.Builder();
@ -170,9 +176,12 @@ public class OAuthPasswordAuthenticator implements Constants {
authorizeResultBuilder.extra(RequestType.API);
response = client.execute(authorizeResultBuilder.build());
parseAuthorizeRequestData(response, data);
if (TextUtils.isEmpty(data.authenticityToken)) {
throw new LoginVerificationException();
}
return data;
} catch (AttoParseException e) {
throw new VerificationCodeException();
throw new LoginVerificationException();
} finally {
Utils.closeSilently(response);
}
@ -440,7 +449,7 @@ public class OAuthPasswordAuthenticator implements Constants {
}
public interface LoginVerificationCallback {
String getLoginVerification();
String getLoginVerification(String challengeType);
}
public static class AuthenticationException extends Exception {
@ -469,7 +478,7 @@ public class OAuthPasswordAuthenticator implements Constants {
}
public static final class VerificationCodeException extends AuthenticationException {
public static final class LoginVerificationException extends AuthenticationException {
}

View File

@ -25,9 +25,10 @@
<TextView
android:layout_width="match_parent"
android:id="@+id/verification_hint"
android:layout_height="wrap_content"
android:layout_margin="@dimen/element_spacing_normal"
android:text="@string/login_verification_hint" />
android:text="@string/login_verification_pin_hint" />
<EditText
android:id="@+id/edit_verification_code"

View File

@ -820,5 +820,7 @@
<string name="copy_link">Copy link</string>
<string name="link_copied_to_clipboard">Link copied to clipboard</string>
<string name="login_verification">Login verification</string>
<string name="login_verification_hint">Please check your phone for a PIN code and enter it to log in.</string>
<string name="login_verification_pin_hint">Check your phone for a PIN code and enter it to log in.</string>
<string name="login_verification_push_hint">Accept login verification request from Twitter app, once you approved the request, click OK.</string>
<string name="login_verification_failed">Login verification failed.</string>
</resources>