Guided Outlook password auth

pull/206/head
M66B 3 years ago
parent 3bb984924a
commit 81670c26fe

@ -19,14 +19,18 @@ package eu.faircode.email;
Copyright 2018-2021 by Marcel Bokhorst (M66B)
*/
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import java.util.List;
public class ActivityError extends ActivityBase {
static final int PI_ERROR = 1;
static final int PI_ALERT = 2;
@ -42,6 +46,7 @@ public class ActivityError extends ActivityBase {
TextView tvTitle = view.findViewById(R.id.tvTitle);
TextView tvMessage = view.findViewById(R.id.tvMessage);
Button btnPassword = view.findViewById(R.id.btnPassword);
ImageButton ibSetting = view.findViewById(R.id.ibSetting);
ImageButton ibInfo = view.findViewById(R.id.ibInfo);
@ -49,20 +54,90 @@ public class ActivityError extends ActivityBase {
String type = intent.getStringExtra("type");
String title = intent.getStringExtra("title");
String message = intent.getStringExtra("message");
String provider = intent.getStringExtra("provider");
long account = intent.getLongExtra("account", -1L);
int protocol = intent.getIntExtra("protocol", -1);
int auth_type = intent.getIntExtra("auth_type", -1);
int faq = intent.getIntExtra("faq", -1);
tvTitle.setText(title);
tvMessage.setMovementMethod(LinkMovementMethod.getInstance());
tvMessage.setText(message);
boolean outlook = (auth_type == ServiceAuthenticator.AUTH_TYPE_OAUTH &&
("office365".equals(provider) || "outlook".equals(provider)));
btnPassword.setVisibility(outlook ? View.VISIBLE : View.GONE);
btnPassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bundle args = new Bundle();
args.putLong("id", account);
new SimpleTask<Void>() {
@Override
protected Void onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
DB db = DB.getInstance(context);
try {
db.beginTransaction();
EntityAccount account = db.account().getAccount(id);
if (account == null)
return null;
if (account.auth_type == ServiceAuthenticator.AUTH_TYPE_OAUTH &&
("office365".equals(account.provider) ||
"outlook".equals(account.provider))) {
account.auth_type = ServiceAuthenticator.AUTH_TYPE_PASSWORD;
account.password = "";
db.account().updateAccount(account);
List<EntityIdentity> identities = db.identity().getIdentities(account.id);
if (identities != null)
for (EntityIdentity identity : identities)
if (identity.auth_type == ServiceAuthenticator.AUTH_TYPE_OAUTH) {
identity.auth_type = ServiceAuthenticator.AUTH_TYPE_PASSWORD;
identity.password = "";
db.identity().updateIdentity(identity);
}
}
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
return null;
}
@Override
protected void onExecuted(Bundle args, Void data) {
startActivity(new Intent(ActivityError.this, ActivitySetup.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("target", "accounts")
.putExtra("id", account)
.putExtra("protocol", protocol));
finish();
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getSupportFragmentManager(), ex);
}
}.execute(ActivityError.this, args, "error:password");
}
});
ibSetting.setVisibility(account < 0 ? View.GONE : View.VISIBLE);
ibSetting.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.getContext().startActivity(new Intent(v.getContext(), ActivitySetup.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("target", "accounts"));
.putExtra("target", "accounts")
.putExtra("id", account)
.putExtra("protocol", protocol));
}
});

@ -301,13 +301,18 @@ public class ActivitySetup extends ActivityBase implements FragmentManager.OnBac
if (getSupportFragmentManager().getFragments().size() == 0) {
Intent intent = getIntent();
String target = intent.getStringExtra("target");
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if ("accounts".equals(target))
fragmentTransaction.replace(R.id.content_frame, new FragmentAccounts()).addToBackStack("accounts");
else
fragmentTransaction.replace(R.id.content_frame, new FragmentOptions()).addToBackStack("options");
fragmentTransaction.commit();
long id = intent.getLongExtra("id", -1L);
if ("accounts".equals(target) && id > 0)
onEditAccount(intent);
else {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if ("accounts".equals(target))
fragmentTransaction.replace(R.id.content_frame, new FragmentAccounts()).addToBackStack("accounts");
else
fragmentTransaction.replace(R.id.content_frame, new FragmentOptions()).addToBackStack("options");
fragmentTransaction.commit();
}
if (intent.hasExtra("target")) {
intent.removeExtra("target");

@ -5118,10 +5118,12 @@ class Core {
// Build pending intent
Intent intent = new Intent(context, ActivityError.class);
intent.setAction(channel + ":" + account.id + ":" + id);
intent.putExtra("type", channel);
intent.putExtra("title", title);
intent.putExtra("message", message);
intent.putExtra("provider", account.provider);
intent.putExtra("account", account.id);
intent.putExtra("protocol", account.protocol);
intent.putExtra("auth_type", account.auth_type);
intent.putExtra("faq", 22);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntentCompat.getActivity(

@ -413,12 +413,12 @@ public class EmailService implements AutoCloseable {
connect(host, port, auth, user, authenticator, factory);
} catch (AuthenticationFailedException ex) {
if ("outlook.office365.com".equals(host) &&
"AUTHENTICATE failed.".equals(ex.getMessage()))
throw new AuthenticationFailedException(
"The Outlook IMAP server is currently not accepting logins. " +
"Synchronizing and configuring accounts will work again after Microsoft has fixed this.",
ex.getNextException());
//if ("outlook.office365.com".equals(host) &&
// "AUTHENTICATE failed.".equals(ex.getMessage()))
// throw new AuthenticationFailedException(
// "The Outlook IMAP server is currently not accepting logins. " +
// "Synchronizing and configuring accounts will work again after Microsoft has fixed this.",
// ex.getNextException());
if (auth == AUTH_TYPE_GMAIL || auth == AUTH_TYPE_OAUTH) {
try {

@ -96,6 +96,7 @@ public class FragmentAccount extends FragmentBase {
private EditText etPort;
private EditText etUser;
private TextInputLayout tilPassword;
private TextView tvAppPassword;
private TextView tvPasswordStorage;
private Button btnCertificate;
private TextView tvCertificate;
@ -201,6 +202,7 @@ public class FragmentAccount extends FragmentBase {
tvInsecureRemark = view.findViewById(R.id.tvInsecureRemark);
etUser = view.findViewById(R.id.etUser);
tilPassword = view.findViewById(R.id.tilPassword);
tvAppPassword = view.findViewById(R.id.tvAppPassword);
tvPasswordStorage = view.findViewById(R.id.tvPasswordStorage);
btnCertificate = view.findViewById(R.id.btnCertificate);
tvCertificate = view.findViewById(R.id.tvCertificate);
@ -288,6 +290,9 @@ public class FragmentAccount extends FragmentBase {
etUser.setTag(null);
etUser.setText(null);
tilPassword.getEditText().setText(null);
tvAppPassword.setVisibility(
"office365".equals(provider.id) || "outlook".equals(provider.id)
? View.VISIBLE : View.GONE);
certificate = null;
tvCertificate.setText(R.string.title_optional);
etRealm.setText(null);
@ -353,6 +358,15 @@ public class FragmentAccount extends FragmentBase {
}
});
tvAppPassword.setVisibility(View.GONE);
tvAppPassword.setPaintFlags(tvAppPassword.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
tvAppPassword.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Helper.viewFAQ(view.getContext(), 14);
}
});
tvPasswordStorage.setPaintFlags(tvPasswordStorage.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
tvPasswordStorage.setOnClickListener(new View.OnClickListener() {
@Override
@ -1454,6 +1468,9 @@ public class FragmentAccount extends FragmentBase {
etUser.setText(account == null ? null : account.user);
tilPassword.getEditText().setText(account == null ? null : account.password);
tvAppPassword.setVisibility(account != null &&
("office365".equals(account.provider) || "outlook".equals(account.provider))
? View.VISIBLE : View.GONE);
certificate = (account == null ? null : account.certificate_alias);
tvCertificate.setText(certificate == null ? getString(R.string.title_optional) : certificate);
etRealm.setText(account == null ? null : account.realm);

@ -258,9 +258,42 @@ public class FragmentFolders extends FragmentBase {
fabError.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.getContext().startActivity(new Intent(v.getContext(), ActivitySetup.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra("target", "accounts"));
Bundle args = new Bundle();
args.putLong("id", account);
new SimpleTask<EntityAccount>() {
@Override
protected EntityAccount onExecute(Context context, Bundle args) {
long id = args.getLong("id");
DB db = DB.getInstance(context);
return db.account().getAccount(id);
}
@Override
protected void onExecuted(Bundle args, EntityAccount account) {
if (account == null)
return;
String title = getString(R.string.title_notification_failed, account.name);
Intent intent = new Intent(getContext(), ActivityError.class);
intent.putExtra("title", title);
intent.putExtra("message", account.error);
intent.putExtra("provider", account.provider);
intent.putExtra("account", account.id);
intent.putExtra("protocol", account.protocol);
intent.putExtra("auth_type", account.auth_type);
intent.putExtra("faq", 22);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(getParentFragmentManager(), ex);
}
}.execute(FragmentFolders.this, args, "folders:error");
}
});

@ -511,6 +511,52 @@ public class FragmentOAuth extends FragmentBase {
String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps");
int iencryption = (provider.smtp.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
if ("outlook".equals(id) && BuildConfig.DEBUG) {
DB db = DB.getInstance(context);
// Create account
EntityAccount account = new EntityAccount();
account.host = provider.imap.host;
account.encryption = aencryption;
account.port = provider.imap.port;
account.auth_type = AUTH_TYPE_OAUTH;
account.provider = provider.id;
account.user = address;
account.password = state;
int at = account.user.indexOf('@');
String user = account.user.substring(0, at);
account.name = provider.name + "/" + user;
account.synchronize = true;
account.primary = false;
if (provider.keepalive > 0)
account.poll_interval = provider.keepalive;
account.partial_fetch = provider.partial;
account.created = new Date().getTime();
account.last_connected = account.created;
account.id = db.account().insertAccount(account);
args.putLong("account", account.id);
EntityLog.log(context, "OAuth account=" + account.name);
EntityFolder folder = new EntityFolder("INBOX", EntityFolder.INBOX);
folder.account = account.id;
folder.setProperties();
folder.setSpecials(account);
folder.id = db.folder().insertFolder(folder);
EntityLog.log(context, "OAuth folder=" + folder.name + " type=" + folder.type);
if (folder.synchronize)
EntityOperation.sync(context, folder.id, true);
return null;
}
/*
* Outlook shared mailbox
* Authenticate: main/shared account

@ -67,6 +67,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTitle" />
<Button
android:id="@+id/btnPassword"
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:drawableEnd="@drawable/twotone_edit_24"
android:drawablePadding="6dp"
android:tag="disable"
android:text="@string/title_password"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvMessage" />
<ImageButton
android:id="@+id/ibSetting"
android:layout_width="wrap_content"
@ -75,7 +88,7 @@
android:contentDescription="@string/title_setup"
android:tooltipText="@string/title_setup"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvMessage"
app:layout_constraintTop_toBottomOf="@id/btnPassword"
app:srcCompat="@drawable/twotone_settings_24" />
<ImageButton
@ -86,7 +99,7 @@
android:contentDescription="@string/title_info"
android:tooltipText="@string/title_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvMessage"
app:layout_constraintTop_toBottomOf="@id/btnPassword"
app:srcCompat="@drawable/twotone_info_24" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

@ -287,6 +287,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tilPassword" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvAppPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:drawableEnd="@drawable/twotone_open_in_new_12"
android:drawablePadding="6dp"
android:drawableTint="?android:attr/textColorLink"
android:text="@string/title_setup_app_password"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorLink"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tvCaseSensitive" />
<eu.faircode.email.FixedTextView
android:id="@+id/tvPasswordStorage"
android:layout_width="wrap_content"
@ -299,7 +313,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?android:attr/textColorLink"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCaseSensitive" />
app:layout_constraintTop_toBottomOf="@id/tvAppPassword" />
<Button
android:id="@+id/btnCertificate"
@ -1001,7 +1015,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="
tvUser,etUser,tvPassword,tilPassword,tvCaseSensitive,tvPasswordStorage,
tvUser,etUser,tvPassword,tilPassword,tvCaseSensitive,tvAppPassword,tvPasswordStorage,
btnCertificate,tvCertificate,
tvRealm,etRealm,
tvName,tvNameRemark,etName,

@ -240,6 +240,7 @@
<string name="title_setup_still">Still to do</string>
<string name="title_setup_error">Error</string>
<string name="title_setup_configuring">Configuring account &#8230;</string>
<string name="title_setup_app_password">You might need to use an app password</string>
<string name="title_setup_close">Close settings</string>
<string name="title_setup_export">Export settings</string>

Loading…
Cancel
Save