feat: surface most severe SPF result and hide "via" badge on spoofed mail
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
getSecurityStatus,
|
||||
parseSpamLLM,
|
||||
extractListHeaders,
|
||||
isAuthenticationSpoofed,
|
||||
} from '../email-headers';
|
||||
|
||||
describe('parseAuthenticationResults', () => {
|
||||
@@ -52,6 +53,66 @@ describe('parseAuthenticationResults', () => {
|
||||
const result = parseAuthenticationResults('spf=softfail smtp.mailfrom=example.com');
|
||||
expect(result.spf?.result).toBe('softfail');
|
||||
});
|
||||
|
||||
it('surfaces the most severe result when multiple SPF identities exist', () => {
|
||||
// HELO temperror, MAIL FROM fail — the harder fail must be the headline.
|
||||
const header =
|
||||
'mx.example.com; spf=temperror (mx: dns timeout) smtp.helo=mail.spoof.com; spf=fail (mx: not authorized) smtp.mailfrom=victim.com';
|
||||
const result = parseAuthenticationResults(header);
|
||||
expect(result.spf?.result).toBe('fail');
|
||||
expect(result.spf?.domain).toBe('victim.com');
|
||||
});
|
||||
|
||||
it('exposes all SPF results when more than one identity is evaluated', () => {
|
||||
const header =
|
||||
'spf=temperror smtp.helo=mail.spoof.com; spf=fail smtp.mailfrom=victim.com';
|
||||
const result = parseAuthenticationResults(header);
|
||||
expect(result.spf?.all).toEqual([
|
||||
{ result: 'temperror', identity: 'helo', domain: 'mail.spoof.com' },
|
||||
{ result: 'fail', identity: 'mailfrom', domain: 'victim.com' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not set `all` for a single SPF result', () => {
|
||||
const result = parseAuthenticationResults('spf=pass smtp.mailfrom=example.com');
|
||||
expect(result.spf?.all).toBeUndefined();
|
||||
});
|
||||
|
||||
it('prefers the MAIL FROM identity when severities tie', () => {
|
||||
const header = 'spf=pass smtp.helo=mail.example.com; spf=pass smtp.mailfrom=example.com';
|
||||
const result = parseAuthenticationResults(header);
|
||||
expect(result.spf?.domain).toBe('example.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isAuthenticationSpoofed', () => {
|
||||
it('returns false when no auth results are present', () => {
|
||||
expect(isAuthenticationSpoofed(undefined)).toBe(false);
|
||||
expect(isAuthenticationSpoofed({})).toBe(false);
|
||||
});
|
||||
|
||||
it('flags a DMARC fail as spoofed', () => {
|
||||
expect(isAuthenticationSpoofed({ dmarc: { result: 'fail' } })).toBe(true);
|
||||
});
|
||||
|
||||
it('flags a hard SPF fail without a passing DKIM as spoofed', () => {
|
||||
expect(isAuthenticationSpoofed({ spf: { result: 'fail' } })).toBe(true);
|
||||
expect(
|
||||
isAuthenticationSpoofed({ spf: { result: 'fail' }, dkim: { result: 'fail' } })
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('does not flag an SPF fail rescued by a passing DKIM', () => {
|
||||
expect(
|
||||
isAuthenticationSpoofed({ spf: { result: 'fail' }, dkim: { result: 'pass' } })
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('does not flag passing or ambiguous results', () => {
|
||||
expect(isAuthenticationSpoofed({ spf: { result: 'pass' }, dmarc: { result: 'pass' } })).toBe(false);
|
||||
expect(isAuthenticationSpoofed({ spf: { result: 'softfail' } })).toBe(false);
|
||||
expect(isAuthenticationSpoofed({ spf: { result: 'temperror' } })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSpamScore', () => {
|
||||
|
||||
Reference in New Issue
Block a user