1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 11:42:16 -05:00

Fix Issue 2389: Self signed certificate expiry causes silent send/receive failure.

With this fix, a CertPathValidatorException or CertificateException will
create a "Certificate error:  Check your server settings" notification
in the status bar.  When the user clicks on the notification, they are
taken to the appropriate server settings screen where they can review their
settings and can accept a different server certificate.
This commit is contained in:
Joe Steele 2013-01-08 18:16:26 -05:00
parent ac6c48c2d8
commit 29f15d715d
13 changed files with 108 additions and 12 deletions

View File

@ -221,6 +221,8 @@ Please submit bug reports, contribute new features and ask questions at
<string name="notification_action_reply">Reply</string>
<string name="notification_action_read">Read</string>
<string name="notification_action_delete">Delete</string>
<string name="notification_certificate_error_title">Certificate error</string>
<string name="notification_certificate_error_text">Check your server settings</string>
<string name="notification_bg_sync_ticker">Checking mail: <xliff:g id="account">%s</xliff:g>:<xliff:g id="folder">%s</xliff:g></string>
<string name="notification_bg_sync_title">Checking mail</string>

View File

@ -345,12 +345,14 @@ public class K9 extends Application {
public static final int NOTIFICATION_LED_SENDING_FAILURE_COLOR = 0xffff0000;
public static final int NOTIFICATION_LED_FAILURE_COLOR = 0xffff0000;
// Must not conflict with an account number
public static final int FETCHING_EMAIL_NOTIFICATION = -5000;
public static final int SEND_FAILED_NOTIFICATION = -1500;
public static final int CONNECTIVITY_ID = -3;
public static final int CERTIFICATE_EXCEPTION_NOTIFICATION_INCOMING = -4;
public static final int CERTIFICATE_EXCEPTION_NOTIFICATION_OUTGOING = -5;
public static class Intents {

View File

@ -3,6 +3,9 @@ package com.fsck.k9.activity.setup;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Application;
import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
@ -105,6 +108,7 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
finish();
return;
}
clearCertificateErrorNotifications();
if (mCheckIncoming) {
store = mAccount.getRemoteStore();
@ -195,6 +199,19 @@ public class AccountSetupCheckSettings extends K9Activity implements OnClickList
});
}
private void clearCertificateErrorNotifications() {
final Application app = getApplication();
final NotificationManager notifMgr = (NotificationManager) app
.getSystemService(Context.NOTIFICATION_SERVICE);
final String uuid = mAccount.getUuid();
if (mCheckOutgoing){
notifMgr.cancel(uuid, K9.CERTIFICATE_EXCEPTION_NOTIFICATION_OUTGOING);
}
if (mCheckIncoming){
notifMgr.cancel(uuid, K9.CERTIFICATE_EXCEPTION_NOTIFICATION_INCOMING);
}
}
private void showErrorDialog(final int msgResId, final Object... args) {
mHandler.post(new Runnable() {
public void run() {

View File

@ -33,7 +33,7 @@ import java.util.HashMap;
import java.util.Map;
public class AccountSetupIncoming extends K9Activity implements OnClickListener {
private static final String EXTRA_ACCOUNT = "account";
public static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";
private static final int[] POP3_PORTS = {

View File

@ -26,7 +26,7 @@ import java.net.URLEncoder;
public class AccountSetupOutgoing extends K9Activity implements OnClickListener,
OnCheckedChangeListener {
private static final String EXTRA_ACCOUNT = "account";
public static final String EXTRA_ACCOUNT = "account";
private static final String EXTRA_MAKE_DEFAULT = "makeDefault";

View File

@ -3280,13 +3280,30 @@ public class MessagingController implements Runnable {
PendingIntent pi = PendingIntent.getActivity(mApplication, 0, i, 0);
builder.setContentIntent(pi);
configureNotification(builder, null, null, K9.NOTIFICATION_LED_SENDING_FAILURE_COLOR,
configureNotification(builder, null, null, K9.NOTIFICATION_LED_FAILURE_COLOR,
K9.NOTIFICATION_LED_BLINK_FAST, true);
notifMgr.notify(K9.SEND_FAILED_NOTIFICATION - account.getAccountNumber(),
builder.build());
}
public void notify(String tag, int id, String title, String text, PendingIntent pi) {
final NotificationManager notifMgr = (NotificationManager) mApplication
.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder builder = new NotificationCompat.Builder(mApplication);
builder.setSmallIcon(R.drawable.stat_notify_email_generic);
builder.setWhen(System.currentTimeMillis());
builder.setAutoCancel(true);
builder.setTicker(title);
builder.setContentTitle(title);
builder.setContentText(text);
builder.setContentIntent(pi);
configureNotification(builder, null, null,
K9.NOTIFICATION_LED_FAILURE_COLOR,
K9.NOTIFICATION_LED_BLINK_FAST, true);
notifMgr.notify(tag, id, builder.build());
}
/**
* Display an ongoing notification while checking for new messages on the server.
*

View File

@ -1,6 +1,18 @@
package com.fsck.k9.mail;
import android.app.Application;
import android.app.PendingIntent;
import android.content.Intent;
import com.fsck.k9.Account;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.activity.setup.AccountSetupIncoming;
import com.fsck.k9.activity.setup.AccountSetupOutgoing;
import com.fsck.k9.controller.MessagingController;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertificateException;
public class CertificateValidationException extends MessagingException {
public static final long serialVersionUID = -1;
@ -8,7 +20,44 @@ public class CertificateValidationException extends MessagingException {
super(message);
}
public CertificateValidationException(String message, Throwable throwable) {
public CertificateValidationException(final String message,
Throwable throwable, final Account account, final boolean incoming) {
super(message, throwable);
/*
* We get here because of an SSLException. We are only interested in
* creating a notification if the underlying cause is certificate
* related.
*/
while (throwable != null
&& !(throwable instanceof CertPathValidatorException)
&& !(throwable instanceof CertificateException)) {
throwable = throwable.getCause();
}
if (throwable == null)
return;
final Application app = K9.app;
final String title = app
.getString(R.string.notification_certificate_error_title);
final String text = app
.getString(R.string.notification_certificate_error_text);
final Class<?> className;
final String extraName;
final int id;
if (incoming) {
className = AccountSetupIncoming.class;
extraName = AccountSetupIncoming.EXTRA_ACCOUNT;
id = K9.CERTIFICATE_EXCEPTION_NOTIFICATION_INCOMING;
} else {
className = AccountSetupOutgoing.class;
extraName = AccountSetupOutgoing.EXTRA_ACCOUNT;
id = K9.CERTIFICATE_EXCEPTION_NOTIFICATION_OUTGOING;
}
final Intent i = new Intent(app, className);
final String uuid = account.getUuid();
i.setAction(Intent.ACTION_EDIT);
i.putExtra(extraName, uuid);
final PendingIntent pi = PendingIntent.getActivity(app, 0, i, 0);
MessagingController controller = MessagingController.getInstance(app);
controller.notify(uuid, id, title, text, pi);
}
}

View File

@ -14,7 +14,7 @@ public abstract class Transport {
public synchronized static Transport getInstance(Account account) throws MessagingException {
String uri = account.getTransportUri();
if (uri.startsWith("smtp")) {
return new SmtpTransport(uri);
return new SmtpTransport(account);
} else if (uri.startsWith("webdav")) {
return new WebDavTransport(account);
} else {

View File

@ -429,6 +429,10 @@ public class ImapStore extends Store {
mCombinedPrefix = prefix;
}
@Override
public Account getAccount() {
return mAccount;
}
}
private static final SimpleDateFormat RFC3501_DATE = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
@ -2623,7 +2627,7 @@ public class ImapStore extends Store {
} catch (SSLException e) {
throw new CertificateValidationException(e.getMessage(), e);
throw new CertificateValidationException(e.getMessage(), e, mSettings.getAccount(), true);
} catch (GeneralSecurityException gse) {
throw new MessagingException(
"Unable to open connection to IMAP server due to security error.", gse);

View File

@ -391,7 +391,7 @@ public class Pop3Store extends Store {
mCapabilities = getCapabilities();
} catch (SSLException e) {
throw new CertificateValidationException(e.getMessage(), e);
throw new CertificateValidationException(e.getMessage(), e, mAccount, true);
} catch (GeneralSecurityException gse) {
throw new MessagingException(
"Unable to open connection to POP server due to security error.", gse);

View File

@ -848,7 +848,7 @@ public class WebDavStore extends Store {
response.getStatusLine().toString());
}
} catch (SSLException e) {
throw new CertificateValidationException(e.getMessage(), e);
throw new CertificateValidationException(e.getMessage(), e, mAccount, true);
} catch (IOException ioe) {
Log.e(K9.LOG_TAG, "IOException: " + ioe + "\nTrace: " + processException(ioe));
throw new MessagingException("IOException", ioe);

View File

@ -182,6 +182,7 @@ public class SmtpTransport extends Transport {
}
Account mAccount;
String mHost;
int mPort;
String mUsername;
@ -194,14 +195,15 @@ public class SmtpTransport extends Transport {
private boolean m8bitEncodingAllowed;
private int mLargestAcceptableMessage;
public SmtpTransport(String uri) throws MessagingException {
public SmtpTransport(Account account) throws MessagingException {
ServerSettings settings;
try {
settings = decodeUri(uri);
settings = decodeUri(account.getTransportUri());
} catch (IllegalArgumentException e) {
throw new MessagingException("Error while decoding transport URI", e);
}
mAccount = account;
mHost = settings.host;
mPort = settings.port;
@ -387,7 +389,7 @@ public class SmtpTransport extends Transport {
}
}
} catch (SSLException e) {
throw new CertificateValidationException(e.getMessage(), e);
throw new CertificateValidationException(e.getMessage(), e, mAccount, false);
} catch (GeneralSecurityException gse) {
throw new MessagingException(
"Unable to open connection to SMTP server due to security error.", gse);

View File

@ -1,5 +1,6 @@
package com.fsck.k9.mail.transport.imap;
import com.fsck.k9.Account;
import com.fsck.k9.mail.store.ImapStore;
import com.fsck.k9.mail.store.ImapStore.AuthType;
import com.fsck.k9.mail.store.ImapStore.ImapConnection;
@ -34,4 +35,6 @@ public interface ImapSettings {
void setCombinedPrefix(String prefix);
Account getAccount();
}