Allow switching to password auth

This commit is contained in:
M66B 2021-12-24 08:37:33 +01:00
parent 09c2fcb1c4
commit 6b000d75ee
5 changed files with 85 additions and 40 deletions

View File

@ -104,12 +104,13 @@ public interface DaoIdentity {
@Query("UPDATE identity SET password = :password WHERE id = :id AND NOT (password IS :password)") @Query("UPDATE identity SET password = :password WHERE id = :id AND NOT (password IS :password)")
int setIdentityPassword(long id, String password); int setIdentityPassword(long id, String password);
@Query("UPDATE identity SET password = :password" + @Query("UPDATE identity" +
" SET password = :password, auth_type = :auth_type" +
" WHERE account = :account" + " WHERE account = :account" +
" AND user = :user" + " AND user = :user" +
" AND NOT (password IS :password)" + " AND NOT (password IS :password AND auth_type = :auth_type)" +
" AND host LIKE :domain") " AND host LIKE :domain")
int setIdentityPassword(long account, String user, String password, String domain); int setIdentityPassword(long account, String user, String password, int auth_type, String domain);
@Query("UPDATE identity" + @Query("UPDATE identity" +
" SET password = :password, auth_type = :new_auth_type" + " SET password = :password, auth_type = :new_auth_type" +

View File

@ -29,6 +29,7 @@ import static eu.faircode.email.ServiceAuthenticator.AUTH_TYPE_PASSWORD;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.net.Uri; import android.net.Uri;
@ -58,10 +59,12 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.widget.PopupMenu;
import androidx.constraintlayout.widget.Group; import androidx.constraintlayout.widget.Group;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout; import com.google.android.material.textfield.TextInputLayout;
@ -719,6 +722,10 @@ public class FragmentAccount extends FragmentBase {
result.account = db.account().getAccount(id); result.account = db.account().getAccount(id);
result.folders = new ArrayList<>(); result.folders = new ArrayList<>();
if (result.account.auth_type != AUTH_TYPE_PASSWORD &&
!Objects.equals(result.account.password, password))
auth = AUTH_TYPE_PASSWORD;
// Check IMAP server / get folders // Check IMAP server / get folders
String protocol = "imap" + (encryption == EmailService.ENCRYPTION_SSL ? "s" : ""); String protocol = "imap" + (encryption == EmailService.ENCRYPTION_SSL ? "s" : "");
try (EmailService iservice = new EmailService( try (EmailService iservice = new EmailService(
@ -983,6 +990,10 @@ public class FragmentAccount extends FragmentBase {
DB db = DB.getInstance(context); DB db = DB.getInstance(context);
EntityAccount account = db.account().getAccount(id); EntityAccount account = db.account().getAccount(id);
if (account.auth_type != AUTH_TYPE_PASSWORD &&
!Objects.equals(account.password, password))
auth = AUTH_TYPE_PASSWORD;
if (should) { if (should) {
if (account == null) if (account == null)
return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user); return !TextUtils.isEmpty(host) && !TextUtils.isEmpty(user);
@ -1130,7 +1141,7 @@ public class FragmentAccount extends FragmentBase {
if (account != null && !account.password.equals(password)) { if (account != null && !account.password.equals(password)) {
String domain = UriHelper.getParentDomain(context, account.host); String domain = UriHelper.getParentDomain(context, account.host);
String match = (Objects.equals(account.host, domain) ? account.host : "%." + domain); String match = (Objects.equals(account.host, domain) ? account.host : "%." + domain);
int count = db.identity().setIdentityPassword(account.id, account.user, password, match); int count = db.identity().setIdentityPassword(account.id, account.user, password, auth, match);
Log.i("Updated passwords=" + count + " match=" + match); Log.i("Updated passwords=" + count + " match=" + match);
} }
@ -1442,12 +1453,13 @@ public class FragmentAccount extends FragmentBase {
@Override @Override
protected void onExecuted(Bundle args, final EntityAccount account) { protected void onExecuted(Bundle args, final EntityAccount account) {
// Get providers // Get providers
List<EmailProvider> providers = EmailProvider.loadProfiles(getContext()); final Context context = getContext();
List<EmailProvider> providers = EmailProvider.loadProfiles(context);
providers.add(0, new EmailProvider(getString(R.string.title_select))); providers.add(0, new EmailProvider(getString(R.string.title_select)));
providers.add(1, new EmailProvider(getString(R.string.title_custom))); providers.add(1, new EmailProvider(getString(R.string.title_custom)));
ArrayAdapter<EmailProvider> aaProvider = ArrayAdapter<EmailProvider> aaProvider =
new ArrayAdapter<>(getContext(), R.layout.spinner_item1, android.R.id.text1, providers); new ArrayAdapter<>(context, R.layout.spinner_item1, android.R.id.text1, providers);
aaProvider.setDropDownViewResource(R.layout.spinner_item1_dropdown); aaProvider.setDropDownViewResource(R.layout.spinner_item1_dropdown);
spProvider.setAdapter(aaProvider); spProvider.setAdapter(aaProvider);
@ -1505,7 +1517,7 @@ public class FragmentAccount extends FragmentBase {
etCategory.setText(account == null ? null : account.category); etCategory.setText(account == null ? null : account.category);
btnColor.setColor(account == null ? null : account.color); btnColor.setColor(account == null ? null : account.color);
boolean pro = ActivityBilling.isPro(getContext()); boolean pro = ActivityBilling.isPro(context);
cbNotify.setChecked(account != null && account.notify && pro); cbNotify.setChecked(account != null && account.notify && pro);
cbNotify.setEnabled(pro); cbNotify.setEnabled(pro);
@ -1570,42 +1582,72 @@ public class FragmentAccount extends FragmentBase {
tilPassword.setEndIconOnClickListener(new View.OnClickListener() { tilPassword.setEndIconOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Fragment fragment; PopupMenuLifecycle popupMenu = new PopupMenuLifecycle(context, FragmentAccount.this, view);
if (auth == AUTH_TYPE_GMAIL)
fragment = new FragmentGmail();
else if (auth == AUTH_TYPE_OAUTH)
fragment = new FragmentOAuth();
else {
Log.e("Unknown auth=" + auth);
return;
}
try { popupMenu.getMenu().add(Menu.NONE, R.string.title_account_auth_update, 1, R.string.title_account_auth_update);
Bundle aargs = new Bundle(); popupMenu.getMenu().add(Menu.NONE, R.string.title_account_auth_password, 2, R.string.title_account_auth_password);
if (auth == AUTH_TYPE_OAUTH) {
if (account == null)
throw new IllegalArgumentException("Account missing");
EmailProvider provider = popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
EmailProvider.getProvider(view.getContext(), account.provider); @Override
aargs.putString("id", provider.id); public boolean onMenuItemClick(MenuItem item) {
aargs.putString("name", provider.description); int id = item.getItemId();
aargs.putString("privacy", provider.oauth.privacy); if (id == R.string.title_account_auth_update) {
aargs.putBoolean("askAccount", provider.oauth.askAccount); onUpdate();
return true;
} else if (id == R.string.title_account_auth_password) {
onPassword();
return true;
} else
return false;
} }
aargs.putString("personal", args.getString("personal"));
aargs.putString("address", etUser.getText().toString());
aargs.putBoolean("update", true);
fragment.setArguments(aargs); private void onUpdate() {
Fragment fragment;
if (auth == AUTH_TYPE_GMAIL)
fragment = new FragmentGmail();
else if (auth == AUTH_TYPE_OAUTH)
fragment = new FragmentOAuth();
else {
Log.e("Unknown auth=" + auth);
return;
}
getParentFragmentManager().popBackStack(); try {
FragmentTransaction fragmentTransaction = getParentFragmentManager().beginTransaction(); Bundle aargs = new Bundle();
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("quick"); if (auth == AUTH_TYPE_OAUTH) {
fragmentTransaction.commit(); if (account == null)
} catch (Throwable ex) { throw new IllegalArgumentException("Account missing");
Log.e(ex);
} EmailProvider provider =
EmailProvider.getProvider(view.getContext(), account.provider);
aargs.putString("id", provider.id);
aargs.putString("name", provider.description);
aargs.putString("privacy", provider.oauth.privacy);
aargs.putBoolean("askAccount", provider.oauth.askAccount);
}
aargs.putString("personal", args.getString("personal"));
aargs.putString("address", etUser.getText().toString());
aargs.putBoolean("update", true);
fragment.setArguments(aargs);
getParentFragmentManager().popBackStack();
FragmentTransaction fragmentTransaction = getParentFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("quick");
fragmentTransaction.commit();
} catch (Throwable ex) {
Log.e(ex);
}
}
private void onPassword() {
tilPassword.getEditText().setText(null);
tilPassword.getEditText().setEnabled(true);
tilPassword.requestFocus();
}
});
popupMenu.show();
} }
}); });
} }

View File

@ -955,7 +955,7 @@ public class FragmentIdentity extends FragmentBase {
if (identity != null && !identity.password.equals(password)) { if (identity != null && !identity.password.equals(password)) {
int count = db.identity().setIdentityPassword( int count = db.identity().setIdentityPassword(
identity.account, identity.account,
identity.user, password, identity.user, password, identity.auth_type,
identity.host); identity.host);
Log.i("Updated passwords=" + count); Log.i("Updated passwords=" + count);
} }

View File

@ -495,7 +495,7 @@ public class FragmentPop extends FragmentBase {
if (account != null && !account.password.equals(password)) { if (account != null && !account.password.equals(password)) {
String domain = UriHelper.getParentDomain(context, account.host); String domain = UriHelper.getParentDomain(context, account.host);
String match = (Objects.equals(account.host, domain) ? account.host : "%." + domain); String match = (Objects.equals(account.host, domain) ? account.host : "%." + domain);
int count = db.identity().setIdentityPassword(account.id, account.user, password, match); int count = db.identity().setIdentityPassword(account.id, account.user, password, AUTH_TYPE_PASSWORD, match);
Log.i("Updated passwords=" + count + " match=" + match); Log.i("Updated passwords=" + count + " match=" + match);
} }

View File

@ -909,6 +909,8 @@
<string name="title_identity_required">An identity is required to send emails</string> <string name="title_identity_required">An identity is required to send emails</string>
<string name="title_drafts_required">A drafts folder is required to send emails</string> <string name="title_drafts_required">A drafts folder is required to send emails</string>
<string name="title_drafts_select">Sending emails requires a drafts folder to be selected in the account settings</string> <string name="title_drafts_select">Sending emails requires a drafts folder to be selected in the account settings</string>
<string name="title_account_auth_update">Update authorization</string>
<string name="title_account_auth_password">Switch to password authentication</string>
<string name="title_account_delete">Delete this account permanently?</string> <string name="title_account_delete">Delete this account permanently?</string>
<string name="title_identity_delete">Delete this identity permanently?</string> <string name="title_identity_delete">Delete this identity permanently?</string>
<string name="title_edit_html">Edit as HTML</string> <string name="title_edit_html">Edit as HTML</string>