Peertube 2FA support

This commit is contained in:
Thomas 2023-01-30 17:02:24 +01:00
parent 9fd834eb44
commit 408e51c0a6
6 changed files with 58 additions and 23 deletions

View file

@ -17,18 +17,12 @@ package app.fedilab.android.peertube.activities;
import static app.fedilab.android.peertube.client.RetrofitPeertubeAPI.updateCredential; import static app.fedilab.android.peertube.client.RetrofitPeertubeAPI.updateCredential;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.Patterns; import android.util.Patterns;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -160,6 +154,7 @@ public class LoginActivity extends BaseBarActivity {
oauthParams.setClient_secret(client_secret); oauthParams.setClient_secret(client_secret);
oauthParams.setGrant_type("password"); oauthParams.setGrant_type("password");
oauthParams.setScope("user"); oauthParams.setScope("user");
oauthParams.x_peertube_otp = binding.loginOtp.getText().toString().isEmpty() ? null : binding.loginOtp.getText().toString();
if (binding.loginUid.getText() != null) { if (binding.loginUid.getText() != null) {
oauthParams.setUsername(binding.loginUid.getText().toString().trim()); oauthParams.setUsername(binding.loginUid.getText().toString().trim());
} }
@ -169,24 +164,23 @@ public class LoginActivity extends BaseBarActivity {
try { try {
Token token = new RetrofitPeertubeAPI(LoginActivity.this, finalInstance, null).manageToken(oauthParams); Token token = new RetrofitPeertubeAPI(LoginActivity.this, finalInstance, null).manageToken(oauthParams);
proceedLogin(token, finalInstance); proceedLogin(token, finalInstance);
} catch (final Exception e) {
oauthParams.setUsername(binding.loginUid.getText().toString().toLowerCase().trim());
Token token = null;
try {
token = new RetrofitPeertubeAPI(LoginActivity.this, finalInstance, null).manageToken(oauthParams);
} catch (Error ex) {
ex.printStackTrace();
}
proceedLogin(token, finalInstance);
} catch (Error e) { } catch (Error e) {
if (e.getError() != null && e.getError().contains("missing_two_factor")) {
runOnUiThread(() -> {
binding.loginOtpContainer.setVisibility(View.VISIBLE);
binding.loginOtp.setFocusable(true);
binding.loginOtp.requestFocus();
binding.loginButton.setEnabled(true);
});
} else {
runOnUiThread(() -> { runOnUiThread(() -> {
Toasty.error(LoginActivity.this, e.getError() != null && !e.getError().isEmpty() ? e.getError() : getString(R.string.toast_error), Toasty.LENGTH_SHORT).show(); Toasty.error(LoginActivity.this, e.getError() != null && !e.getError().isEmpty() ? e.getError() : getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
binding.loginButton.setEnabled(true); binding.loginButton.setEnabled(true);
}); });
e.printStackTrace(); e.printStackTrace();
} }
} }
}
@SuppressLint("ApplySharedPref") @SuppressLint("ApplySharedPref")

View file

@ -122,6 +122,18 @@ public interface PeertubeService {
@Field("password") String password, @Field("password") String password,
@Field("externalAuthToken") String externalAuthToken); @Field("externalAuthToken") String externalAuthToken);
@FormUrlEncoded
@POST("users/token")
Call<Token> otpConnetion(
@Header("x-peertube-otp") String externalAuthToken,
@Field("client_id") String client_id,
@Field("client_secret") String client_secret,
@Field("response_type") String response_type,
@Field("grant_type") String grant_type,
@Field("scope") String scope,
@Field("username") String username,
@Field("password") String password);
//TOKEN //TOKEN
//Refresh //Refresh
@FormUrlEncoded @FormUrlEncoded

View file

@ -267,7 +267,9 @@ public class RetrofitPeertubeAPI {
public Token manageToken(OauthParams oauthParams) throws Error { public Token manageToken(OauthParams oauthParams) throws Error {
PeertubeService peertubeService = init(); PeertubeService peertubeService = init();
Call<Token> refreshTokenCall = null; Call<Token> refreshTokenCall = null;
if (oauthParams.getGrant_type().compareTo("password") == 0) { if (oauthParams.x_peertube_otp != null) {
refreshTokenCall = peertubeService.otpConnetion(oauthParams.x_peertube_otp, oauthParams.getClient_id(), oauthParams.getClient_secret(), "code", oauthParams.getGrant_type(), "upload", oauthParams.getUsername(), oauthParams.getPassword());
} else if (oauthParams.getGrant_type().compareTo("password") == 0) {
refreshTokenCall = peertubeService.createToken(oauthParams.getClient_id(), oauthParams.getClient_secret(), oauthParams.getGrant_type(), oauthParams.getUsername(), oauthParams.getPassword()); refreshTokenCall = peertubeService.createToken(oauthParams.getClient_id(), oauthParams.getClient_secret(), oauthParams.getGrant_type(), oauthParams.getUsername(), oauthParams.getPassword());
} else if (oauthParams.getGrant_type().compareTo("refresh_token") == 0) { } else if (oauthParams.getGrant_type().compareTo("refresh_token") == 0) {
refreshTokenCall = peertubeService.refreshToken(oauthParams.getClient_id(), oauthParams.getClient_secret(), oauthParams.getRefresh_token(), oauthParams.getGrant_type()); refreshTokenCall = peertubeService.refreshToken(oauthParams.getClient_id(), oauthParams.getClient_secret(), oauthParams.getRefresh_token(), oauthParams.getGrant_type());

View file

@ -44,6 +44,9 @@ public class OauthParams {
private String code; private String code;
@SerializedName("redirect_uri") @SerializedName("redirect_uri")
private String redirect_uri; private String redirect_uri;
@SerializedName("x_peertube_otp")
public String x_peertube_otp;
public String getClient_secret() { public String getClient_secret() {
return client_secret; return client_secret;

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="otp_message">Two factor authentication token</string>
</resources>

View file

@ -18,6 +18,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:padding="24dp"> android:padding="24dp">
@ -73,6 +74,25 @@
android:singleLine="true" /> android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/login_otp_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:visibility="gone"
app:passwordToggleEnabled="true"
tools:visibility="visible">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/login_otp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/otp_message"
android:importantForAutofill="no"
android:inputType="numberPassword"
android:singleLine="true" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/login_button" android:id="@+id/login_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -81,6 +101,6 @@
android:text="@string/login" android:text="@string/login"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/login_passwd_container" /> app:layout_constraintTop_toBottomOf="@id/login_otp_container" />
</androidx.appcompat.widget.LinearLayoutCompat> </androidx.appcompat.widget.LinearLayoutCompat>