-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
92 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,26 @@ | ||
import fs from "fs"; | ||
import path from "path"; | ||
import { verifyDKIMSignature } from "../src/dkim"; | ||
import * as dnsOverHttp from "../src/dkim/dns-over-http"; | ||
import * as dnsArchive from "../src/dkim/dns-archive"; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import { verifyDKIMSignature } from '../src/dkim'; | ||
import * as dnsOverHttp from '../src/dkim/dns-over-http'; | ||
import * as dnsArchive from '../src/dkim/dns-archive'; | ||
|
||
jest.setTimeout(10000); | ||
|
||
describe("DKIM signature verification", () => { | ||
it("should pass for valid email", async () => { | ||
describe('DKIM signature verification', () => { | ||
it('should pass for valid email', async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
path.join(__dirname, 'test-data/email-good.eml'), | ||
); | ||
|
||
const result = await verifyDKIMSignature(email); | ||
|
||
expect(result.signingDomain).toBe("icloud.com"); | ||
expect(result.signingDomain).toBe('icloud.com'); | ||
expect(result.appliedSanitization).toBeFalsy(); | ||
}); | ||
|
||
it("should fail for invalid selector", async () => { | ||
it('should fail for invalid selector', async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-invalid-selector.eml") | ||
path.join(__dirname, 'test-data/email-invalid-selector.eml'), | ||
); | ||
|
||
expect.assertions(1); | ||
|
@@ -29,14 +29,14 @@ describe("DKIM signature verification", () => { | |
await verifyDKIMSignature(email); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: no key" | ||
'DKIM signature verification failed for domain icloud.com. Reason: no key', | ||
); | ||
} | ||
}); | ||
|
||
it("should fail for tampered body", async () => { | ||
it('should fail for tampered body', async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-body-tampered.eml") | ||
path.join(__dirname, 'test-data/email-body-tampered.eml'), | ||
); | ||
|
||
expect.assertions(1); | ||
|
@@ -45,30 +45,32 @@ describe("DKIM signature verification", () => { | |
await verifyDKIMSignature(email); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: body hash did not verify" | ||
'DKIM signature verification failed for domain icloud.com. Reason: body hash did not verify', | ||
); | ||
} | ||
}); | ||
|
||
it("should fail for when DKIM signature is not present for domain", async () => { | ||
it('should fail for when DKIM signature is not present for domain', async () => { | ||
// In this email From address is [email protected], but the DKIM signature is only for icloud.com | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-invalid-domain.eml") | ||
path.join(__dirname, 'test-data/email-invalid-domain.eml'), | ||
); | ||
|
||
expect.assertions(1); | ||
|
||
try { | ||
await verifyDKIMSignature(email); | ||
} catch (e) { | ||
expect(e.message).toBe("DKIM signature not found for domain gmail.com"); | ||
expect(e.message).toBe( | ||
'DKIM signature not found for domain gmail.com', | ||
); | ||
} | ||
}); | ||
|
||
it("should be able to override domain", async () => { | ||
it('should be able to override domain', async () => { | ||
// From address domain is icloud.com | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-different-domain.eml") | ||
path.join(__dirname, 'test-data/email-different-domain.eml'), | ||
); | ||
|
||
// Should pass with default domain | ||
|
@@ -79,94 +81,96 @@ describe("DKIM signature verification", () => { | |
// different from From domain and the below check pass. | ||
expect.assertions(1); | ||
try { | ||
await verifyDKIMSignature(email, "domain.com"); | ||
await verifyDKIMSignature(email, 'domain.com'); | ||
} catch (e) { | ||
expect(e.message).toBe("DKIM signature not found for domain domain.com"); | ||
expect(e.message).toBe( | ||
'DKIM signature not found for domain domain.com', | ||
); | ||
} | ||
}); | ||
}); | ||
|
||
it("should fallback to ZK Email Archive if DNS over HTTP fails", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
); | ||
|
||
// Mock resolveDNSHTTP to throw an error just for this test | ||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
const consoleSpy = jest.spyOn(console, "log"); | ||
await verifyDKIMSignature(email, "icloud.com", true, true); | ||
|
||
// Check if the error was logged to ensure fallback to ZK Email Archive happened | ||
expect(consoleSpy).toHaveBeenCalledWith( | ||
"DNS over HTTP failed, falling back to ZK Email Archive" | ||
); | ||
it("should fallback to ZK Email Archive if DNS over HTTP fails", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
); | ||
|
||
mockResolveDNSHTTP.mockRestore(); | ||
}); | ||
// Mock resolveDNSHTTP to throw an error just for this test | ||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
it("should fail on DNS over HTTP failure if fallback is not enabled", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
); | ||
const consoleSpy = jest.spyOn(console, "log"); | ||
await verifyDKIMSignature(email, "icloud.com", true, true); | ||
|
||
// Mock resolveDNSHTTP to throw an error just for this test | ||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
// Check if the error was logged to ensure fallback to ZK Email Archive happened | ||
expect(consoleSpy).toHaveBeenCalledWith( | ||
"DNS over HTTP failed, falling back to ZK Email Archive" | ||
); | ||
|
||
expect.assertions(1); | ||
try { | ||
await verifyDKIMSignature(email, "icloud.com", true, false); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: DNS failure: Failed due to mock" | ||
); | ||
} | ||
mockResolveDNSHTTP.mockRestore(); | ||
}); | ||
mockResolveDNSHTTP.mockRestore(); | ||
}); | ||
|
||
it("should fail if both DNS over HTTP and ZK Email Archive fail", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
it("should fail on DNS over HTTP failure if fallback is not enabled", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
); | ||
|
||
// Mock resolveDNSHTTP to throw an error just for this test | ||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
expect.assertions(1); | ||
try { | ||
await verifyDKIMSignature(email, "icloud.com", true, false); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: DNS failure: Failed due to mock" | ||
); | ||
} | ||
mockResolveDNSHTTP.mockRestore(); | ||
}); | ||
|
||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
const mockResolveDNSFromZKEmailArchive = jest | ||
.spyOn(dnsArchive, "resolveDNSFromZKEmailArchive") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
expect.assertions(1); | ||
try { | ||
await verifyDKIMSignature(email, "icloud.com", true, false); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: DNS failure: Failed due to mock" | ||
); | ||
} | ||
it("should fail if both DNS over HTTP and ZK Email Archive fail", async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
); | ||
|
||
const mockResolveDNSHTTP = jest | ||
.spyOn(dnsOverHttp, "resolveDNSHTTP") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
const mockResolveDNSFromZKEmailArchive = jest | ||
.spyOn(dnsArchive, "resolveDNSFromZKEmailArchive") | ||
.mockRejectedValue(new Error("Failed due to mock")); | ||
|
||
expect.assertions(1); | ||
try { | ||
await verifyDKIMSignature(email, "icloud.com", true, false); | ||
} catch (e) { | ||
expect(e.message).toBe( | ||
"DKIM signature verification failed for domain icloud.com. Reason: DNS failure: Failed due to mock" | ||
); | ||
} | ||
|
||
mockResolveDNSHTTP.mockRestore(); | ||
mockResolveDNSFromZKEmailArchive.mockRestore(); | ||
}); | ||
mockResolveDNSHTTP.mockRestore(); | ||
mockResolveDNSFromZKEmailArchive.mockRestore(); | ||
}); | ||
|
||
describe("DKIM with sanitization", () => { | ||
it("should pass after removing label from Subject", async () => { | ||
describe('DKIM with sanitization', () => { | ||
it('should pass after removing label from Subject', async () => { | ||
const email = fs.readFileSync( | ||
path.join(__dirname, "test-data/email-good.eml") | ||
path.join(__dirname, 'test-data/email-good.eml'), | ||
); | ||
|
||
// Add a label to the subject | ||
const tamperedEmail = email | ||
.toString() | ||
.replace("Subject: ", "Subject: [EmailListABC]"); | ||
const tamperedEmail = email.toString().replace('Subject: ', 'Subject: [EmailListABC]'); | ||
|
||
const result = await verifyDKIMSignature(tamperedEmail); | ||
|
||
expect(result.appliedSanitization).toBe("removeLabels"); | ||
expect(result.appliedSanitization).toBe('removeLabels'); | ||
}); | ||
}); | ||
}); |