mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-02 08:07:11 +00:00
fix: show a warning shield instead of the sender photo when the sender check fails (bulwarkmail/webmail#1439)
This commit is contained in:
@@ -37,7 +37,9 @@ import {
|
||||
searchEmails,
|
||||
sendEmail,
|
||||
MAILBOX_PROPERTIES,
|
||||
queryEmailPage,
|
||||
} from '../email';
|
||||
import { senderWarningOf } from '../../lib/email-headers';
|
||||
import { uploadBytes } from '../blob';
|
||||
import { getIdentities, updateIdentity } from '../identity';
|
||||
import { isJMAPSetError } from '../jmap-result';
|
||||
@@ -418,4 +420,32 @@ live('live Stalwart: mail, contacts, search (0.16 and 1.0)', () => {
|
||||
}
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe('mail list (reader pass)', () => {
|
||||
it('lists the Authentication-Results headers so a forged From gets the warning shield (bulwarkmail/webmail#1439)', async () => {
|
||||
const subject = `forged ${mailTag}`;
|
||||
const raw = [
|
||||
'Authentication-Results: mx.example.org; spf=fail smtp.mailfrom=evil.example; dkim=none; dmarc=fail header.from=bank.example',
|
||||
'From: Bank <ceo@bank.example>',
|
||||
`To: ${USER}`,
|
||||
`Subject: ${subject}`,
|
||||
`Date: ${new Date().toUTCString()}`,
|
||||
`Message-ID: <forged-${RUN}@live.test>`,
|
||||
'MIME-Version: 1.0',
|
||||
'Content-Type: text/plain; charset=utf-8',
|
||||
'',
|
||||
'hello',
|
||||
'',
|
||||
].join('\r\n');
|
||||
const { blobId } = await uploadBytes(new TextEncoder().encode(raw), 'message/rfc822');
|
||||
const id = await importEmailBlob(blobId, scratch, {});
|
||||
const page = await queryEmailPage(scratch, { limit: 10 });
|
||||
const row = page.list.find((e) => e.id === id);
|
||||
expect(row).toBeDefined();
|
||||
expect(senderWarningOf(row!)?.status).toBe('failed');
|
||||
// The full fetch reads the same verdict from `headers`.
|
||||
const [full] = await getFullEmails([id]);
|
||||
expect(senderWarningOf(full)?.status).toBe('failed');
|
||||
}, 60_000);
|
||||
});
|
||||
});
|
||||
|
||||
+13
-3
@@ -19,17 +19,27 @@ import { hasTruncatedDisplayedBody } from '../lib/email-body';
|
||||
import { withInlineBodyParts } from '../lib/email-inline-parts';
|
||||
import { stalwartStateWentBack } from './stalwart-state';
|
||||
import { isTransientNetworkError } from '../lib/network-error';
|
||||
import { LIST_AUTH_RESULTS_PROPERTY } from '../lib/email-headers';
|
||||
|
||||
export const EMAIL_LIST_PROPERTIES = [
|
||||
const EMAIL_SUMMARY_PROPERTIES = [
|
||||
'id', 'threadId', 'mailboxIds', 'keywords', 'size',
|
||||
'receivedAt', 'from', 'to', 'cc', 'subject', 'preview', 'hasAttachment',
|
||||
];
|
||||
|
||||
export const EMAIL_LIST_PROPERTIES = [
|
||||
...EMAIL_SUMMARY_PROPERTIES,
|
||||
// The sender check, so a list row shows a warning shield instead of the
|
||||
// favicon or photo of a forged From (webmail #1439).
|
||||
LIST_AUTH_RESULTS_PROPERTY,
|
||||
];
|
||||
|
||||
// The viewer derives reply threading (In-Reply-To/References), Reply-To
|
||||
// handling, SPF/DKIM/DMARC chips, List-Unsubscribe and read-receipt requests
|
||||
// from these; without `messageId`/`headers` none of that can work.
|
||||
// from these; without `messageId`/`headers` none of that can work. The full
|
||||
// `headers` carry Authentication-Results, so the list's header property is
|
||||
// left out.
|
||||
export const EMAIL_FULL_PROPERTIES = [
|
||||
...EMAIL_LIST_PROPERTIES,
|
||||
...EMAIL_SUMMARY_PROPERTIES,
|
||||
'bodyStructure', 'textBody', 'htmlBody', 'bodyValues',
|
||||
'attachments', 'blobId', 'bcc', 'replyTo', 'sentAt',
|
||||
'messageId', 'inReplyTo', 'references', 'headers',
|
||||
|
||||
@@ -8,6 +8,7 @@ import { keywordPointer, mailboxPointer } from './patch-pointer';
|
||||
import { secureFetch } from '../lib/client-cert';
|
||||
import { freshStoredCredentials } from '../lib/stored-token-refresh';
|
||||
import { textConditions } from '../lib/search-utils';
|
||||
import { LIST_AUTH_RESULTS_PROPERTY } from '../lib/email-headers';
|
||||
|
||||
// Aggregated views across accounts ("All inboxes", "All Sent", All mail /
|
||||
// Unread / Starred). Because the JMAP client is a single-account singleton
|
||||
@@ -21,6 +22,8 @@ import { textConditions } from '../lib/search-utils';
|
||||
const EMAIL_LIST_PROPERTIES = [
|
||||
'id', 'threadId', 'mailboxIds', 'keywords', 'size',
|
||||
'receivedAt', 'from', 'to', 'cc', 'subject', 'preview', 'hasAttachment',
|
||||
// The sender check, for the warning shield on a forged From (#1439).
|
||||
LIST_AUTH_RESULTS_PROPERTY,
|
||||
];
|
||||
|
||||
const SESSION_CACHE_TTL_MS = 10 * 60 * 1000;
|
||||
|
||||
Reference in New Issue
Block a user