Add authentication #689

This commit is contained in:
stom79 2019-01-02 19:39:40 +01:00
parent 6b623e96bf
commit eebe401aaf
10 changed files with 4024 additions and 21 deletions

View File

@ -91,6 +91,9 @@ public class LoginActivity extends BaseActivity {
boolean isLoadingInstance = false; boolean isLoadingInstance = false;
private String oldSearch; private String oldSearch;
private ImageView info_uid, info_instance, info_pwd, info_2FA; private ImageView info_uid, info_instance, info_pwd, info_2FA;
private CheckBox peertube_instance;
private Button connectionButton;
private String actionToken;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -122,7 +125,7 @@ public class LoginActivity extends BaseActivity {
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token); editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
editor.apply(); editor.apply();
//Update the account with the token; //Update the account with the token;
new UpdateAccountInfoAsyncTask(LoginActivity.this, token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new UpdateAccountInfoAsyncTask(LoginActivity.this, token, instance, peertube_instance.isChecked()?UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE:UpdateAccountInfoAsyncTask.SOCIAL.MASTODON).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (JSONException ignored) {} } catch (JSONException ignored) {}
} catch (Exception ignored) {} } catch (Exception ignored) {}
}}).start(); }}).start();
@ -171,7 +174,7 @@ public class LoginActivity extends BaseActivity {
} else { } else {
changeDrawableColor(getApplicationContext(), R.drawable.mastodon_icon, R.color.mastodonC3); changeDrawableColor(getApplicationContext(), R.drawable.mastodon_icon, R.color.mastodonC3);
} }
final Button connectionButton = findViewById(R.id.login_button);
login_instance = findViewById(R.id.login_instance); login_instance = findViewById(R.id.login_instance);
login_uid = findViewById(R.id.login_uid); login_uid = findViewById(R.id.login_uid);
login_passwd = findViewById(R.id.login_passwd); login_passwd = findViewById(R.id.login_passwd);
@ -179,6 +182,8 @@ public class LoginActivity extends BaseActivity {
info_instance = findViewById(R.id.info_instance); info_instance = findViewById(R.id.info_instance);
info_pwd = findViewById(R.id.info_pwd); info_pwd = findViewById(R.id.info_pwd);
info_2FA = findViewById(R.id.info_2FA); info_2FA = findViewById(R.id.info_2FA);
peertube_instance = findViewById(R.id.peertube_instance);
connectionButton = findViewById(R.id.login_button);
info_instance.setOnClickListener(new View.OnClickListener() { info_instance.setOnClickListener(new View.OnClickListener() {
@Override @Override
@ -309,6 +314,7 @@ public class LoginActivity extends BaseActivity {
startActivity(browserIntent); startActivity(browserIntent);
} }
}); });
login_instance.setOnFocusChangeListener(new View.OnFocusChangeListener() { login_instance.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override @Override
public void onFocusChange(View v, boolean hasFocus) { public void onFocusChange(View v, boolean hasFocus) {
@ -369,7 +375,7 @@ public class LoginActivity extends BaseActivity {
@Override @Override
protected void onResume(){ protected void onResume(){
super.onResume(); super.onResume();
Button connectionButton = findViewById(R.id.login_button);
if (login_instance != null &&login_instance.getText() != null && login_instance.getText().toString().length() > 0 && client_id_for_webview) { if (login_instance != null &&login_instance.getText() != null && login_instance.getText().toString().length() > 0 && client_id_for_webview) {
connectionButton.setEnabled(false); connectionButton.setEnabled(false);
client_id_for_webview = false; client_id_for_webview = false;
@ -378,24 +384,35 @@ public class LoginActivity extends BaseActivity {
} }
private void retrievesClientId(){ private void retrievesClientId(){
final Button connectionButton = findViewById(R.id.login_button);
try { try {
instance = URLEncoder.encode(login_instance.getText().toString().trim(), "utf-8"); instance = URLEncoder.encode(login_instance.getText().toString().trim(), "utf-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
Toasty.error(LoginActivity.this,getString(R.string.client_error), Toast.LENGTH_LONG).show(); Toasty.error(LoginActivity.this,getString(R.string.client_error), Toast.LENGTH_LONG).show();
} }
final String action = "/api/v1/apps"; if( !peertube_instance.isChecked())
actionToken = "/api/v1/apps";
else
actionToken = "/api/v1/oauth-clients/local";
final HashMap<String, String> parameters = new HashMap<>(); final HashMap<String, String> parameters = new HashMap<>();
parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE); parameters.put(Helper.CLIENT_NAME, Helper.CLIENT_NAME_VALUE);
parameters.put(Helper.REDIRECT_URIS, client_id_for_webview?Helper.REDIRECT_CONTENT_WEB:Helper.REDIRECT_CONTENT); parameters.put(Helper.REDIRECT_URIS, client_id_for_webview?Helper.REDIRECT_CONTENT_WEB:Helper.REDIRECT_CONTENT);
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES); if( !peertube_instance.isChecked()) {
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES);
}else {
parameters.put(Helper.SCOPES, Helper.OAUTH_SCOPES_PEERTUBE);
}
parameters.put(Helper.WEBSITE, Helper.WEBSITE_VALUE); parameters.put(Helper.WEBSITE, Helper.WEBSITE_VALUE);
new Thread(new Runnable(){ new Thread(new Runnable(){
@Override @Override
public void run() { public void run() {
try { try {
final String response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + action, 30, parameters, null ); String response;
if( !peertube_instance.isChecked())
response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + actionToken, 30, parameters, null );
else
response = new HttpsConnection(LoginActivity.this).get(Helper.instanceWithProtocol(instance) + actionToken, 30, parameters, null );
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
JSONObject resobj; JSONObject resobj;
@ -403,7 +420,9 @@ public class LoginActivity extends BaseActivity {
resobj = new JSONObject(response); resobj = new JSONObject(response);
client_id = resobj.get(Helper.CLIENT_ID).toString(); client_id = resobj.get(Helper.CLIENT_ID).toString();
client_secret = resobj.get(Helper.CLIENT_SECRET).toString(); client_secret = resobj.get(Helper.CLIENT_SECRET).toString();
String id = resobj.get(Helper.ID).toString(); String id = null;
if( !peertube_instance.isChecked())
id = resobj.get(Helper.ID).toString();
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit(); SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(Helper.CLIENT_ID, client_id); editor.putString(Helper.CLIENT_ID, client_id);
@ -418,6 +437,7 @@ public class LoginActivity extends BaseActivity {
boolean embedded_browser = sharedpreferences.getBoolean(Helper.SET_EMBEDDED_BROWSER, true); boolean embedded_browser = sharedpreferences.getBoolean(Helper.SET_EMBEDDED_BROWSER, true);
if( embedded_browser) { if( embedded_browser) {
Intent i = new Intent(LoginActivity.this, WebviewConnectActivity.class); Intent i = new Intent(LoginActivity.this, WebviewConnectActivity.class);
i.putExtra("social", peertube_instance.isChecked()?UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE:UpdateAccountInfoAsyncTask.SOCIAL.MASTODON);
i.putExtra("instance", instance); i.putExtra("instance", instance);
startActivity(i); startActivity(i);
}else{ }else{
@ -471,13 +491,19 @@ public class LoginActivity extends BaseActivity {
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
parameters.put("password",login_passwd.getText().toString()); parameters.put("password",login_passwd.getText().toString());
} }
parameters.put("scope"," read write follow"); String oauthUrl;
if( !peertube_instance.isChecked()) {
parameters.put("scope", " read write follow");
oauthUrl = "/oauth/token";
}else {
parameters.put("scope", "user");
oauthUrl = "/api/v1/users/token";
}
new Thread(new Runnable(){ new Thread(new Runnable(){
@Override @Override
public void run() { public void run() {
try { try {
final String response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + "/oauth/token", 30, parameters, null ); final String response = new HttpsConnection(LoginActivity.this).post(Helper.instanceWithProtocol(instance) + oauthUrl, 30, parameters, null );
runOnUiThread(new Runnable() { runOnUiThread(new Runnable() {
public void run() { public void run() {
JSONObject resobj; JSONObject resobj;
@ -489,7 +515,7 @@ public class LoginActivity extends BaseActivity {
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token); editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
editor.apply(); editor.apply();
//Update the account with the token; //Update the account with the token;
new UpdateAccountInfoAsyncTask(LoginActivity.this, token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new UpdateAccountInfoAsyncTask(LoginActivity.this, token, instance, peertube_instance.isChecked()?UpdateAccountInfoAsyncTask.SOCIAL.PEERTUBE:UpdateAccountInfoAsyncTask.SOCIAL.MASTODON).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (JSONException ignored) {ignored.printStackTrace();} } catch (JSONException ignored) {ignored.printStackTrace();}
} }
}); });

View File

@ -63,6 +63,7 @@ public class WebviewConnectActivity extends BaseActivity {
private AlertDialog alert; private AlertDialog alert;
private String clientId, clientSecret; private String clientId, clientSecret;
private String instance; private String instance;
private UpdateAccountInfoAsyncTask.SOCIAL social;
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -84,8 +85,10 @@ public class WebviewConnectActivity extends BaseActivity {
setContentView(R.layout.activity_webview_connect); setContentView(R.layout.activity_webview_connect);
Bundle b = getIntent().getExtras(); Bundle b = getIntent().getExtras();
if(b != null) if(b != null) {
instance = b.getString("instance"); instance = b.getString("instance");
social = (UpdateAccountInfoAsyncTask.SOCIAL) b.getSerializable("social");
}
if( instance == null) if( instance == null)
finish(); finish();
clientId = sharedpreferences.getString(Helper.CLIENT_ID, null); clientId = sharedpreferences.getString(Helper.CLIENT_ID, null);
@ -167,7 +170,7 @@ public class WebviewConnectActivity extends BaseActivity {
editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token); editor.putString(Helper.PREF_KEY_OAUTH_TOKEN, token);
editor.apply(); editor.apply();
//Update the account with the token; //Update the account with the token;
new UpdateAccountInfoAsyncTask(WebviewConnectActivity.this, token, instance).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new UpdateAccountInfoAsyncTask(WebviewConnectActivity.this, token, instance, social).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} catch (JSONException ignored) {} } catch (JSONException ignored) {}
} catch (Exception ignored) {} } catch (Exception ignored) {}
}}).start(); }}).start();

View File

@ -28,9 +28,10 @@ import java.net.URLDecoder;
import fr.gouv.etalab.mastodon.activities.MainActivity; import fr.gouv.etalab.mastodon.activities.MainActivity;
import fr.gouv.etalab.mastodon.client.API; import fr.gouv.etalab.mastodon.client.API;
import fr.gouv.etalab.mastodon.client.Entities.Account; import fr.gouv.etalab.mastodon.client.Entities.Account;
import fr.gouv.etalab.mastodon.client.PeertubeAPI;
import fr.gouv.etalab.mastodon.helper.Helper; import fr.gouv.etalab.mastodon.helper.Helper;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
import fr.gouv.etalab.mastodon.sqlite.AccountDAO; import fr.gouv.etalab.mastodon.sqlite.AccountDAO;
import fr.gouv.etalab.mastodon.sqlite.Sqlite;
/** /**
* Created by Thomas on 23/04/2017. * Created by Thomas on 23/04/2017.
@ -42,16 +43,30 @@ public class UpdateAccountInfoAsyncTask extends AsyncTask<Void, Void, Void> {
private String token; private String token;
private String instance; private String instance;
private WeakReference<Context> contextReference; private WeakReference<Context> contextReference;
private SOCIAL social;
public UpdateAccountInfoAsyncTask(Context context, String token, String instance){ public enum SOCIAL{
MASTODON,
PEERTUBE
}
public UpdateAccountInfoAsyncTask(Context context, String token, String instance, SOCIAL social){
this.contextReference = new WeakReference<>(context); this.contextReference = new WeakReference<>(context);
this.token = token; this.token = token;
this.instance = instance; this.instance = instance;
this.social = social;
} }
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
Account account = new API(this.contextReference.get(), instance, null).verifyCredentials(); Account account = null;
if( social == SOCIAL.MASTODON)
account = new API(this.contextReference.get(), instance, null).verifyCredentials();
else if( social == SOCIAL.PEERTUBE)
account = new PeertubeAPI(this.contextReference.get(), instance, null).verifyCredentials();
if( account == null)
return null;
try { try {
//At the state the instance can be encoded //At the state the instance can be encoded
instance = URLDecoder.decode(instance, "utf-8"); instance = URLDecoder.decode(instance, "utf-8");

View File

@ -104,6 +104,7 @@ public class Account implements Parcelable {
private List<Emojis> emojis; private List<Emojis> emojis;
private String host; private String host;
private boolean isBot; private boolean isBot;
private String social;
protected Account(Parcel in) { protected Account(Parcel in) {
id = in.readString(); id = in.readString();
@ -270,6 +271,14 @@ public class Account implements Parcelable {
this.stored_displayname = stored_displayname; this.stored_displayname = stored_displayname;
} }
public String getSocial() {
return social;
}
public void setSocial(String social) {
this.social = social;
}
public enum followAction{ public enum followAction{
FOLLOW, FOLLOW,

File diff suppressed because it is too large Load Diff

View File

@ -193,7 +193,10 @@ public class Helper {
public static final String TAG = "mastodon_etalab"; public static final String TAG = "mastodon_etalab";
public static final String CLIENT_NAME_VALUE = "Mastalab"; public static final String CLIENT_NAME_VALUE = "Mastalab";
public static final String OAUTH_SCOPES = "read write follow"; public static final String OAUTH_SCOPES = "read write follow";
public static final String OAUTH_SCOPES_PEERTUBE = "user";
public static final String PREF_KEY_OAUTH_TOKEN = "oauth_token"; public static final String PREF_KEY_OAUTH_TOKEN = "oauth_token";
public static final String PREF_KEY_ID = "userID"; public static final String PREF_KEY_ID = "userID";
public static final String PREF_INSTANCE = "instance"; public static final String PREF_INSTANCE = "instance";
public static final String REDIRECT_CONTENT = "urn:ietf:wg:oauth:2.0:oob"; public static final String REDIRECT_CONTENT = "urn:ietf:wg:oauth:2.0:oob";

View File

@ -69,6 +69,7 @@ public class AccountDAO {
values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(account.getCreated_at())); values.put(Sqlite.COL_CREATED_AT, Helper.dateToString(account.getCreated_at()));
values.put(Sqlite.COL_INSTANCE, account.getInstance()); values.put(Sqlite.COL_INSTANCE, account.getInstance());
values.put(Sqlite.COL_EMOJIS, Helper.emojisToStringStorage(account.getEmojis())); values.put(Sqlite.COL_EMOJIS, Helper.emojisToStringStorage(account.getEmojis()));
values.put(Sqlite.COL_SOCIAL, account.getSocial());
if( account.getToken() != null) if( account.getToken() != null)
values.put(Sqlite.COL_OAUTHTOKEN, account.getToken()); values.put(Sqlite.COL_OAUTHTOKEN, account.getToken());
@ -243,7 +244,7 @@ public class AccountDAO {
account.setInstance(c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE))); account.setInstance(c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE)));
account.setEmojis(Helper.restoreEmojisFromString(c.getString(c.getColumnIndex(Sqlite.COL_EMOJIS)))); account.setEmojis(Helper.restoreEmojisFromString(c.getString(c.getColumnIndex(Sqlite.COL_EMOJIS))));
account.setToken(c.getString(c.getColumnIndex(Sqlite.COL_OAUTHTOKEN))); account.setToken(c.getString(c.getColumnIndex(Sqlite.COL_OAUTHTOKEN)));
account.setSocial(c.getString(c.getColumnIndex(Sqlite.COL_SOCIAL))!=null?c.getString(c.getColumnIndex(Sqlite.COL_SOCIAL)):"MASTODON");
//Close the cursor //Close the cursor
c.close(); c.close();
@ -282,6 +283,7 @@ public class AccountDAO {
account.setCreated_at(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_CREATED_AT)))); account.setCreated_at(Helper.stringToDate(context, c.getString(c.getColumnIndex(Sqlite.COL_CREATED_AT))));
account.setInstance(c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE))); account.setInstance(c.getString(c.getColumnIndex(Sqlite.COL_INSTANCE)));
account.setToken(c.getString(c.getColumnIndex(Sqlite.COL_OAUTHTOKEN))); account.setToken(c.getString(c.getColumnIndex(Sqlite.COL_OAUTHTOKEN)));
account.setSocial(c.getString(c.getColumnIndex(Sqlite.COL_SOCIAL))!=null?c.getString(c.getColumnIndex(Sqlite.COL_SOCIAL)):"MASTODON");
accounts.add(account); accounts.add(account);
} }
//Close the cursor //Close the cursor

View File

@ -26,7 +26,7 @@ import android.database.sqlite.SQLiteOpenHelper;
public class Sqlite extends SQLiteOpenHelper { public class Sqlite extends SQLiteOpenHelper {
public static final int DB_VERSION = 22; public static final int DB_VERSION = 23;
public static final String DB_NAME = "mastodon_etalab_db"; public static final String DB_NAME = "mastodon_etalab_db";
public static SQLiteDatabase db; public static SQLiteDatabase db;
private static Sqlite sInstance; private static Sqlite sInstance;
@ -82,7 +82,7 @@ public class Sqlite extends SQLiteOpenHelper {
static final String COL_INSTANCE = "INSTANCE"; static final String COL_INSTANCE = "INSTANCE";
static final String COL_OAUTHTOKEN = "OAUTH_TOKEN"; static final String COL_OAUTHTOKEN = "OAUTH_TOKEN";
static final String COL_EMOJIS = "EMOJIS"; static final String COL_EMOJIS = "EMOJIS";
static final String COL_SOCIAL = "SOCIAL";
private static final String CREATE_TABLE_USER_ACCOUNT = "CREATE TABLE " + TABLE_USER_ACCOUNT + " (" private static final String CREATE_TABLE_USER_ACCOUNT = "CREATE TABLE " + TABLE_USER_ACCOUNT + " ("
+ COL_USER_ID + " TEXT PRIMARY KEY, " + COL_USERNAME + " TEXT NOT NULL, " + COL_ACCT + " TEXT NOT NULL, " + COL_USER_ID + " TEXT PRIMARY KEY, " + COL_USERNAME + " TEXT NOT NULL, " + COL_ACCT + " TEXT NOT NULL, "
@ -92,6 +92,7 @@ public class Sqlite extends SQLiteOpenHelper {
+ COL_AVATAR + " TEXT NOT NULL, "+ COL_AVATAR_STATIC + " TEXT NOT NULL, " + COL_AVATAR + " TEXT NOT NULL, "+ COL_AVATAR_STATIC + " TEXT NOT NULL, "
+ COL_HEADER + " TEXT NOT NULL, "+ COL_HEADER_STATIC + " TEXT NOT NULL, " + COL_HEADER + " TEXT NOT NULL, "+ COL_HEADER_STATIC + " TEXT NOT NULL, "
+ COL_EMOJIS + " TEXT, " + COL_EMOJIS + " TEXT, "
+ COL_SOCIAL + " TEXT, "
+ COL_INSTANCE + " TEXT NOT NULL, " + COL_OAUTHTOKEN + " TEXT NOT NULL, " + COL_CREATED_AT + " TEXT NOT NULL)"; + COL_INSTANCE + " TEXT NOT NULL, " + COL_OAUTHTOKEN + " TEXT NOT NULL, " + COL_CREATED_AT + " TEXT NOT NULL)";
@ -306,6 +307,8 @@ public class Sqlite extends SQLiteOpenHelper {
if( oldVersion > 6) { if( oldVersion > 6) {
db.execSQL("ALTER TABLE " + TABLE_SEARCH + " ADD COLUMN " + COL_NAME + " TEXT"); db.execSQL("ALTER TABLE " + TABLE_SEARCH + " ADD COLUMN " + COL_NAME + " TEXT");
} }
case 22:
db.execSQL("ALTER TABLE " + TABLE_USER_ACCOUNT + " ADD COLUMN " + COL_SOCIAL + " TEXT");
default: default:
break; break;
} }

View File

@ -77,6 +77,11 @@
android:src="@drawable/ic_info_login" android:src="@drawable/ic_info_login"
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" /> android:layout_height="30dp" />
<CheckBox
android:id="@+id/peertube_instance"
android:layout_width="wrap_content"
android:text="@string/peertube_instance"
android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<LinearLayout <LinearLayout

View File

@ -83,7 +83,11 @@
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" /> android:layout_height="30dp" />
</LinearLayout> </LinearLayout>
<CheckBox
android:id="@+id/peertube_instance"
android:layout_width="wrap_content"
android:text="@string/peertube_instance"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"