Mark messages with failed DKIM, SPF or DMARC authentication

pull/155/head
M66B 5 years ago
parent c312725446
commit a29de1bd3f

File diff suppressed because it is too large Load Diff

@ -167,6 +167,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
View.OnClickListener, View.OnLongClickListener, BottomNavigationView.OnNavigationItemSelectedListener {
private View view;
private View vwColor;
private View vwStatus;
private ImageView ivExpander;
private ImageView ivFlagged;
private ImageView ivAvatar;
@ -250,6 +251,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
view = itemView.findViewById(R.id.clItem);
vwColor = itemView.findViewById(R.id.vwColor);
vwStatus = itemView.findViewById(R.id.vwStatus);
ivExpander = itemView.findViewById(R.id.ivExpander);
ivFlagged = itemView.findViewById(R.id.ivFlagged);
ivAvatar = itemView.findViewById(R.id.ivAvatar);
@ -405,6 +407,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
private void clear() {
vwColor.setVisibility(View.GONE);
vwStatus.setVisibility(View.GONE);
ivExpander.setVisibility(View.GONE);
ivFlagged.setVisibility(View.GONE);
ivAvatar.setVisibility(View.GONE);
@ -499,6 +502,13 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
vwColor.setBackgroundColor(message.accountColor == null ? Color.TRANSPARENT : message.accountColor);
vwColor.setVisibility(View.VISIBLE);
vwStatus.setBackgroundColor(
Boolean.FALSE.equals(message.dkim) ||
Boolean.FALSE.equals(message.spf) ||
Boolean.FALSE.equals(message.dmarc)
? colorWarning : Color.TRANSPARENT);
vwStatus.setVisibility(View.VISIBLE);
// Expander
boolean expanded = (viewType == ViewType.THREAD && properties.getValue("expanded", message.id));
ivExpander.setImageResource(expanded ? R.drawable.baseline_expand_less_24 : R.drawable.baseline_expand_more_24);

@ -1156,6 +1156,7 @@ class Core {
}
}
String authentication = helper.getAuthentication();
MessageHelper.MessageParts parts = helper.getMessageParts();
message = new EntityMessage();
@ -1173,6 +1174,9 @@ class Core {
// Local address contains control or whitespace in string ``mailing list someone@example.org''
message.deliveredto = helper.getDeliveredTo();
message.thread = helper.getThreadId(context, account.id, uid);
message.dkim = EntityMessage.getAuthentication("dkim", authentication);
message.spf = EntityMessage.getAuthentication("spf", authentication);
message.dmarc = EntityMessage.getAuthentication("dmarc", authentication);
message.from = froms;
message.to = tos;
message.cc = ccs;

@ -50,7 +50,7 @@ import io.requery.android.database.sqlite.RequerySQLiteOpenHelperFactory;
// https://developer.android.com/topic/libraries/architecture/room.html
@Database(
version = 63,
version = 64,
entities = {
EntityIdentity.class,
EntityAccount.class,
@ -684,6 +684,15 @@ public abstract class DB extends RoomDatabase {
db.execSQL("CREATE INDEX `index_message_msgid` ON `message` (`msgid`)");
}
})
.addMigrations(new Migration(63, 64) {
@Override
public void migrate(SupportSQLiteDatabase db) {
Log.i("DB migration from version " + startVersion + " to " + endVersion);
db.execSQL("ALTER TABLE `message` ADD COLUMN `dkim` INTEGER");
db.execSQL("ALTER TABLE `message` ADD COLUMN `spf` INTEGER");
db.execSQL("ALTER TABLE `message` ADD COLUMN `dmarc` INTEGER");
}
})
.build();
}

@ -90,6 +90,9 @@ public class EntityMessage implements Serializable {
public String deliveredto;
public String inreplyto;
public String thread; // compose = null
public Boolean dkim;
public Boolean spf;
public Boolean dmarc;
public String avatar; // lookup URI from sender
public String sender; // sort key
public Address[] from;
@ -182,6 +185,31 @@ public class EntityMessage implements Serializable {
}
}
static Boolean getAuthentication(String type, String header) {
if (header == null)
return null;
// https://tools.ietf.org/html/rfc7601
Boolean result = null;
String[] part = header.split(";");
for (int i = 1; i < part.length; i++) {
String[] kv = part[i].split("=");
if (kv.length > 1) {
String key = kv[0].trim();
String[] val = kv[1].split(" ");
if (val.length > 0 && type.equals(key)) {
if ("fail".equals(val[0]))
result = false;
else if ("pass".equals(val[0]))
if (result == null)
result = true;
}
}
}
return result;
}
public boolean uiEquals(Object obj) {
if (obj instanceof EntityMessage) {
EntityMessage other = (EntityMessage) obj;

@ -455,6 +455,11 @@ public class MessageHelper {
return (TextUtils.isEmpty(msgid) ? Long.toString(uid) : msgid);
}
String getAuthentication() throws MessagingException {
String header = imessage.getHeader("Authentication-Results", "");
return (header == null ? null : header.replaceAll("\\r?\\n", ""));
}
Address getSender() throws MessagingException {
String sender = imessage.getHeader("Sender", null);
if (sender == null)

@ -260,6 +260,15 @@
android:layout_width="6dp"
android:layout_height="0dp"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@+id/vwStatus"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/vwStatus"
android:layout_width="6dp"
android:layout_height="0dp"
android:background="@color/colorPrimary"
app:layout_constraintBottom_toTopOf="@+id/vSeparatorAddress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

@ -254,6 +254,15 @@
android:id="@+id/paddingEnd"
android:layout_width="6dp"
android:layout_height="0dp"
app:layout_constraintEnd_toStartOf="@+id/vwStatus"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/vwStatus"
android:layout_width="6dp"
android:layout_height="0dp"
android:background="@color/colorPrimary"
app:layout_constraintBottom_toTopOf="@+id/vSeparatorAddress"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

Loading…
Cancel
Save