Show message signers

pull/212/head
M66B 2 years ago
parent bf91c80b7e
commit 1bd7b4cfdb

File diff suppressed because it is too large Load Diff

@ -272,6 +272,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private boolean avatars;
private boolean color_stripe;
private boolean check_authentication;
private boolean native_dkim;
private boolean check_tls;
private boolean check_reply_domain;
private boolean check_mx;
@ -400,6 +401,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private ImageButton ibPinContact;
private ImageButton ibAddContact;
private TextView tvSignedByTitle;
private TextView tvSubmitterTitle;
private TextView tvDeliveredToTitle;
private TextView tvFromExTitle;
@ -415,6 +417,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private TextView tvLanguageTitle;
private TextView tvThreadTitle;
private TextView tvSignedBy;
private TextView tvSubmitter;
private TextView tvDeliveredTo;
private TextView tvFromEx;
@ -806,6 +809,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ibPinContact = vsBody.findViewById(R.id.ibPinContact);
ibAddContact = vsBody.findViewById(R.id.ibAddContact);
tvSignedByTitle = vsBody.findViewById(R.id.tvSignedByTitle);
tvSubmitterTitle = vsBody.findViewById(R.id.tvSubmitterTitle);
tvDeliveredToTitle = vsBody.findViewById(R.id.tvDeliveredToTitle);
tvFromExTitle = vsBody.findViewById(R.id.tvFromExTitle);
@ -821,6 +825,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvLanguageTitle = vsBody.findViewById(R.id.tvLanguageTitle);
tvThreadTitle = vsBody.findViewById(R.id.tvThreadTitle);
tvSignedBy = vsBody.findViewById(R.id.tvSignedBy);
tvSubmitter = vsBody.findViewById(R.id.tvSubmitter);
tvDeliveredTo = vsBody.findViewById(R.id.tvDeliveredTo);
tvFromEx = vsBody.findViewById(R.id.tvFromEx);
@ -1680,6 +1685,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ibPinContact.setVisibility(View.GONE);
ibAddContact.setVisibility(View.GONE);
tvSignedByTitle.setVisibility(View.GONE);
tvSubmitterTitle.setVisibility(View.GONE);
tvDeliveredToTitle.setVisibility(View.GONE);
tvFromExTitle.setVisibility(View.GONE);
@ -1695,6 +1701,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
tvLanguageTitle.setVisibility(View.GONE);
tvThreadTitle.setVisibility(View.GONE);
tvSignedBy.setVisibility(View.GONE);
tvSubmitter.setVisibility(View.GONE);
tvDeliveredTo.setVisibility(View.GONE);
tvFromEx.setVisibility(View.GONE);
@ -2486,6 +2493,29 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
ibPinContact.setVisibility(show_addresses && pin && contacts && froms > 0 ? View.VISIBLE : View.GONE);
ibAddContact.setVisibility(show_addresses && contacts && froms > 0 ? View.VISIBLE : View.GONE);
boolean known_signer = false;
if (native_dkim &&
message.signedby != null &&
message.from != null &&
message.from.length == 1) {
String domain = UriHelper.getEmailDomain(((InternetAddress) message.from[0]).getAddress());
if (domain != null)
for (String signer : message.signedby.split(","))
if (signer.equals(domain)) {
known_signer = true;
break;
}
}
boolean show_signers = (native_dkim &&
message.signedby != null &&
(show_addresses || !known_signer));
tvSignedByTitle.setVisibility(show_signers ? View.VISIBLE : View.GONE);
tvSignedBy.setVisibility(show_signers ? View.VISIBLE : View.GONE);
tvSignedBy.setTextColor(known_signer ? textColorTertiary : colorAccent);
tvSignedBy.setText(message.signedby);
tvSubmitterTitle.setVisibility(!TextUtils.isEmpty(submitter) ? View.VISIBLE : View.GONE);
tvSubmitter.setVisibility(!TextUtils.isEmpty(submitter) ? View.VISIBLE : View.GONE);
tvSubmitter.setText(submitter);
@ -4578,6 +4608,14 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
.append(message.dmarc == null ? "-" : (message.dmarc ? "✓" : "✗"));
}
if (native_dkim && !TextUtils.isEmpty(message.signedby)) {
if (sb.length() > 0)
sb.append('\n');
sb.append("Signed by:").append('\n');
for (String signer : message.signedby.split(","))
sb.append(signer).append('\n');
}
if (Boolean.TRUE.equals(message.blocklist)) {
if (sb.length() > 0)
sb.append('\n');
@ -7402,6 +7440,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
this.avatars = (contacts && avatars) || (bimi || gravatars || libravatars || favicons || generated);
this.color_stripe = prefs.getBoolean("color_stripe", true);
this.check_authentication = prefs.getBoolean("check_authentication", true);
this.native_dkim = prefs.getBoolean("native_dkim", false);
this.check_tls = prefs.getBoolean("check_tls", true);
this.check_reply_domain = prefs.getBoolean("check_reply_domain", true);
this.check_mx = prefs.getBoolean("check_mx", false);
@ -7532,6 +7571,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
same = false;
log("bimi_selector changed", next.id);
}
if (!Objects.equals(prev.signedby, next.signedby)) {
same = false;
log("signedby changed", next.id);
}
if (!Objects.equals(prev.tls, next.tls)) {
same = false;
log("tls changed", next.id);

@ -4076,6 +4076,7 @@ class Core {
boolean download_headers = prefs.getBoolean("download_headers", false);
boolean download_plain = prefs.getBoolean("download_plain", false);
boolean notify_known = prefs.getBoolean("notify_known", false);
boolean native_dkim = prefs.getBoolean("native_dkim", false);
boolean experiments = prefs.getBoolean("experiments", false);
boolean pro = ActivityBilling.isPro(context);
@ -4255,15 +4256,14 @@ class Core {
message.receipt_request = helper.getReceiptRequested();
message.receipt_to = helper.getReceiptTo();
message.bimi_selector = helper.getBimiSelector();
if (native_dkim) {
List<String> signers = helper.verifyDKIM(context);
message.signedby = (signers.size() == 0 ? null : TextUtils.join(",", signers));
}
message.tls = helper.getTLS();
message.dkim = MessageHelper.getAuthentication("dkim", authentication);
if (BuildConfig.DEBUG &&
Boolean.TRUE.equals(message.dkim) &&
EntityFolder.JUNK.equals(folder.type)) {
Boolean dkim = helper.verifyDKIM(context);
flagged = Boolean.FALSE.equals(dkim);
color = android.graphics.Color.RED;
}
if (Boolean.TRUE.equals(message.dkim))
message.dkim = helper.checkDKIMRequirements();
message.spf = MessageHelper.getAuthentication("spf", authentication);

@ -68,7 +68,7 @@ import javax.mail.internet.InternetAddress;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 268,
version = 269,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -2741,6 +2741,12 @@ public abstract class DB extends RoomDatabase {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `folder` ADD COLUMN `count_unread` INTEGER NOT NULL DEFAULT 1");
}
}).addMigrations(new Migration(268, 269) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {
logMigration(startVersion, endVersion);
db.execSQL("ALTER TABLE `message` ADD COLUMN `signedby` TEXT");
}
}).addMigrations(new Migration(998, 999) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase db) {

@ -155,6 +155,7 @@ public class EntityMessage implements Serializable {
public Boolean receipt_request;
public Address[] receipt_to;
public String bimi_selector;
public String signedby;
public Boolean tls;
public Boolean dkim;
public Boolean spf;

@ -217,6 +217,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
private SeekBar sbMaxBackOff;
private SwitchCompat swLogarithmicBackoff;
private SwitchCompat swExactAlarms;
private SwitchCompat swNativeDkim;
private SwitchCompat swInfra;
private SwitchCompat swDupMsgId;
private EditText etKeywords;
@ -275,7 +276,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
"auth_plain", "auth_login", "auth_ntlm", "auth_sasl", "auth_apop", "use_top",
"keep_alive_poll", "empty_pool", "idle_done", "fast_fetch",
"max_backoff_power", "logarithmic_backoff",
"exact_alarms", "infra", "dkim_verify", "dup_msgids", "global_keywords", "test_iab"
"exact_alarms", "native_dkim", "infra", "dkim_verify", "dup_msgids", "global_keywords", "test_iab"
};
private final static String[] RESET_QUESTIONS = new String[]{
@ -440,6 +441,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
sbMaxBackOff = view.findViewById(R.id.sbMaxBackOff);
swLogarithmicBackoff = view.findViewById(R.id.swLogarithmicBackoff);
swExactAlarms = view.findViewById(R.id.swExactAlarms);
swNativeDkim = view.findViewById(R.id.swNativeDkim);
swInfra = view.findViewById(R.id.swInfra);
swDupMsgId = view.findViewById(R.id.swDupMsgId);
etKeywords = view.findViewById(R.id.etKeywords);
@ -1585,6 +1587,13 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
}
});
swNativeDkim.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
prefs.edit().putBoolean("native_dkim", checked).apply();
}
});
swInfra.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean checked) {
@ -2293,6 +2302,7 @@ public class FragmentOptionsMisc extends FragmentBase implements SharedPreferenc
swLogarithmicBackoff.setChecked(prefs.getBoolean("logarithmic_backoff", true));
swExactAlarms.setChecked(prefs.getBoolean("exact_alarms", true));
swNativeDkim.setChecked(prefs.getBoolean("native_dkim", false));
swInfra.setChecked(prefs.getBoolean("infra", false));
swDupMsgId.setChecked(prefs.getBoolean("dup_msgids", false));
etKeywords.setText(prefs.getString("global_keywords", null));

@ -1989,10 +1989,11 @@ public class MessageHelper {
return true;
}
Boolean verifyDKIM(Context context) throws MessagingException, IOException {
if (!(imessage instanceof IMAPMessage))
return null;
@NonNull
List<String> verifyDKIM(Context context) {
List<String> signers = new ArrayList<>();
try {
// Workaround reformatted headers
Properties props = MessageHelper.getSessionProperties(true);
Session isession = Session.getInstance(props, null);
@ -2001,9 +2002,8 @@ public class MessageHelper {
// https://datatracker.ietf.org/doc/html/rfc6376/
String[] headers = amessage.getHeader("DKIM-Signature");
if (headers == null || headers.length < 1)
return null;
return signers;
boolean valid = false;
for (String header : headers) {
Map<String, String> kv = getKeyValues(MimeUtility.unfold(header));
@ -2018,11 +2018,12 @@ public class MessageHelper {
salgo = "SHA256withRSA";
} else {
Log.i("DKIM a=" + a);
return false;
continue;
}
try {
String dns = kv.get("s") + "._domainkey." + kv.get("d");
String signer = kv.get("d");
String dns = kv.get("s") + "._domainkey." + signer;
Log.i("DKIM lookup " + dns);
DnsHelper.DnsRecord[] records = DnsHelper.lookup(context, dns, "txt");
if (records.length > 0) {
@ -2149,17 +2150,21 @@ public class MessageHelper {
" dns=" + dns +
" from=" + formatAddresses(getFrom()));
if (verified)
valid = true;
if (verified &&
!signers.contains(signer))
signers.add(signer);
}
} catch (Throwable ex) {
Log.i("DKIM error=" + ex);
Log.e(ex);
Log.e("DKIM", ex);
}
}
Log.i("DKIM signers=" + TextUtils.join(",", signers));
} catch (Throwable ex) {
Log.e("DKIM", ex);
}
Log.i("DKIM passed=" + valid);
return valid;
return signers;
}
Address[] getMailFrom(String[] headers) {

@ -1639,6 +1639,30 @@
app:layout_constraintTop_toBottomOf="@id/tvLogarithmicBackoffHint"
app:switchPadding="12dp" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swNativeDkim"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/title_advanced_native_dkim"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExactAlarms"
app:switchPadding="12dp" />
<TextView
android:id="@+id/tvNativeDkimHint"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="48dp"
android:text="@string/title_advanced_sync_delay_hint"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="?attr/colorWarning"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swNativeDkim" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/swInfra"
android:layout_width="0dp"
@ -1647,7 +1671,7 @@
android:text="@string/title_advanced_infra"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/swExactAlarms"
app:layout_constraintTop_toBottomOf="@id/tvNativeDkimHint"
app:switchPadding="12dp" />
<androidx.constraintlayout.helper.widget.Flow

@ -131,6 +131,31 @@
app:barrierDirection="bottom"
app:constraint_referenced_ids="ivPlain,ibReceipt,ivAutoSubmitted,ivBrowsed,ivRaw,ibSearchContact,ibNotifyContact,ibPinContact,ibAddContact" />
<TextView
android:id="@+id/tvSignedByTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:labelFor="@+id/tvSignedBy"
android:text="@string/title_signed_by"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_action" />
<TextView
android:id="@+id/tvSignedBy"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp"
android:text="Submitter"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/barrier_addresses"
app:layout_constraintTop_toBottomOf="@id/barrier_action" />
<TextView
android:id="@+id/tvSubmitterTitle"
android:layout_width="wrap_content"
@ -141,7 +166,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/barrier_action" />
app:layout_constraintTop_toBottomOf="@id/tvSignedBy" />
<TextView
android:id="@+id/tvSubmitter"
@ -154,7 +179,7 @@
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/barrier_addresses"
app:layout_constraintTop_toBottomOf="@id/barrier_action" />
app:layout_constraintTop_toBottomOf="@id/tvSignedBy" />
<TextView
android:id="@+id/tvDeliveredToTitle"
@ -487,6 +512,7 @@
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="
tvSignedByTitle,
tvSubmitterTitle,tvDeliveredToTitle,
tvFromExTitle,tvToTitle,tvReplyToTitle,
tvCcTitle,tvBccTitle,

@ -856,6 +856,7 @@
<string name="title_advanced_keep_alive_poll" translatable="false">Poll on keep-alive</string>
<string name="title_advanced_empty_pool" translatable="false">Empty connection pool</string>
<string name="title_advanced_exact_alarms" translatable="false">Use exact timers</string>
<string name="title_advanced_native_dkim" translatable="false">Native DKIM verification</string>
<string name="title_advanced_infra" translatable="false">Show infrastructure</string>
<string name="title_advanced_dup_msgid" translatable="false">Duplicates by message ID</string>
<string name="title_advanced_global_keywords" translatable="false">Global keywords</string>
@ -1485,6 +1486,7 @@
<string name="title_compose">Compose</string>
<string name="title_submitter">Sent by:</string>
<string name="title_signed_by">Signed by:</string>
<string name="title_delivered_to">Delivered to:</string>
<string name="title_from">From:</string>
<string name="title_to">To:</string>

Loading…
Cancel
Save