mirror of https://github.com/M66B/FairEmail.git
Added account/identity option to enforce DANE
This commit is contained in:
parent
ea9125ff72
commit
399612896f
File diff suppressed because it is too large
Load Diff
|
@ -583,8 +583,7 @@ public class ActivityEML extends ActivityBase {
|
|||
Session isession = Session.getInstance(props, null);
|
||||
MimeMessage imessage = new MimeMessage(isession, is);
|
||||
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, account.getProtocol(), account.realm, account.encryption, account.insecure, account.unicode, true)) {
|
||||
try (EmailService iservice = new EmailService(context, account, EmailService.PURPOSE_USE, true)) {
|
||||
iservice.setPartialFetch(account.partial_fetch);
|
||||
iservice.setRawFetch(account.raw_fetch);
|
||||
iservice.setIgnoreBodyStructureSize(account.ignore_size);
|
||||
|
|
|
@ -426,9 +426,7 @@ public class BoundaryCallbackMessages extends PagedList.BoundaryCallback<TupleMe
|
|||
throw new IllegalStateException(context.getString(R.string.title_no_internet));
|
||||
|
||||
EntityLog.log(context, "Boundary server connecting account=" + account.name);
|
||||
state.iservice = new EmailService(
|
||||
context, account.getProtocol(), account.realm, account.encryption, account.insecure, account.unicode,
|
||||
EmailService.PURPOSE_SEARCH, debug || BuildConfig.DEBUG);
|
||||
state.iservice = new EmailService(context, account, EmailService.PURPOSE_SEARCH, debug || BuildConfig.DEBUG);
|
||||
state.iservice.setPartialFetch(account.partial_fetch);
|
||||
state.iservice.setRawFetch(account.raw_fetch);
|
||||
state.iservice.setIgnoreBodyStructureSize(account.ignore_size);
|
||||
|
|
|
@ -67,7 +67,7 @@ import javax.mail.internet.InternetAddress;
|
|||
// https://developer.android.com/topic/libraries/architecture/room.html
|
||||
|
||||
@Database(
|
||||
version = 287,
|
||||
version = 288,
|
||||
entities = {
|
||||
EntityIdentity.class,
|
||||
EntityAccount.class,
|
||||
|
@ -2908,6 +2908,13 @@ public abstract class DB extends RoomDatabase {
|
|||
logMigration(startVersion, endVersion);
|
||||
db.execSQL("ALTER TABLE `message` ADD COLUMN `auth` INTEGER");
|
||||
}
|
||||
}).addMigrations(new Migration(287, 288) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
logMigration(startVersion, endVersion);
|
||||
db.execSQL("ALTER TABLE `account` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE `identity` ADD COLUMN `dane` INTEGER NOT NULL DEFAULT 0");
|
||||
}
|
||||
}).addMigrations(new Migration(998, 999) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
|
|
|
@ -99,6 +99,7 @@ public class EmailService implements AutoCloseable {
|
|||
private Context context;
|
||||
private String protocol;
|
||||
private boolean insecure;
|
||||
private boolean dane;
|
||||
private int purpose;
|
||||
private boolean ssl_harden;
|
||||
private boolean ssl_harden_strict;
|
||||
|
@ -168,14 +169,11 @@ public class EmailService implements AutoCloseable {
|
|||
// Prevent instantiation
|
||||
}
|
||||
|
||||
EmailService(Context context, String protocol, String realm, int encryption, boolean insecure, boolean unicode, boolean debug) throws NoSuchProviderException {
|
||||
this(context, protocol, realm, encryption, insecure, unicode, PURPOSE_USE, debug);
|
||||
}
|
||||
|
||||
EmailService(Context context, String protocol, String realm, int encryption, boolean insecure, boolean unicode, int purpose, boolean debug) throws NoSuchProviderException {
|
||||
EmailService(Context context, String protocol, String realm, int encryption, boolean insecure, boolean dane, boolean unicode, int purpose, boolean debug) throws NoSuchProviderException {
|
||||
this.context = context.getApplicationContext();
|
||||
this.protocol = protocol;
|
||||
this.insecure = insecure;
|
||||
this.dane = dane;
|
||||
this.purpose = purpose;
|
||||
this.debug = debug;
|
||||
|
||||
|
@ -312,6 +310,14 @@ public class EmailService implements AutoCloseable {
|
|||
throw new NoSuchProviderException(protocol);
|
||||
}
|
||||
|
||||
EmailService(Context context, EntityIdentity ident, int purpose, boolean debug) throws NoSuchProviderException {
|
||||
this(context, ident.getProtocol(), ident.realm, ident.encryption, ident.insecure, ident.dane, ident.unicode, purpose, debug);
|
||||
}
|
||||
|
||||
EmailService(Context context, EntityAccount account, int purpose, boolean debug) throws NoSuchProviderException {
|
||||
this(context, account.getProtocol(), account.realm, account.encryption, account.insecure, account.dane, account.unicode, purpose, debug);
|
||||
}
|
||||
|
||||
void setPartialFetch(boolean enabled) {
|
||||
properties.put("mail." + protocol + ".partialfetch", Boolean.toString(enabled));
|
||||
}
|
||||
|
@ -454,7 +460,7 @@ public class EmailService implements AutoCloseable {
|
|||
boolean bc = prefs.getBoolean("bouncy_castle", false);
|
||||
boolean fips = prefs.getBoolean("bc_fips", false);
|
||||
factory = new SSLSocketFactoryService(
|
||||
context, host, insecure,
|
||||
context, host, port, insecure, dane,
|
||||
ssl_harden, strict, cert_strict, cert_transparency, check_names,
|
||||
bc, fips, key, chain, fingerprint);
|
||||
properties.put("mail." + protocol + ".ssl.socketFactory", factory);
|
||||
|
@ -1042,8 +1048,10 @@ public class EmailService implements AutoCloseable {
|
|||
private SSLSocketFactory factory;
|
||||
private X509Certificate certificate;
|
||||
|
||||
SSLSocketFactoryService(Context context, String host, boolean insecure,
|
||||
boolean ssl_harden, boolean ssl_harden_strict, boolean cert_strict, boolean cert_transparency, boolean check_names,
|
||||
SSLSocketFactoryService(Context context, String host, int port,
|
||||
boolean insecure, boolean dane,
|
||||
boolean ssl_harden, boolean ssl_harden_strict, boolean cert_strict, boolean cert_transparency,
|
||||
boolean check_names,
|
||||
boolean bc, boolean fips,
|
||||
PrivateKey key, X509Certificate[] chain, String fingerprint) throws GeneralSecurityException {
|
||||
this.server = host;
|
||||
|
@ -1053,7 +1061,7 @@ public class EmailService implements AutoCloseable {
|
|||
this.trustedFingerprint = fingerprint;
|
||||
|
||||
TrustManager[] tms = SSLHelper.getTrustManagers(
|
||||
context, server, secure, cert_strict, cert_transparency, check_names, trustedFingerprint,
|
||||
context, server, port, secure, dane, cert_strict, cert_transparency, check_names, trustedFingerprint,
|
||||
new SSLHelper.ITrust() {
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain) {
|
||||
|
|
|
@ -81,6 +81,8 @@ public class EntityAccount extends EntityOrder implements Serializable {
|
|||
@NonNull
|
||||
public Boolean insecure = false;
|
||||
@NonNull
|
||||
public Boolean dane = false;
|
||||
@NonNull
|
||||
public Integer port;
|
||||
@NonNull
|
||||
public Integer auth_type;
|
||||
|
|
|
@ -75,6 +75,8 @@ public class EntityIdentity {
|
|||
@NonNull
|
||||
public Boolean insecure = false;
|
||||
@NonNull
|
||||
public Boolean dane = false;
|
||||
@NonNull
|
||||
public Integer port;
|
||||
@NonNull
|
||||
public Integer auth_type;
|
||||
|
|
|
@ -101,6 +101,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
private RadioGroup rgEncryption;
|
||||
private CheckBox cbInsecure;
|
||||
private TextView tvInsecureRemark;
|
||||
private CheckBox cbDane;
|
||||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
|
@ -224,6 +225,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
rgEncryption = view.findViewById(R.id.rgEncryption);
|
||||
cbInsecure = view.findViewById(R.id.cbInsecure);
|
||||
tvInsecureRemark = view.findViewById(R.id.tvInsecureRemark);
|
||||
cbDane = view.findViewById(R.id.cbDane);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvAppPassword = view.findViewById(R.id.tvAppPassword);
|
||||
|
@ -366,6 +368,13 @@ public class FragmentAccount extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
cbInsecure.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
|
||||
cbDane.setEnabled(!checked);
|
||||
}
|
||||
});
|
||||
|
||||
tvInsecureRemark.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -631,6 +640,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
if (!SSLHelper.customTrustManager()) {
|
||||
Helper.hide(cbInsecure);
|
||||
Helper.hide(tvInsecureRemark);
|
||||
Helper.hide(cbDane);
|
||||
}
|
||||
|
||||
if (id < 0)
|
||||
|
@ -729,6 +739,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
|
||||
args.putInt("encryption", encryption);
|
||||
args.putBoolean("insecure", cbInsecure.isChecked());
|
||||
args.putBoolean("dane", cbDane.isChecked());
|
||||
args.putString("port", etPort.getText().toString());
|
||||
args.putInt("auth", auth);
|
||||
args.putString("provider", provider);
|
||||
|
@ -774,6 +785,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
String host = args.getString("host");
|
||||
int encryption = args.getInt("encryption");
|
||||
boolean insecure = args.getBoolean("insecure");
|
||||
boolean dane = args.getBoolean("dane");
|
||||
String port = args.getString("port");
|
||||
int auth = args.getInt("auth");
|
||||
String provider = args.getString("provider");
|
||||
|
@ -808,8 +820,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
|
||||
// Check IMAP server / get folders
|
||||
String protocol = "imap" + (encryption == EmailService.ENCRYPTION_SSL ? "s" : "");
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, protocol, realm, encryption, insecure, unicode,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
protocol, realm, encryption, insecure, dane, unicode,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
host, Integer.parseInt(port),
|
||||
|
@ -938,6 +950,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
|
||||
args.putInt("encryption", encryption);
|
||||
args.putBoolean("insecure", cbInsecure.isChecked());
|
||||
args.putBoolean("dane", cbDane.isChecked());
|
||||
args.putString("port", etPort.getText().toString());
|
||||
args.putInt("auth", auth);
|
||||
args.putString("provider", provider);
|
||||
|
@ -1015,6 +1028,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
String host = args.getString("host");
|
||||
int encryption = args.getInt("encryption");
|
||||
boolean insecure = args.getBoolean("insecure");
|
||||
boolean dane = args.getBoolean("dane");
|
||||
String port = args.getString("port");
|
||||
int auth = args.getInt("auth");
|
||||
String provider = args.getString("provider");
|
||||
|
@ -1111,6 +1125,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
return true;
|
||||
if (!Objects.equals(account.insecure, insecure))
|
||||
return true;
|
||||
if (!Objects.equals(account.dane, dane))
|
||||
return true;
|
||||
if (!Objects.equals(account.port, Integer.parseInt(port)))
|
||||
return true;
|
||||
if (account.auth_type != auth)
|
||||
|
@ -1211,6 +1227,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
!account.host.equals(host) ||
|
||||
!account.encryption.equals(encryption) ||
|
||||
!account.insecure.equals(insecure) ||
|
||||
!account.dane.equals(dane) ||
|
||||
!account.port.equals(Integer.parseInt(port)) ||
|
||||
!account.user.equals(user) ||
|
||||
!account.password.equals(password) ||
|
||||
|
@ -1228,8 +1245,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
EntityFolder inbox = null;
|
||||
if (check) {
|
||||
String protocol = "imap" + (encryption == EmailService.ENCRYPTION_SSL ? "s" : "");
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, protocol, realm, encryption, insecure, unicode,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
protocol, realm, encryption, insecure, dane, unicode,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
host, Integer.parseInt(port),
|
||||
|
@ -1277,6 +1294,7 @@ public class FragmentAccount extends FragmentBase {
|
|||
account.host = host;
|
||||
account.encryption = encryption;
|
||||
account.insecure = insecure;
|
||||
account.dane = dane;
|
||||
account.port = Integer.parseInt(port);
|
||||
account.auth_type = auth;
|
||||
account.user = user;
|
||||
|
@ -1673,6 +1691,8 @@ public class FragmentAccount extends FragmentBase {
|
|||
rgEncryption.check(R.id.radio_ssl);
|
||||
|
||||
cbInsecure.setChecked(account == null ? false : account.insecure);
|
||||
cbDane.setChecked(account == null ? false : account.dane);
|
||||
cbDane.setEnabled(!cbInsecure.isChecked());
|
||||
|
||||
etUser.setText(account == null ? null : account.user);
|
||||
tilPassword.getEditText().setText(account == null ? null : account.password);
|
||||
|
|
|
@ -479,8 +479,8 @@ public class FragmentGmail extends FragmentBase {
|
|||
EmailProvider.Server inbound = (pop ? provider.pop : provider.imap);
|
||||
String aprotocol = (pop ? (inbound.starttls ? "pop3" : "pop3s") : (inbound.starttls ? "imap" : "imaps"));
|
||||
int aencryption = (inbound.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
|
||||
try (EmailService aservice = new EmailService(
|
||||
context, aprotocol, null, aencryption, false, false,
|
||||
try (EmailService aservice = new EmailService(context,
|
||||
aprotocol, null, aencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
aservice.connect(
|
||||
inbound.host, inbound.port,
|
||||
|
@ -497,8 +497,8 @@ public class FragmentGmail extends FragmentBase {
|
|||
Long max_size;
|
||||
String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps");
|
||||
int iencryption = (provider.smtp.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, iprotocol, null, iencryption, false, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
iprotocol, null, iencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
provider.smtp.host, provider.smtp.port,
|
||||
|
|
|
@ -102,6 +102,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
private RadioGroup rgEncryption;
|
||||
private CheckBox cbInsecure;
|
||||
private TextView tvInsecureRemark;
|
||||
private CheckBox cbDane;
|
||||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
|
@ -209,6 +210,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
rgEncryption = view.findViewById(R.id.rgEncryption);
|
||||
cbInsecure = view.findViewById(R.id.cbInsecure);
|
||||
tvInsecureRemark = view.findViewById(R.id.tvInsecureRemark);
|
||||
cbDane = view.findViewById(R.id.cbDane);
|
||||
etPort = view.findViewById(R.id.etPort);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
|
@ -466,6 +468,13 @@ public class FragmentIdentity extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
cbInsecure.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
|
||||
cbDane.setEnabled(!checked);
|
||||
}
|
||||
});
|
||||
|
||||
tvInsecureRemark.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -570,6 +579,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
if (!SSLHelper.customTrustManager()) {
|
||||
Helper.hide(cbInsecure);
|
||||
Helper.hide(tvInsecureRemark);
|
||||
Helper.hide(cbDane);
|
||||
}
|
||||
|
||||
btnAdvanced.setVisibility(View.GONE);
|
||||
|
@ -768,6 +778,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
|
||||
args.putInt("encryption", encryption);
|
||||
args.putBoolean("insecure", cbInsecure.isChecked());
|
||||
args.putBoolean("dane", cbDane.isChecked());
|
||||
args.putString("port", etPort.getText().toString());
|
||||
args.putInt("auth", auth);
|
||||
args.putString("provider", provider);
|
||||
|
@ -821,6 +832,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
String host = args.getString("host");
|
||||
int encryption = args.getInt("encryption");
|
||||
boolean insecure = args.getBoolean("insecure");
|
||||
boolean dane = args.getBoolean("dane");
|
||||
String port = args.getString("port");
|
||||
int auth = args.getInt("auth");
|
||||
String provider = args.getString("provider");
|
||||
|
@ -967,6 +979,8 @@ public class FragmentIdentity extends FragmentBase {
|
|||
return true;
|
||||
if (!Objects.equals(identity.insecure, insecure))
|
||||
return true;
|
||||
if (!Objects.equals(identity.dane, dane))
|
||||
return true;
|
||||
if (!Objects.equals(identity.port, Integer.parseInt(port)))
|
||||
return true;
|
||||
if (identity.auth_type != auth)
|
||||
|
@ -1036,6 +1050,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
!host.equals(identity.host) ||
|
||||
encryption != identity.encryption ||
|
||||
insecure != identity.insecure ||
|
||||
dane != identity.dane ||
|
||||
Integer.parseInt(port) != identity.port ||
|
||||
!user.equals(identity.user) ||
|
||||
!password.equals(identity.password) ||
|
||||
|
@ -1057,8 +1072,8 @@ public class FragmentIdentity extends FragmentBase {
|
|||
if (check) {
|
||||
// Create transport
|
||||
String protocol = (encryption == EmailService.ENCRYPTION_SSL ? "smtps" : "smtp");
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, protocol, realm, encryption, insecure, unicode,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
protocol, realm, encryption, insecure, dane, unicode,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.setUseIp(use_ip, ehlo);
|
||||
iservice.connect(
|
||||
|
@ -1094,6 +1109,7 @@ public class FragmentIdentity extends FragmentBase {
|
|||
identity.host = host;
|
||||
identity.encryption = encryption;
|
||||
identity.insecure = insecure;
|
||||
identity.dane = dane;
|
||||
identity.port = Integer.parseInt(port);
|
||||
identity.auth_type = auth;
|
||||
identity.user = user;
|
||||
|
@ -1274,6 +1290,8 @@ public class FragmentIdentity extends FragmentBase {
|
|||
rgEncryption.check(R.id.radio_ssl);
|
||||
|
||||
cbInsecure.setChecked(identity == null ? false : identity.insecure);
|
||||
cbDane.setChecked(identity == null ? false : identity.dane);
|
||||
cbDane.setEnabled(!cbInsecure.isChecked());
|
||||
etPort.setText(identity == null ? null : Long.toString(identity.port));
|
||||
etUser.setText(identity == null ? null : identity.user);
|
||||
tilPassword.getEditText().setText(identity == null ? null : identity.password);
|
||||
|
|
|
@ -817,8 +817,8 @@ public class FragmentOAuth extends FragmentBase {
|
|||
for (String alt : usernames) {
|
||||
EntityLog.log(context, "Trying username=" + alt);
|
||||
try {
|
||||
try (EmailService aservice = new EmailService(
|
||||
context, aprotocol, null, aencryption, false, false,
|
||||
try (EmailService aservice = new EmailService(context,
|
||||
aprotocol, null, aencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
aservice.connect(
|
||||
inbound.host, inbound.port,
|
||||
|
@ -827,8 +827,8 @@ public class FragmentOAuth extends FragmentBase {
|
|||
null, null);
|
||||
}
|
||||
if (state.length == 1) {
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, iprotocol, null, iencryption, false, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
iprotocol, null, iencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
provider.smtp.host, provider.smtp.port,
|
||||
|
@ -892,8 +892,8 @@ public class FragmentOAuth extends FragmentBase {
|
|||
List<EntityFolder> folders;
|
||||
|
||||
EntityLog.log(context, "OAuth checking IMAP/POP3 provider=" + provider.id);
|
||||
try (EmailService aservice = new EmailService(
|
||||
context, aprotocol, null, aencryption, false, false,
|
||||
try (EmailService aservice = new EmailService(context,
|
||||
aprotocol, null, aencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
aservice.connect(
|
||||
inbound.host, inbound.port,
|
||||
|
@ -911,8 +911,8 @@ public class FragmentOAuth extends FragmentBase {
|
|||
if (!inbound_only && state.length == 1) {
|
||||
EntityLog.log(context, "OAuth checking SMTP provider=" + provider.id);
|
||||
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, iprotocol, null, iencryption, false, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
iprotocol, null, iencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
provider.smtp.host, provider.smtp.port,
|
||||
|
|
|
@ -76,6 +76,7 @@ public class FragmentPop extends FragmentBase {
|
|||
private RadioGroup rgEncryption;
|
||||
private CheckBox cbInsecure;
|
||||
private TextView tvInsecureRemark;
|
||||
private CheckBox cbDane;
|
||||
private EditText etPort;
|
||||
private EditText etUser;
|
||||
private TextInputLayout tilPassword;
|
||||
|
@ -156,6 +157,7 @@ public class FragmentPop extends FragmentBase {
|
|||
rgEncryption = view.findViewById(R.id.rgEncryption);
|
||||
cbInsecure = view.findViewById(R.id.cbInsecure);
|
||||
tvInsecureRemark = view.findViewById(R.id.tvInsecureRemark);
|
||||
cbDane = view.findViewById(R.id.cbDane);
|
||||
etUser = view.findViewById(R.id.etUser);
|
||||
tilPassword = view.findViewById(R.id.tilPassword);
|
||||
tvPasswordStorage = view.findViewById(R.id.tvPasswordStorage);
|
||||
|
@ -207,6 +209,13 @@ public class FragmentPop extends FragmentBase {
|
|||
}
|
||||
});
|
||||
|
||||
cbInsecure.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean checked) {
|
||||
cbDane.setEnabled(!checked);
|
||||
}
|
||||
});
|
||||
|
||||
tvInsecureRemark.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
@ -356,6 +365,7 @@ public class FragmentPop extends FragmentBase {
|
|||
if (!SSLHelper.customTrustManager()) {
|
||||
Helper.hide(cbInsecure);
|
||||
Helper.hide(tvInsecureRemark);
|
||||
Helper.hide(cbDane);
|
||||
}
|
||||
|
||||
if (id < 0)
|
||||
|
@ -384,6 +394,7 @@ public class FragmentPop extends FragmentBase {
|
|||
args.putString("host", etHost.getText().toString().trim().replace(" ", ""));
|
||||
args.putInt("encryption", encryption);
|
||||
args.putBoolean("insecure", cbInsecure.isChecked());
|
||||
args.putBoolean("dane", cbDane.isChecked());
|
||||
args.putString("port", etPort.getText().toString());
|
||||
args.putInt("auth", auth);
|
||||
args.putString("user", etUser.getText().toString());
|
||||
|
@ -441,6 +452,7 @@ public class FragmentPop extends FragmentBase {
|
|||
String host = args.getString("host");
|
||||
int encryption = args.getInt("encryption");
|
||||
boolean insecure = args.getBoolean("insecure");
|
||||
boolean dane = args.getBoolean("dane");
|
||||
String port = args.getString("port");
|
||||
int auth = args.getInt("auth");
|
||||
String user = args.getString("user").trim();
|
||||
|
@ -526,6 +538,8 @@ public class FragmentPop extends FragmentBase {
|
|||
return true;
|
||||
if (!Objects.equals(account.insecure, insecure))
|
||||
return true;
|
||||
if (!Objects.equals(account.dane, dane))
|
||||
return true;
|
||||
if (!Objects.equals(account.port, Integer.parseInt(port)))
|
||||
return true;
|
||||
if (!Objects.equals(account.user, user))
|
||||
|
@ -585,6 +599,7 @@ public class FragmentPop extends FragmentBase {
|
|||
!account.host.equals(host) ||
|
||||
!account.encryption.equals(encryption) ||
|
||||
!account.insecure.equals(insecure) ||
|
||||
!account.dane.equals(dane) ||
|
||||
!account.port.equals(Integer.parseInt(port)) ||
|
||||
!account.user.equals(user) ||
|
||||
!account.password.equals(password) ||
|
||||
|
@ -598,8 +613,8 @@ public class FragmentPop extends FragmentBase {
|
|||
// Check POP3 server
|
||||
if (check) {
|
||||
String protocol = "pop3" + (encryption == EmailService.ENCRYPTION_SSL ? "s" : "");
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, protocol, null, encryption, insecure, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
protocol, null, encryption, insecure, dane, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.connect(
|
||||
host, Integer.parseInt(port),
|
||||
|
@ -629,6 +644,7 @@ public class FragmentPop extends FragmentBase {
|
|||
account.host = host;
|
||||
account.encryption = encryption;
|
||||
account.insecure = insecure;
|
||||
account.dane = dane;
|
||||
account.port = Integer.parseInt(port);
|
||||
account.auth_type = auth;
|
||||
account.user = user;
|
||||
|
@ -832,6 +848,8 @@ public class FragmentPop extends FragmentBase {
|
|||
rgEncryption.check(R.id.radio_ssl);
|
||||
|
||||
cbInsecure.setChecked(account == null ? false : account.insecure);
|
||||
cbDane.setChecked(account == null ? false : account.dane);
|
||||
cbDane.setEnabled(!cbInsecure.isChecked());
|
||||
|
||||
etUser.setText(account == null ? null : account.user);
|
||||
tilPassword.getEditText().setText(account == null ? null : account.password);
|
||||
|
|
|
@ -430,8 +430,8 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
String user = null;
|
||||
String aprotocol = (provider.imap.starttls ? "imap" : "imaps");
|
||||
int aencryption = (provider.imap.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, aprotocol, null, aencryption, false, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
aprotocol, null, aencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
List<Throwable> exceptions = new ArrayList<>();
|
||||
for (int i = 0; i < users.size(); i++) {
|
||||
|
@ -539,8 +539,8 @@ public class FragmentQuickSetup extends FragmentBase {
|
|||
Long max_size;
|
||||
String iprotocol = (provider.smtp.starttls ? "smtp" : "smtps");
|
||||
int iencryption = (provider.smtp.starttls ? EmailService.ENCRYPTION_STARTTLS : EmailService.ENCRYPTION_SSL);
|
||||
try (EmailService iservice = new EmailService(
|
||||
context, iprotocol, null, iencryption, false, false,
|
||||
try (EmailService iservice = new EmailService(context,
|
||||
iprotocol, null, iencryption, false, false, false,
|
||||
EmailService.PURPOSE_CHECK, true)) {
|
||||
iservice.setUseIp(provider.useip, null);
|
||||
try {
|
||||
|
|
|
@ -29,6 +29,8 @@ import com.appmattus.certificatetransparency.CTTrustManagerBuilder;
|
|||
import com.appmattus.certificatetransparency.VerificationResult;
|
||||
import com.appmattus.certificatetransparency.cache.AndroidDiskCache;
|
||||
|
||||
import org.minidns.dane.DaneVerifier;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyStore;
|
||||
|
@ -39,6 +41,9 @@ import java.security.cert.CertificateExpiredException;
|
|||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
@ -46,7 +51,10 @@ import javax.net.ssl.X509TrustManager;
|
|||
|
||||
public class SSLHelper {
|
||||
static TrustManager[] getTrustManagers(
|
||||
Context context, String server, boolean secure, boolean cert_strict, boolean transparency, boolean check_names, String trustedFingerprint, ITrust intf) {
|
||||
Context context, String server, int port,
|
||||
boolean secure, boolean dane, boolean cert_strict, boolean transparency, boolean check_names,
|
||||
String trustedFingerprint,
|
||||
ITrust intf) {
|
||||
TrustManagerFactory tmf;
|
||||
try {
|
||||
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
|
@ -122,6 +130,31 @@ public class SSLHelper {
|
|||
throw new CertificateException(principal.getName(), ex);
|
||||
}
|
||||
|
||||
if (dane) {
|
||||
Handler handler = new Handler() {
|
||||
@Override
|
||||
public void publish(LogRecord record) {
|
||||
Log.w("DANE " + record.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws SecurityException {
|
||||
}
|
||||
};
|
||||
String clazz = DaneVerifier.class.getName();
|
||||
Logger.getLogger(clazz).addHandler(handler);
|
||||
Log.w("DANE verify " + server + ":" + port);
|
||||
boolean verified = new DaneVerifier().verifyCertificateChain(chain, server, port);
|
||||
Log.w("DANE verified=" + verified + " " + server + ":" + port);
|
||||
Logger.getLogger(clazz).removeHandler(handler);
|
||||
if (!verified)
|
||||
throw new CertificateException("DANE missing or invalid");
|
||||
}
|
||||
|
||||
// Check host name
|
||||
if (check_names) {
|
||||
List<String> names = EntityCertificate.getDnsNames(chain[0]);
|
||||
|
|
|
@ -752,8 +752,7 @@ public class ServiceSend extends ServiceBase implements SharedPreferences.OnShar
|
|||
MicrosoftGraph.send(ServiceSend.this, ident, imessage);
|
||||
end = new Date().getTime();
|
||||
} else {
|
||||
EmailService iservice = new EmailService(
|
||||
this, ident.getProtocol(), ident.realm, ident.encryption, ident.insecure, ident.unicode, debug);
|
||||
EmailService iservice = new EmailService(this, ident, EmailService.PURPOSE_USE, debug);
|
||||
try {
|
||||
iservice.setUseIp(ident.use_ip, ident.ehlo);
|
||||
if (!message.isSigned() && !message.isEncrypted())
|
||||
|
|
|
@ -1591,8 +1591,7 @@ public class ServiceSynchronize extends ServiceBase implements SharedPreferences
|
|||
boolean empty_pool = prefs.getBoolean("empty_pool", true);
|
||||
boolean debug = (prefs.getBoolean("debug", false) || BuildConfig.DEBUG);
|
||||
|
||||
final EmailService iservice = new EmailService(
|
||||
this, account.getProtocol(), account.realm, account.encryption, account.insecure, account.unicode, debug);
|
||||
final EmailService iservice = new EmailService(this, account, EmailService.PURPOSE_USE, debug);
|
||||
iservice.setPartialFetch(account.partial_fetch);
|
||||
iservice.setRawFetch(account.raw_fetch);
|
||||
iservice.setIgnoreBodyStructureSize(account.ignore_size);
|
||||
|
|
|
@ -204,6 +204,29 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbInsecure" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbDane"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_dane"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDaneRemark"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/title_dane_remark"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbDane" />
|
||||
|
||||
<!-- port -->
|
||||
|
||||
<TextView
|
||||
|
@ -214,7 +237,7 @@
|
|||
android:text="@string/title_port"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDaneRemark" />
|
||||
|
||||
<eu.faircode.email.EditTextPlain
|
||||
android:id="@+id/etPort"
|
||||
|
@ -1178,7 +1201,7 @@
|
|||
android:layout_height="0dp"
|
||||
app:constraint_referenced_ids="
|
||||
tvDomain,tvDomainHint,etDomain,btnAutoConfig,
|
||||
tvImap,tvHost,etHost,tvEncryption,rgEncryption,cbInsecure,tvInsecureRemark,tvPort,etPort" />
|
||||
tvImap,tvHost,etHost,tvEncryption,rgEncryption,cbInsecure,tvInsecureRemark,cbDane,tvDaneRemark,tvPort,etPort" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/grpAuthorize"
|
||||
|
|
|
@ -355,6 +355,29 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbInsecure" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbDane"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_dane"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDaneRemark"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/title_dane_remark"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbDane" />
|
||||
|
||||
<!-- port -->
|
||||
|
||||
<TextView
|
||||
|
@ -365,7 +388,7 @@
|
|||
android:text="@string/title_port"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDaneRemark" />
|
||||
|
||||
<eu.faircode.email.EditTextPlain
|
||||
android:id="@+id/etPort"
|
||||
|
@ -1075,7 +1098,7 @@
|
|||
app:constraint_referenced_ids="
|
||||
tvProvider,spProvider,
|
||||
tvDomain,tvDomainHint,etDomain,btnAutoConfig,
|
||||
tvSmtp,tvHost,etHost,tvEncryption,rgEncryption,cbInsecure,tvInsecureRemark,tvPort,etPort,
|
||||
tvSmtp,tvHost,etHost,tvEncryption,rgEncryption,cbInsecure,tvInsecureRemark,cbDane,tvDaneRemark,tvPort,etPort,
|
||||
tvUser,etUser,tvPassword,tilPassword,tvCaseSensitiveHint,tvPasswordStorage,
|
||||
btnCertificate,tvCertificate,
|
||||
tvRealm,etRealm,
|
||||
|
|
|
@ -135,6 +135,29 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbInsecure" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/cbDane"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/title_dane"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvDaneRemark"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:text="@string/title_dane_remark"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textStyle="italic"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/cbDane" />
|
||||
|
||||
<!-- port -->
|
||||
|
||||
<TextView
|
||||
|
@ -145,7 +168,7 @@
|
|||
android:text="@string/title_port"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tvInsecureRemark" />
|
||||
app:layout_constraintTop_toBottomOf="@id/tvDaneRemark" />
|
||||
|
||||
<eu.faircode.email.EditTextPlain
|
||||
android:id="@+id/etPort"
|
||||
|
|
|
@ -1192,6 +1192,8 @@
|
|||
<string name="title_encryption_none">None (insecure)</string>
|
||||
<string name="title_allow_insecure">Allow insecure connections</string>
|
||||
<string name="title_insecure_remark">Insecure connections should only be allowed on trusted networks and never on public networks</string>
|
||||
<string name="title_dane">Enforce DANE</string>
|
||||
<string name="title_dane_remark">Only some mail servers support DNS-based Authentication of Named Entities</string>
|
||||
<string name="title_notify_remark">You can enable this for account specific notifications</string>
|
||||
<string name="title_port">Port number</string>
|
||||
<string name="title_user">User name</string>
|
||||
|
|
Loading…
Reference in New Issue