@vlayer/sdk 0.1.0-nightly-20241001-aa0406f → 0.1.0-nightly-20241001-f254bee

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vlayer/sdk",
3
3
  "type": "module",
4
4
  "module": "src/index.ts",
5
- "version": "0.1.0-nightly-20241001-aa0406f",
5
+ "version": "0.1.0-nightly-20241001-f254bee",
6
6
  "scripts": {
7
7
  "build": "npm run gen:types",
8
8
  "test": "vitest --run",
@@ -19,7 +19,9 @@
19
19
  "typescript": "^5.0.0"
20
20
  },
21
21
  "dependencies": {
22
+ "dns-over-http-resolver": "^3.0.3",
22
23
  "mailparser": "^3.7.1",
24
+ "postal-mime": "^2.3.2",
23
25
  "viem": "^2.21.0"
24
26
  }
25
27
  }
@@ -1,14 +1,7 @@
1
- import dns from "node:dns";
1
+ import DnsResolver from "dns-over-http-resolver";
2
2
 
3
3
  export async function resolveDkimDns(domain: string, selector: string) {
4
- return new Promise<string>((resolve, reject) => {
5
- dns.resolveTxt(`${selector}._domainkey.${domain}`, (err, addresses) => {
6
- if (err) {
7
- reject(err);
8
- return;
9
- }
10
-
11
- resolve(addresses.flat()[0]);
12
- });
13
- });
4
+ const resolver = new DnsResolver();
5
+ const address = await resolver.resolveTxt(`${selector}._domainkey.${domain}`);
6
+ return address.flat()[0];
14
7
  }
@@ -1,7 +1,5 @@
1
- import assert from "node:assert";
2
1
  import { describe, expect, test } from "vitest";
3
- import { getDkimSigners, parseEmail } from "./parseEmail.ts";
4
- import { StructuredHeader } from "mailparser";
2
+ import { getDkimSigners, parseEmail, parseParams } from "./parseEmail.ts";
5
3
 
6
4
  const emailHeaders = `From: "John Doe" <john@d.oe>
7
5
  To: "Jane Doe" <jane@d.oe>
@@ -17,18 +15,12 @@ const body = "Hello, World!";
17
15
  const emailFixture = `${emailHeaders}${dkimHeader}\n\n${body}`;
18
16
 
19
17
  describe("parseEmail", () => {
20
- test("should get dkim header from email", async () => {
21
- const email = await parseEmail(emailFixture);
22
- const dkim = email.headers.get("dkim-signature")!;
23
- assert(typeof dkim === "object" && "params" in dkim);
24
- expect(dkim.params.d).toBe("example.com");
25
- expect(dkim.params.s).toBe("selector1");
26
- });
18
+ test("should get dkim header from email", async () => {});
27
19
 
28
20
  test("correctly parses untrimmed email", async () => {
29
21
  const untrimmed = `\n ${emailFixture} \n`;
30
22
  const email = await parseEmail(untrimmed);
31
- expect(email.headers.get("dkim-signature")).toBeDefined();
23
+ expect(email.headers.find((h) => h.key === "dkim-signature")).toBeDefined();
32
24
  });
33
25
 
34
26
  test("works well with multiple dkim headers", async () => {
@@ -38,12 +30,11 @@ describe("parseEmail", () => {
38
30
  const email = await parseEmail(
39
31
  `${emailHeaders}${dkimHeader}\n${dkimHeader2}\n\n${body}`,
40
32
  );
41
- const dkim = email.headers.get(
42
- "dkim-signature",
43
- )! as unknown as StructuredHeader[];
33
+ const dkim = email.headers.filter((h) => h.key === "dkim-signature")!;
34
+
44
35
  expect(dkim).toHaveLength(2);
45
- expect(dkim[0].params.s).toBe("selector1");
46
- expect(dkim[1].params.s).toBe("selector2");
36
+ expect(parseParams(dkim[0].value).s).toBe("selector1");
37
+ expect(parseParams(dkim[1].value).s).toBe("selector2");
47
38
  });
48
39
  });
49
40
 
@@ -103,3 +94,40 @@ describe("getDkimSigners", () => {
103
94
  );
104
95
  });
105
96
  });
97
+
98
+ describe("parseParams", () => {
99
+ test("should parse single parameter", () => {
100
+ const params = parseParams("a=b");
101
+ expect(params).toEqual({ a: "b" });
102
+ });
103
+
104
+ test("should parse multiple parameters", () => {
105
+ const params = parseParams("a=b; c=d; e=f");
106
+ expect(params).toEqual({ a: "b", c: "d", e: "f" });
107
+ });
108
+
109
+ test("should trim spaces around parameters", () => {
110
+ const params = parseParams(" a = b ; c = d ; e = f ");
111
+ expect(params).toEqual({ a: "b", c: "d", e: "f" });
112
+ });
113
+
114
+ test("should handle empty values", () => {
115
+ const params = parseParams("a=; b=c");
116
+ expect(params).toEqual({ a: "", b: "c" });
117
+ });
118
+
119
+ test("should handle missing values", () => {
120
+ const params = parseParams("a; b=c");
121
+ expect(params).toEqual({ a: undefined, b: "c" });
122
+ });
123
+
124
+ test("should handle empty string", () => {
125
+ const params = parseParams("");
126
+ expect(params).toEqual({});
127
+ });
128
+
129
+ test("should handle parameters with extra semicolons", () => {
130
+ const params = parseParams("a=b;; c=d;");
131
+ expect(params).toEqual({ a: "b", c: "d" });
132
+ });
133
+ });
@@ -1,4 +1,4 @@
1
- import { simpleParser, HeaderValue, type ParsedMail } from "mailparser";
1
+ import PostalMime, { Email, Header } from "postal-mime";
2
2
 
3
3
  export class DkimParsingError extends Error {
4
4
  constructor(message: string) {
@@ -8,38 +8,42 @@ export class DkimParsingError extends Error {
8
8
  }
9
9
 
10
10
  export async function parseEmail(mime: string) {
11
- return simpleParser(mime.trim(), {
12
- skipHtmlToText: true,
13
- skipTextToHtml: true,
14
- skipTextLinks: true,
15
- skipImageLinks: true,
16
- });
11
+ return await PostalMime.parse(mime.trim());
17
12
  }
18
13
 
19
- export function getDkimSigners(mail: ParsedMail) {
20
- const dkimHeader = mail.headers.get("dkim-signature");
21
- if (!dkimHeader) throw new DkimParsingError("No DKIM header found");
22
- if (Array.isArray(dkimHeader)) {
23
- return dkimHeader.map(parseHeader);
24
- }
25
- return [parseHeader(dkimHeader)];
14
+ export function getDkimSigners(mail: Email) {
15
+ const dkimHeader = mail.headers.filter((h) => h.key === "dkim-signature");
16
+ if (dkimHeader.length === 0)
17
+ throw new DkimParsingError("No DKIM header found");
18
+ return dkimHeader.map(parseHeader);
19
+ }
20
+
21
+ export function parseParams(str: string) {
22
+ return Object.fromEntries(
23
+ str.split(";").map((s) =>
24
+ s
25
+ .trim()
26
+ .split("=")
27
+ .map((v) => v && v.trim()),
28
+ ),
29
+ );
26
30
  }
27
31
 
28
- function parseHeader(header: HeaderValue) {
29
- if (typeof header === "string" || !("params" in header)) {
32
+ function parseHeader(header: Header) {
33
+ const params = parseParams(header.value);
34
+ if (!params) {
30
35
  throw new DkimParsingError(`Invalid DKIM header ${header}`);
31
36
  }
32
37
 
33
- if (!header.params.d) {
38
+ if (!params.d) {
34
39
  throw new DkimParsingError("DKIM header missing domain");
35
40
  }
36
41
 
37
- if (!header.params.s) {
42
+ if (!params.s) {
38
43
  throw new DkimParsingError("DKIM header missing selector");
39
44
  }
40
-
41
45
  return {
42
- domain: header.params.d,
43
- selector: header.params.s,
46
+ domain: params.d,
47
+ selector: params.s,
44
48
  };
45
49
  }
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, test } from "vitest";
2
2
  import { preverifyEmail } from "./preverify.ts";
3
- import { readFile } from "testHelpers/readFile";
3
+ import { readFile } from "../../testHelpers/readFile";
4
4
 
5
5
  describe("Preverify email: integration", () => {
6
6
  test("adds dns record to email mime", async () => {