mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(imap): handle DMARC outcomes without alignment (#131060)
This commit is contained in:
committed by
GitHub
parent
78268eeb43
commit
ad0848149b
@@ -1,3 +1,4 @@
|
||||
import { authenticate } from "mailauth";
|
||||
import { simpleParser } from "mailparser";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { resolveImapConfig } from "./config.js";
|
||||
@@ -75,25 +76,54 @@ describe("IMAP sender admission", () => {
|
||||
it.each(["neutral", "temperror", "none"] as const)(
|
||||
"never dispatches on DMARC %s at the default verified threshold",
|
||||
async (result) => {
|
||||
const mail = await message(["From: trusted@example.com", "To: reader@example.com"]);
|
||||
const authenticator = vi.fn(async () => createImapAuthResult(result));
|
||||
const mail = await message([
|
||||
"From: trusted@example.com",
|
||||
"To: reader+wrong-token@example.com",
|
||||
]);
|
||||
const authentication =
|
||||
result === "neutral"
|
||||
? createImapAuthResult(result)
|
||||
: await authenticate(mail.raw, {
|
||||
disableArc: true,
|
||||
disableBimi: true,
|
||||
resolver: async () => {
|
||||
if (result === "temperror") {
|
||||
throw new Error("fixture DNS timeout");
|
||||
}
|
||||
return [];
|
||||
},
|
||||
});
|
||||
expect(authentication.dmarc).toMatchObject({ status: { result } });
|
||||
if (result !== "neutral") {
|
||||
expect(authentication.dmarc).not.toHaveProperty("alignment");
|
||||
}
|
||||
const configured = account({
|
||||
addressTokens: [{ token: "expected-token", senders: ["trusted@example.com"] }],
|
||||
});
|
||||
await expect(
|
||||
evaluateImapSender({ ...mail, account: account(), authenticator }),
|
||||
).resolves.toMatchObject({ accepted: false });
|
||||
evaluateImapSender({
|
||||
...mail,
|
||||
account: configured,
|
||||
authenticator: async () => authentication,
|
||||
}),
|
||||
).resolves.toMatchObject({ accepted: false, transient: result === "temperror" });
|
||||
},
|
||||
);
|
||||
|
||||
it("does not verify a passing DKIM signature that left message body bytes unsigned", async () => {
|
||||
const result = createImapAuthResult("pass");
|
||||
if (result.dmarc) {
|
||||
result.dmarc.alignment.dkim.underSized = 32;
|
||||
}
|
||||
const mail = await message(["From: trusted@example.com", "To: reader@example.com"]);
|
||||
const authenticator = vi.fn(async () => result);
|
||||
await expect(
|
||||
evaluateImapSender({ ...mail, account: account(), authenticator }),
|
||||
).resolves.toMatchObject({ accepted: false, reason: "dkim-unsigned-body" });
|
||||
});
|
||||
it.each(["pass", "fail"] as const)(
|
||||
"rejects unsigned body bytes even with DMARC %s",
|
||||
async (dmarc) => {
|
||||
const result = createImapAuthResult(dmarc);
|
||||
if (result.dmarc) {
|
||||
result.dmarc.alignment.dkim.underSized = 32;
|
||||
}
|
||||
const mail = await message(["From: trusted@example.com", "To: reader@example.com"]);
|
||||
const authenticator = vi.fn(async () => result);
|
||||
await expect(
|
||||
evaluateImapSender({ ...mail, account: account(), authenticator }),
|
||||
).resolves.toMatchObject({ accepted: false, reason: "dkim-unsigned-body" });
|
||||
},
|
||||
);
|
||||
|
||||
it("accepts only configured Authentication-Results authorities", async () => {
|
||||
const configured = account({
|
||||
|
||||
@@ -117,7 +117,8 @@ function mapImapAuthStrength(
|
||||
account: ImapAccountConfig,
|
||||
): { strength: SenderStrength; reason: string; transient: boolean } {
|
||||
const dmarc = result?.dmarc && result.dmarc.status.result;
|
||||
if (result?.dmarc && result.dmarc.alignment.dkim.underSized) {
|
||||
// mailauth omits alignment when no DMARC policy exists or its DNS lookup fails.
|
||||
if (result?.dmarc && result.dmarc.alignment?.dkim.underSized) {
|
||||
return { strength: "unverified", reason: "dkim-unsigned-body", transient: false };
|
||||
}
|
||||
if (dmarc === "pass") {
|
||||
|
||||
Reference in New Issue
Block a user