TLS debugging

pull/194/merge
M66B 4 years ago
parent 5603fe88ca
commit f0cf46db94

@ -2255,11 +2255,12 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
message.headers, message.blocklist != null && message.blocklist); message.headers, message.blocklist != null && message.blocklist);
if (BuildConfig.DEBUG && headers instanceof SpannableStringBuilder) { if (BuildConfig.DEBUG && headers instanceof SpannableStringBuilder) {
SpannableStringBuilder ssb = (SpannableStringBuilder) headers; SpannableStringBuilder ssb = (SpannableStringBuilder) headers;
ssb.append("TLS=" + message.tls).append('\n'); ssb.append("TLS=" + message.tls)
ssb.append("DKIM=" + message.dkim).append('\n'); .append(" DKIM=" + message.dkim)
ssb.append("SPF=" + message.spf).append('\n'); .append(" SPF=" + message.spf)
ssb.append("DMARC=" + message.dmarc).append('\n'); .append(" DMARC=" + message.dmarc)
ssb.append("BL=" + message.blocklist).append('\n'); .append(" BL=" + message.blocklist)
.append('\n');
} }
tvHeaders.setText(headers); tvHeaders.setText(headers);
ibCopyHeaders.setVisibility(View.VISIBLE); ibCopyHeaders.setVisibility(View.VISIBLE);

@ -2380,6 +2380,8 @@ public class HtmlHelper {
static Spanned highlightHeaders(Context context, String headers, boolean blocklist) { static Spanned highlightHeaders(Context context, String headers, boolean blocklist) {
SpannableStringBuilder ssb = new SpannableStringBuilderEx(headers); SpannableStringBuilder ssb = new SpannableStringBuilderEx(headers);
int textColorLink = Helper.resolveColor(context, android.R.attr.textColorLink); int textColorLink = Helper.resolveColor(context, android.R.attr.textColorLink);
int colorVerified = Helper.resolveColor(context, R.attr.colorVerified);
int colorWarning = Helper.resolveColor(context, R.attr.colorWarning);
int index = 0; int index = 0;
for (String line : headers.split("\n")) { for (String line : headers.split("\n")) {
@ -2421,8 +2423,6 @@ public class HtmlHelper {
int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size); int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size);
d.setBounds(0, 0, iconSize, iconSize); d.setBounds(0, 0, iconSize, iconSize);
int colorWarning = Helper.resolveColor(context, R.attr.colorWarning);
d.setTint(colorWarning); d.setTint(colorWarning);
ssb.append(" \uFFFC"); // Object replacement character ssb.append(" \uFFFC"); // Object replacement character
@ -2462,6 +2462,14 @@ public class HtmlHelper {
j++; j++;
} }
Boolean tls = MessageHelper.isTLS(h);
ssb.append(" TLS=");
int t = ssb.length();
ssb.append(tls == null ? "?" : Boolean.toString(tls));
if (tls != null)
ssb.setSpan(new ForegroundColorSpan(tls ? colorVerified : colorWarning), t, ssb.length(), 0);
ssb.append("\n\n"); ssb.append("\n\n");
} }
} }

@ -2055,121 +2055,127 @@ public class MessageHelper {
for (String r : received) { for (String r : received) {
String header = MimeUtility.unfold(r); String header = MimeUtility.unfold(r);
Log.i("--- header=" + header); Log.i("--- header=" + header);
Boolean tls = isTLS(header);
if (!Boolean.TRUE.equals(tls))
return tls;
}
// Strip date return true;
int semi = header.lastIndexOf(';'); }
if (semi > 0)
header = header.substring(0, semi);
if (header.contains("using TLS") || static Boolean isTLS(String header) {
header.contains("version=TLS")) { // Strip date
Log.i("--- found TLS"); int semi = header.lastIndexOf(';');
continue; if (semi > 0)
} header = header.substring(0, semi);
// (qmail nnn invoked by uid nnn); 1 Jan 2022 00:00:00 -0000 if (header.contains("using TLS") ||
if (header.contains("qmail") && header.contains("invoked by uid")) { header.contains("version=TLS")) {
Log.i("--- found qmail"); Log.i("--- found TLS");
continue; return true;
} }
// Get key/values // (qmail nnn invoked by uid nnn); 1 Jan 2022 00:00:00 -0000
String[] parts = header.split("\\s+"); if (header.contains("qmail") && header.contains("invoked by uid")) {
Map<String, StringBuilder> kv = new HashMap<>(); Log.i("--- found qmail");
String key = null; return true;
for (int p = 0; p < parts.length; p++) { }
String k = parts[p].toLowerCase(Locale.ROOT);
if (RECEIVED_WORDS.contains(k)) { // Get key/values
key = k; String[] parts = header.split("\\s+");
if (!kv.containsKey(key)) Map<String, StringBuilder> kv = new HashMap<>();
kv.put(key, new StringBuilder()); String key = null;
} else if (key != null) { for (int p = 0; p < parts.length; p++) {
StringBuilder sb = kv.get(key); String k = parts[p].toLowerCase(Locale.ROOT);
if (sb.length() > 0) if (RECEIVED_WORDS.contains(k)) {
sb.append(' '); key = k;
sb.append(parts[p]); if (!kv.containsKey(key))
} kv.put(key, new StringBuilder());
} else if (key != null) {
StringBuilder sb = kv.get(key);
if (sb.length() > 0)
sb.append(' ');
sb.append(parts[p]);
} }
}
// Dump // Dump
for (String k : kv.keySet()) for (String k : kv.keySet())
Log.i("--- " + k + "=" + kv.get(k)); Log.i("--- " + k + "=" + kv.get(k));
// Check if 'by' local address // Check if 'by' local address
if (kv.containsKey("by")) { if (kv.containsKey("by")) {
String by = kv.get("by").toString(); String by = kv.get("by").toString();
if (isLocal(by)) { if (isLocal(by)) {
Log.i("--- local by=" + by); Log.i("--- local by=" + by);
continue; return true;
}
} }
}
// Check if 'from' local address // Check if 'from' local address
if (kv.containsKey("from")) { if (kv.containsKey("from")) {
String from = kv.get("from").toString(); String from = kv.get("from").toString();
if (isLocal(from)) { if (isLocal(from)) {
Log.i("--- local from=" + from); Log.i("--- local from=" + from);
continue; return true;
}
} }
}
// Check Microsoft front end transport (proxy) // Check Microsoft front end transport (proxy)
// https://social.technet.microsoft.com/wiki/contents/articles/50370.exchange-2016-what-is-the-front-end-transport-service-on-the-mailbox-role.aspx // https://social.technet.microsoft.com/wiki/contents/articles/50370.exchange-2016-what-is-the-front-end-transport-service-on-the-mailbox-role.aspx
if (kv.containsKey("via")) { if (kv.containsKey("via")) {
String via = kv.get("via").toString(); String via = kv.get("via").toString();
if ("Frontend Transport".equals(via)) { if ("Frontend Transport".equals(via)) {
Log.i("--- frontend via=" + via); Log.i("--- frontend via=" + via);
continue; return true;
}
} }
}
// Check protocol // Check protocol
if (!kv.containsKey("with")) { if (!kv.containsKey("with")) {
Log.i("--- with missing"); Log.i("--- with missing");
return null; return null;
} }
// https://datatracker.ietf.org/doc/html/rfc3848 // https://datatracker.ietf.org/doc/html/rfc3848
// https://www.iana.org/assignments/mail-parameters/mail-parameters.txt // https://www.iana.org/assignments/mail-parameters/mail-parameters.txt
String with = kv.get("with").toString(); String with = kv.get("with").toString();
int w = with.indexOf(' '); int w = with.indexOf(' ');
String protocol = (w < 0 ? with : with.substring(0, w)).toLowerCase(Locale.ROOT); String protocol = (w < 0 ? with : with.substring(0, w)).toLowerCase(Locale.ROOT);
if ("local".equals(protocol)) { if ("local".equals(protocol)) {
// Exim // Exim
Log.i("--- local with=" + with); Log.i("--- local with=" + with);
continue; return true;
} }
if ("mapi".equals(protocol)) { if ("mapi".equals(protocol)) {
// https://en.wikipedia.org/wiki/MAPI // https://en.wikipedia.org/wiki/MAPI
Log.i("--- mapi with=" + with); Log.i("--- mapi with=" + with);
continue; return true;
} }
if ("http".equals(protocol) || if ("http".equals(protocol) ||
"httprest".equals(protocol)) { "httprest".equals(protocol)) {
// httprest by gmailapi.google.com // httprest by gmailapi.google.com
Log.i("--- http with=" + with); Log.i("--- http with=" + with);
continue; return true;
} }
if (!protocol.contains("mtp")) { if (!protocol.contains("mtp")) {
Log.i("--- unknown with=" + with); Log.i("--- unknown with=" + with);
return null; return null;
} }
if (!protocol.contains("mtps" /* STARTTLS */) && if (protocol.contains("mtps")) {
!protocol.contains("_mtpa" /* AUTH */)) { Log.i("--- insecure with=" + with);
Log.i("--- insecure with=" + with); return true;
return false;
}
} }
return true; return false;
} }
private boolean isLocal(String value) { private static boolean isLocal(String value) {
if (value.contains("localhost") || if (value.contains("localhost") ||
value.contains("[127.0.0.1]") || value.contains("[127.0.0.1]") ||
value.contains("[::1]")) value.contains("[::1]"))

Loading…
Cancel
Save