this commit tries to solve #146 it'll remain open until the OP confirms on the fix.

This commit is contained in:
Kosh 2017-03-18 09:50:23 +08:00
parent a1d2089e1a
commit b0be783205
6 changed files with 43 additions and 59 deletions

View File

@ -24,6 +24,7 @@ public class AuthModel implements Parcelable {
private List<String> scopes;
private String state;
private String note;
private String noteUr;
@SerializedName("X-GitHub-OTP") private String otpCode;
@Override public int describeContents() { return 0; }
@ -35,6 +36,8 @@ public class AuthModel implements Parcelable {
dest.writeStringList(this.scopes);
dest.writeString(this.state);
dest.writeString(this.note);
dest.writeString(this.noteUr);
dest.writeString(this.otpCode);
}
protected AuthModel(Parcel in) {
@ -44,6 +47,8 @@ public class AuthModel implements Parcelable {
this.scopes = in.createStringArrayList();
this.state = in.readString();
this.note = in.readString();
this.noteUr = in.readString();
this.otpCode = in.readString();
}
public static final Creator<AuthModel> CREATOR = new Creator<AuthModel>() {

View File

@ -5,25 +5,11 @@ import android.support.annotation.NonNull;
import com.fastaccess.data.dao.AccessTokenModel;
import com.fastaccess.data.dao.AuthModel;
import retrofit2.Response;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Header;
import retrofit2.http.PUT;
import retrofit2.http.Path;
import retrofit2.http.POST;
import rx.Observable;
public interface LoginRestService {
@PUT("authorizations/clients/{clientId}/{fingerprint}")
Observable<AccessTokenModel> login(@NonNull @Path("clientId") String clientId,
@NonNull @Path("clientId") String fingerprint,
@NonNull @Body AuthModel authModel);
@PUT("authorizations/clients/{clientId}/{fingerprint}")
Observable<AccessTokenModel> login(@NonNull @Path("clientId") String clientId,
@NonNull @Path("clientId") String fingerprint,
@NonNull @Body AuthModel authModel,
@NonNull @Header("X-GitHub-OTP") String otpCode);
@DELETE("authorizations/{id}") Observable<Response<Boolean>> deleteToken(@Path("id") long id);
@POST("authorizations") Observable<AccessTokenModel> login(@NonNull @Body AuthModel authModel);
}

View File

@ -1,6 +1,7 @@
package com.fastaccess.provider.rest;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.fastaccess.BuildConfig;
import com.fastaccess.data.service.LoginRestService;
@ -30,26 +31,26 @@ public class LoginProvider {
.setPrettyPrinting()
.create();
private static OkHttpClient provideOkHttpClient(@NonNull String authToken) {
private static OkHttpClient provideOkHttpClient(@NonNull String authToken, @Nullable String otp) {
OkHttpClient.Builder client = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
client.addInterceptor(new HttpLoggingInterceptor()
.setLevel(HttpLoggingInterceptor.Level.BODY));
}
client.addInterceptor(new AuthenticationInterceptor(authToken));
client.addInterceptor(new AuthenticationInterceptor(authToken, otp));
return client.build();
}
private static Retrofit provideRetrofit(@NonNull String authToken) {
private static Retrofit provideRetrofit(@NonNull String authToken, @Nullable String otp) {
return new Retrofit.Builder()
.baseUrl(BuildConfig.REST_URL)
.client(provideOkHttpClient(authToken))
.client(provideOkHttpClient(authToken, otp))
.addConverterFactory(new GithubResponseConverter(gson))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
@NonNull public static LoginRestService getLoginRestService(@NonNull String authToken) {
return provideRetrofit(authToken).create(LoginRestService.class);
@NonNull public static LoginRestService getLoginRestService(@NonNull String authToken, @Nullable String otp) {
return provideRetrofit(authToken, otp).create(LoginRestService.class);
}
}

View File

@ -1,5 +1,7 @@
package com.fastaccess.provider.rest.interceptors;
import com.fastaccess.helper.InputHelper;
import java.io.IOException;
import lombok.AllArgsConstructor;
@ -11,10 +13,14 @@ import okhttp3.Response;
public class AuthenticationInterceptor implements Interceptor {
private String authToken;
private String otp;
@Override public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder().header("Authorization", authToken);
if (!InputHelper.isEmpty(otp)) {
builder.addHeader("X-GitHub-OTP", otp.trim());
}
Request request = builder.build();
return chain.proceed(request);
}

View File

@ -1,6 +1,5 @@
package com.fastaccess.ui.modules.login;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@ -16,11 +15,9 @@ import com.fastaccess.provider.rest.RestProvider;
import com.fastaccess.ui.base.mvp.presenter.BasePresenter;
import java.util.Arrays;
import java.util.UUID;
import okhttp3.Credentials;
import retrofit2.adapter.rxjava.HttpException;
import rx.Observable;
/**
* Created by Kosh on 09 Nov 2016, 9:43 PM
@ -28,6 +25,23 @@ import rx.Observable;
class LoginPresenter extends BasePresenter<LoginMvp.View> implements LoginMvp.Presenter {
@Override public void onError(@NonNull Throwable throwable) {
if (RestProvider.getErrorCode(throwable) == 401 && throwable instanceof HttpException) {
retrofit2.Response response = ((HttpException) throwable).response();
if (response != null && response.headers() != null) {
String twoFaToken = response.headers().get("X-GitHub-OTP");
if (twoFaToken != null) {
sendToView(LoginMvp.View::onRequire2Fa);
return;
} else {
sendToView(view -> view.showMessage(R.string.error, R.string.failed_login));
return;
}
}
}
super.onError(throwable);
}
@Override public void onTokenResponse(@Nullable AccessTokenModel modelResponse) {
if (modelResponse != null) {
String token = modelResponse.getToken();
@ -57,46 +71,17 @@ class LoginPresenter extends BasePresenter<LoginMvp.View> implements LoginMvp.Pr
getView().onEmptyUserName(usernameIsEmpty);
getView().onEmptyPassword(passwordIsEmpty);
if (!usernameIsEmpty && !passwordIsEmpty) {
UUID uuid = UUID.randomUUID();
String authToken = Credentials.basic(username, password);
AuthModel authModel = new AuthModel();
authModel.setScopes(Arrays.asList("user", "repo", "gist", "notifications"));
String uniqueToken = BuildConfig.APPLICATION_ID + "-" + authToken + "-" + Build.MODEL + "-" + uuid;
authModel.setNote(uniqueToken);//make it unique to FastHub.
authModel.setNote(BuildConfig.APPLICATION_ID);
authModel.setClientSecret(BuildConfig.GITHUB_SECRET);
Observable<AccessTokenModel> loginCall = LoginProvider.getLoginRestService(authToken)
.login(BuildConfig.GITHUB_CLIENT_ID, uniqueToken, authModel);
authModel.setClientId(BuildConfig.GITHUB_CLIENT_ID);
authModel.setNoteUr(BuildConfig.REDIRECT_URL);
if (!InputHelper.isEmpty(twoFactorCode)) {
loginCall = LoginProvider.getLoginRestService(authToken)
.login(BuildConfig.GITHUB_CLIENT_ID, uniqueToken, authModel, twoFactorCode);
authModel.setOtpCode(twoFactorCode);
}
makeRestCall(loginCall, tokenModel -> {
if (InputHelper.isEmpty(tokenModel.getToken())) {
makeRestCall(LoginProvider.getLoginRestService(authToken).deleteToken(tokenModel.getId()),
response -> login(username, password, null));
} else {
onTokenResponse(tokenModel);
}
});
makeRestCall(LoginProvider.getLoginRestService(authToken, twoFactorCode).login(authModel), this::onTokenResponse);
}
}
@Override public void onError(@NonNull Throwable throwable) {
if (RestProvider.getErrorCode(throwable) == 401) {
retrofit2.Response response = ((HttpException) throwable).response();
if (response != null && response.headers() != null) {
String twoFaToken = response.headers().get("X-GitHub-OTP");
if (twoFaToken != null) {
sendToView(LoginMvp.View::onRequire2Fa);
return;
} else {
sendToView(view -> {
view.showMessage(R.string.error, R.string.failed_login);
});
return;
}
}
}
super.onError(throwable);
}
}

View File

@ -26,6 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:minHeight="150dp"
android:paddingEnd="@dimen/spacing_xs_large"
android:paddingStart="@dimen/spacing_xs_large">