@c9up/goldstone 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +238 -2
- package/dist/GoldstoneProvider.d.ts +33 -0
- package/dist/GoldstoneProvider.d.ts.map +1 -0
- package/dist/GoldstoneProvider.js +55 -0
- package/dist/GoldstoneProvider.js.map +1 -0
- package/dist/InboxManager.d.ts +17 -0
- package/dist/InboxManager.d.ts.map +1 -0
- package/dist/InboxManager.js +39 -0
- package/dist/InboxManager.js.map +1 -0
- package/dist/Mailbox.d.ts +83 -0
- package/dist/Mailbox.d.ts.map +1 -0
- package/dist/Mailbox.js +326 -0
- package/dist/Mailbox.js.map +1 -0
- package/dist/ReceivedMessage.d.ts +152 -0
- package/dist/ReceivedMessage.d.ts.map +1 -0
- package/dist/ReceivedMessage.js +179 -0
- package/dist/ReceivedMessage.js.map +1 -0
- package/dist/augmentations.d.ts +18 -0
- package/dist/augmentations.d.ts.map +1 -0
- package/dist/augmentations.js +10 -0
- package/dist/augmentations.js.map +1 -0
- package/dist/authenticity.d.ts +81 -0
- package/dist/authenticity.d.ts.map +1 -0
- package/dist/authenticity.js +102 -0
- package/dist/authenticity.js.map +1 -0
- package/dist/config.d.ts +85 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +50 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.d.ts +15 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +50 -0
- package/dist/errors.js.map +1 -0
- package/dist/inbound/context.d.ts +43 -0
- package/dist/inbound/context.d.ts.map +1 -0
- package/dist/inbound/context.js +56 -0
- package/dist/inbound/context.js.map +1 -0
- package/dist/inbound/mailgun.d.ts +57 -0
- package/dist/inbound/mailgun.d.ts.map +1 -0
- package/dist/inbound/mailgun.js +132 -0
- package/dist/inbound/mailgun.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/native/generated.d.ts +106 -0
- package/dist/native/generated.d.ts.map +1 -0
- package/dist/native/generated.js +7 -0
- package/dist/native/generated.js.map +1 -0
- package/dist/native.d.ts +23 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +45 -0
- package/dist/native.js.map +1 -0
- package/dist/services/main.d.ts +22 -0
- package/dist/services/main.d.ts.map +1 -0
- package/dist/services/main.js +43 -0
- package/dist/services/main.js.map +1 -0
- package/dist/vendor/nativeBinary.d.ts +67 -0
- package/dist/vendor/nativeBinary.d.ts.map +1 -0
- package/dist/vendor/nativeBinary.js +156 -0
- package/dist/vendor/nativeBinary.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +67 -3
- package/src/GoldstoneProvider.ts +75 -0
- package/src/InboxManager.ts +51 -0
- package/src/Mailbox.ts +433 -0
- package/src/ReceivedMessage.ts +287 -0
- package/src/augmentations.ts +22 -0
- package/src/authenticity.ts +183 -0
- package/src/config.ts +132 -0
- package/src/errors.ts +57 -0
- package/src/inbound/context.ts +92 -0
- package/src/inbound/mailgun.ts +201 -0
- package/src/index.ts +53 -0
- package/src/native/generated.ts +141 -0
- package/src/native.ts +62 -0
- package/src/services/main.ts +51 -0
- package/src/vendor/nativeBinary.ts +186 -0
package/dist/Mailbox.js
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One IMAP mailbox: its connection, opened on first use, and what the
|
|
3
|
+
* application does with it.
|
|
4
|
+
*
|
|
5
|
+
* const support = inbox.mailbox('support')
|
|
6
|
+
* for (const uid of await support.search({ seen: false })) {
|
|
7
|
+
* const message = await support.fetch(uid)
|
|
8
|
+
* }
|
|
9
|
+
* const stop = support.watch(async (message, { uid }) => { … })
|
|
10
|
+
*
|
|
11
|
+
* Every message read goes through {@link readMessage}: its size is asked of
|
|
12
|
+
* the server first, so one over the limit is refused without being
|
|
13
|
+
* downloaded; it is then parsed, and its sender checked (DKIM, SPF, DMARC)
|
|
14
|
+
* unless `authenticate: false`.
|
|
15
|
+
*/
|
|
16
|
+
import { ImapFlow } from "imapflow";
|
|
17
|
+
import { assertSecure } from "./config.js";
|
|
18
|
+
import { GoldstoneError } from "./errors.js";
|
|
19
|
+
import { readMessage, } from "./ReceivedMessage.js";
|
|
20
|
+
/** Wait before reconnect attempt `n`: 0.5 s, 1 s, 2 s… up to 30 s. */
|
|
21
|
+
export function reconnectDelay(attempt) {
|
|
22
|
+
return Math.min(500 * 2 ** Math.max(attempt - 1, 0), 30_000);
|
|
23
|
+
}
|
|
24
|
+
const DEFAULT_MAX_BYTES = 25 * 1024 * 1024;
|
|
25
|
+
/**
|
|
26
|
+
* Room for what is not a message in one response: SEARCH answers for a big
|
|
27
|
+
* mailbox, the framing around a literal.
|
|
28
|
+
*/
|
|
29
|
+
const RESPONSE_ROOM = 64 * 1024 * 1024;
|
|
30
|
+
/** imapflow's codes for a response it stopped reading at the cap. */
|
|
31
|
+
const OVERSIZED = new Set([
|
|
32
|
+
"LiteralTooLarge",
|
|
33
|
+
"ResponseTooLarge",
|
|
34
|
+
"LineTooLarge",
|
|
35
|
+
]);
|
|
36
|
+
function oversized(error) {
|
|
37
|
+
const code = typeof error === "object" && error !== null
|
|
38
|
+
? Reflect.get(error, "code")
|
|
39
|
+
: undefined;
|
|
40
|
+
return typeof code === "string" && OVERSIZED.has(code);
|
|
41
|
+
}
|
|
42
|
+
export class Mailbox {
|
|
43
|
+
name;
|
|
44
|
+
#config;
|
|
45
|
+
#limits;
|
|
46
|
+
#authenticate;
|
|
47
|
+
#remoteContent;
|
|
48
|
+
#client;
|
|
49
|
+
#watches = new Set();
|
|
50
|
+
#cutOff = new WeakMap();
|
|
51
|
+
constructor(name, config, options = {}) {
|
|
52
|
+
assertSecure(name, config);
|
|
53
|
+
this.name = name;
|
|
54
|
+
this.#config = config;
|
|
55
|
+
this.#limits = options.limits;
|
|
56
|
+
this.#authenticate = options.authenticate ?? true;
|
|
57
|
+
this.#remoteContent = options.remoteContent;
|
|
58
|
+
}
|
|
59
|
+
/** Every folder's path, as the server names it. */
|
|
60
|
+
async folders() {
|
|
61
|
+
const client = await this.#connection();
|
|
62
|
+
return (await client.list()).map((folder) => folder.path);
|
|
63
|
+
}
|
|
64
|
+
/** UIDs of the messages that match, in `folder` (default `INBOX`). */
|
|
65
|
+
async search(criteria, folder = "INBOX") {
|
|
66
|
+
return this.#in(folder, async (client) => {
|
|
67
|
+
const uids = await client.search(criteria, { uid: true });
|
|
68
|
+
return Array.isArray(uids) ? [...uids].sort((a, b) => a - b) : [];
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* One message, parsed — or `undefined` when no message has that UID.
|
|
73
|
+
* Refused with `E_GOLDSTONE_MESSAGE_TOO_LARGE` before download when the
|
|
74
|
+
* server says it is over the limit.
|
|
75
|
+
*/
|
|
76
|
+
async fetch(uid, folder = "INBOX") {
|
|
77
|
+
return this.#in(folder, (client) => this.#read(client, uid));
|
|
78
|
+
}
|
|
79
|
+
async markSeen(uids, folder = "INBOX") {
|
|
80
|
+
if (isEmpty(uids))
|
|
81
|
+
return;
|
|
82
|
+
await this.#in(folder, (client) => client.messageFlagsAdd(range(uids), ["\\Seen"], { uid: true }));
|
|
83
|
+
}
|
|
84
|
+
async markUnseen(uids, folder = "INBOX") {
|
|
85
|
+
if (isEmpty(uids))
|
|
86
|
+
return;
|
|
87
|
+
await this.#in(folder, (client) => client.messageFlagsRemove(range(uids), ["\\Seen"], { uid: true }));
|
|
88
|
+
}
|
|
89
|
+
async move(uids, to, folder = "INBOX") {
|
|
90
|
+
if (isEmpty(uids))
|
|
91
|
+
return;
|
|
92
|
+
await this.#in(folder, (client) => client.messageMove(range(uids), to, { uid: true }));
|
|
93
|
+
}
|
|
94
|
+
async delete(uids, folder = "INBOX") {
|
|
95
|
+
if (isEmpty(uids))
|
|
96
|
+
return;
|
|
97
|
+
await this.#in(folder, (client) => client.messageDelete(range(uids), { uid: true }));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Call `handler` for every new message, as it arrives (IDLE), on a
|
|
101
|
+
* connection of its own. A lost connection is reopened with a growing
|
|
102
|
+
* wait, and what arrived meanwhile is delivered on return: messages are
|
|
103
|
+
* followed by UID, so none is skipped and none delivered twice.
|
|
104
|
+
*
|
|
105
|
+
* A handler that throws does not stop the watch, and the message is not
|
|
106
|
+
* offered again — a message that always fails would otherwise stall the
|
|
107
|
+
* mailbox. Resolves the returned function once the watch has stopped.
|
|
108
|
+
*/
|
|
109
|
+
watch(handler, options = {}) {
|
|
110
|
+
const folder = options.folder ?? "INBOX";
|
|
111
|
+
const report = options.onError ??
|
|
112
|
+
((error) => console.error(`[inbox] ${this.name}/${folder}:`, error));
|
|
113
|
+
let last = options.afterUid;
|
|
114
|
+
let uidValidity;
|
|
115
|
+
let stopped = false;
|
|
116
|
+
let current;
|
|
117
|
+
let wake;
|
|
118
|
+
const deliverNew = async (client) => {
|
|
119
|
+
const after = last ?? 0;
|
|
120
|
+
const found = await client.search({ uid: `${after + 1}:*` }, { uid: true });
|
|
121
|
+
const uids = (Array.isArray(found) ? found : [])
|
|
122
|
+
.filter((uid) => uid > after)
|
|
123
|
+
.sort((a, b) => a - b);
|
|
124
|
+
for (const uid of uids) {
|
|
125
|
+
if (stopped)
|
|
126
|
+
return;
|
|
127
|
+
try {
|
|
128
|
+
const message = await this.#read(client, uid);
|
|
129
|
+
if (message)
|
|
130
|
+
await handler(message, { uid });
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
report(error);
|
|
134
|
+
// The connection is gone (a server pushing more than the
|
|
135
|
+
// limit is cut off): what is left is delivered after the
|
|
136
|
+
// reconnection, not skipped as if it had failed. A message
|
|
137
|
+
// over the limit is skipped: it would be refused again.
|
|
138
|
+
if (!client.usable) {
|
|
139
|
+
if (error instanceof GoldstoneError &&
|
|
140
|
+
error.code === "E_GOLDSTONE_MESSAGE_TOO_LARGE") {
|
|
141
|
+
last = uid;
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
last = uid;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const run = async () => {
|
|
150
|
+
let attempt = 0;
|
|
151
|
+
while (!stopped) {
|
|
152
|
+
try {
|
|
153
|
+
const client = await this.#open();
|
|
154
|
+
current = client;
|
|
155
|
+
const opened = await client.mailboxOpen(folder);
|
|
156
|
+
if (uidValidity !== undefined && opened.uidValidity !== uidValidity) {
|
|
157
|
+
report(new GoldstoneError("E_GOLDSTONE_UIDVALIDITY_CHANGED", `[inbox] ${this.name}/${folder} renumbered its messages; watching resumes from the newest`));
|
|
158
|
+
last = undefined;
|
|
159
|
+
}
|
|
160
|
+
uidValidity = opened.uidValidity;
|
|
161
|
+
if (last === undefined)
|
|
162
|
+
last = opened.uidNext - 1;
|
|
163
|
+
attempt = 0;
|
|
164
|
+
await new Promise((resolve, reject) => {
|
|
165
|
+
// Listening before the catch-up: the server announces
|
|
166
|
+
// mail that arrives during its FETCHes, and an EXISTS
|
|
167
|
+
// nobody hears leaves the message waiting for the next.
|
|
168
|
+
// Every delivery runs after the previous one.
|
|
169
|
+
let queue = Promise.resolve();
|
|
170
|
+
client.on("exists", () => {
|
|
171
|
+
queue = queue.then(() => deliverNew(client)).catch(report);
|
|
172
|
+
});
|
|
173
|
+
client.on("close", () => resolve());
|
|
174
|
+
client.on("error", () => { });
|
|
175
|
+
wake = resolve;
|
|
176
|
+
if (stopped)
|
|
177
|
+
resolve();
|
|
178
|
+
// A catch-up that fails reopens the connection.
|
|
179
|
+
queue = deliverNew(client).catch(reject);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (!stopped)
|
|
184
|
+
report(error);
|
|
185
|
+
}
|
|
186
|
+
current?.close();
|
|
187
|
+
current = undefined;
|
|
188
|
+
if (stopped)
|
|
189
|
+
break;
|
|
190
|
+
attempt += 1;
|
|
191
|
+
await new Promise((resolve) => {
|
|
192
|
+
const timer = setTimeout(resolve, reconnectDelay(attempt));
|
|
193
|
+
wake = () => {
|
|
194
|
+
clearTimeout(timer);
|
|
195
|
+
resolve();
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
};
|
|
200
|
+
const done = run();
|
|
201
|
+
const stop = async () => {
|
|
202
|
+
stopped = true;
|
|
203
|
+
wake?.();
|
|
204
|
+
await current?.logout().catch(() => { });
|
|
205
|
+
await done;
|
|
206
|
+
this.#watches.delete(stop);
|
|
207
|
+
};
|
|
208
|
+
this.#watches.add(stop);
|
|
209
|
+
return stop;
|
|
210
|
+
}
|
|
211
|
+
/** Stop every watch and log out. */
|
|
212
|
+
async close() {
|
|
213
|
+
await Promise.all([...this.#watches].map((stop) => stop()));
|
|
214
|
+
const client = this.#client;
|
|
215
|
+
this.#client = undefined;
|
|
216
|
+
if (client) {
|
|
217
|
+
await client.then((c) => c.logout()).catch(() => { });
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
async #read(client, uid) {
|
|
221
|
+
const maxBytes = this.#limits?.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
222
|
+
const sized = await client.fetchOne(String(uid), { uid: true, size: true }, { uid: true });
|
|
223
|
+
if (!sized)
|
|
224
|
+
return undefined;
|
|
225
|
+
if (sized.size !== undefined && sized.size > maxBytes) {
|
|
226
|
+
throw new GoldstoneError("E_GOLDSTONE_MESSAGE_TOO_LARGE", `[inbox] message ${uid} is ${sized.size} bytes, over the ${maxBytes} allowed — not downloaded`);
|
|
227
|
+
}
|
|
228
|
+
// The server's size is a claim: the connection itself refuses a
|
|
229
|
+
// literal over the limit, before buffering it.
|
|
230
|
+
let full;
|
|
231
|
+
try {
|
|
232
|
+
full = await client.fetchOne(String(uid), { uid: true, source: true }, { uid: true });
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (oversized(error) || oversized(this.#cutOff.get(client))) {
|
|
236
|
+
throw new GoldstoneError("E_GOLDSTONE_MESSAGE_TOO_LARGE", `[inbox] message ${uid} is over the ${maxBytes} bytes allowed, whatever size the server reported — not downloaded`, { cause: error });
|
|
237
|
+
}
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
if (full === false || full === undefined || full.source === undefined) {
|
|
241
|
+
return undefined;
|
|
242
|
+
}
|
|
243
|
+
return readMessage(full.source, {
|
|
244
|
+
limits: this.#limits,
|
|
245
|
+
authenticate: this.#authenticate,
|
|
246
|
+
remoteContent: this.#remoteContent,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
async #in(folder, work) {
|
|
250
|
+
const client = await this.#connection();
|
|
251
|
+
const lock = await client.getMailboxLock(folder);
|
|
252
|
+
try {
|
|
253
|
+
return await work(client);
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
lock.release();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/** The shared connection, opened on first use and again after a loss. */
|
|
260
|
+
#connection() {
|
|
261
|
+
if (!this.#client) {
|
|
262
|
+
const opening = this.#open();
|
|
263
|
+
this.#client = opening;
|
|
264
|
+
opening.then((client) => client.on("close", () => {
|
|
265
|
+
if (this.#client === opening)
|
|
266
|
+
this.#client = undefined;
|
|
267
|
+
}), () => {
|
|
268
|
+
if (this.#client === opening)
|
|
269
|
+
this.#client = undefined;
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return this.#client;
|
|
273
|
+
}
|
|
274
|
+
async #open() {
|
|
275
|
+
const config = this.#config;
|
|
276
|
+
// `starttls` alone means a plaintext connection upgraded: TLS from
|
|
277
|
+
// the first byte is the default only without it.
|
|
278
|
+
const secure = config.secure ?? config.starttls !== true;
|
|
279
|
+
const auth = "pass" in config.auth
|
|
280
|
+
? { user: config.auth.user, pass: config.auth.pass }
|
|
281
|
+
: {
|
|
282
|
+
user: config.auth.user,
|
|
283
|
+
accessToken: typeof config.auth.accessToken === "function"
|
|
284
|
+
? await config.auth.accessToken()
|
|
285
|
+
: config.auth.accessToken,
|
|
286
|
+
};
|
|
287
|
+
const maxBytes = this.#limits?.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
288
|
+
const client = new ImapFlow({
|
|
289
|
+
// Whatever the server says a message weighs, never buffer more
|
|
290
|
+
// than the limit for one, nor much more for any response.
|
|
291
|
+
maxLiteralSize: maxBytes,
|
|
292
|
+
maxResponseSize: Math.max(maxBytes, RESPONSE_ROOM) + 64 * 1024,
|
|
293
|
+
maxLineLength: Math.max(maxBytes, RESPONSE_ROOM),
|
|
294
|
+
host: config.host,
|
|
295
|
+
port: config.port ?? (secure ? 993 : 143),
|
|
296
|
+
secure,
|
|
297
|
+
// Never the silent fallback to cleartext: either TLS from the start,
|
|
298
|
+
// or STARTTLS that must succeed, or a plaintext test server allowed
|
|
299
|
+
// by name.
|
|
300
|
+
doSTARTTLS: !secure && config.allowInsecure !== true
|
|
301
|
+
? true
|
|
302
|
+
: config.starttls === true,
|
|
303
|
+
tls: config.tls,
|
|
304
|
+
auth,
|
|
305
|
+
logger: false,
|
|
306
|
+
// IDLE starts after this much quiet; the default (15 s) delays every
|
|
307
|
+
// new-message notification by as much.
|
|
308
|
+
autoIdleDelay: 1000,
|
|
309
|
+
});
|
|
310
|
+
// The error that cut the connection, which a pending fetch does not
|
|
311
|
+
// always reject with.
|
|
312
|
+
client.on("error", (error) => {
|
|
313
|
+
this.#cutOff.set(client, error);
|
|
314
|
+
});
|
|
315
|
+
await client.connect();
|
|
316
|
+
return client;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/** An empty list is nothing to do — and an empty range a protocol error. */
|
|
320
|
+
function isEmpty(uids) {
|
|
321
|
+
return Array.isArray(uids) && uids.length === 0;
|
|
322
|
+
}
|
|
323
|
+
function range(uids) {
|
|
324
|
+
return Array.isArray(uids) ? uids.join(",") : String(uids);
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=Mailbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mailbox.js","sourceRoot":"","sources":["../src/Mailbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A received mail, parsed as the hostile input it is.
|
|
3
|
+
*
|
|
4
|
+
* const message = await parseMessage(raw)
|
|
5
|
+
* message.subject
|
|
6
|
+
* message.html // sanitized: safe to render
|
|
7
|
+
* message.attachments[0].fileName // safe to save under
|
|
8
|
+
*
|
|
9
|
+
* The parsing happens in Rust, in one call and off the JavaScript thread:
|
|
10
|
+
* the raw bytes go in, this comes out. The size is checked before a byte is
|
|
11
|
+
* parsed, the structure is bounded after, and what the sender controls — the
|
|
12
|
+
* HTML, the attachment names — is made safe before it reaches the
|
|
13
|
+
* application.
|
|
14
|
+
*/
|
|
15
|
+
import { type AuthenticateOptions, type Authenticity } from "./authenticity.js";
|
|
16
|
+
import { GoldstoneError } from "./errors.js";
|
|
17
|
+
import type { JsMessage } from "./native/generated.js";
|
|
18
|
+
/** Bounds on one message; each one left out keeps its default. */
|
|
19
|
+
export interface Limits {
|
|
20
|
+
/** Size of the raw message, checked before parsing. Default 25 MiB. */
|
|
21
|
+
maxBytes?: number;
|
|
22
|
+
/**
|
|
23
|
+
* MIME parts, the message itself included, and the parts of the
|
|
24
|
+
* messages it carries (message/rfc822). Default 1 000.
|
|
25
|
+
*/
|
|
26
|
+
maxParts?: number;
|
|
27
|
+
/** Nesting depth of multiparts and carried messages. Default 32. */
|
|
28
|
+
maxDepth?: number;
|
|
29
|
+
/** Header fields in one header block, the message's or a part's. Default 1 000. */
|
|
30
|
+
maxHeaders?: number;
|
|
31
|
+
/** Size of one header block. Default 1 MiB. */
|
|
32
|
+
maxHeaderBytes?: number;
|
|
33
|
+
/** Number of attachments. Default 100. */
|
|
34
|
+
maxAttachments?: number;
|
|
35
|
+
/** Size of one decoded attachment. Default 25 MiB. */
|
|
36
|
+
maxAttachmentBytes?: number;
|
|
37
|
+
/**
|
|
38
|
+
* Size of the HTML body that is sanitized. Over it, the message is still
|
|
39
|
+
* read, without `html` (see `htmlError`). Default 512 KiB.
|
|
40
|
+
*/
|
|
41
|
+
maxHtmlBytes?: number;
|
|
42
|
+
}
|
|
43
|
+
export interface Mailbox {
|
|
44
|
+
readonly name?: string;
|
|
45
|
+
readonly address?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface Header {
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/** As received, encoded words included. */
|
|
50
|
+
readonly value: string;
|
|
51
|
+
}
|
|
52
|
+
export interface Attachment {
|
|
53
|
+
/**
|
|
54
|
+
* Safe to save under, on any system: the last path segment of what the
|
|
55
|
+
* sender wrote, with control, invisible and bidi characters and the
|
|
56
|
+
* characters Windows refuses (`< > : " | ? *`, `:` naming an NTFS stream)
|
|
57
|
+
* replaced by `_`, without leading dots, trailing dots or spaces, or a
|
|
58
|
+
* Windows device name (`CON`, `COM1`, `CONIN$`…), at most 255 bytes.
|
|
59
|
+
*/
|
|
60
|
+
readonly fileName: string;
|
|
61
|
+
/** The name as the sender wrote it. For display only — never a path. */
|
|
62
|
+
readonly originalName?: string;
|
|
63
|
+
readonly contentType: string;
|
|
64
|
+
readonly size: number;
|
|
65
|
+
readonly content: Uint8Array;
|
|
66
|
+
readonly contentId?: string;
|
|
67
|
+
readonly inline: boolean;
|
|
68
|
+
}
|
|
69
|
+
export declare class ReceivedMessage {
|
|
70
|
+
#private;
|
|
71
|
+
readonly messageId?: string;
|
|
72
|
+
readonly subject?: string;
|
|
73
|
+
readonly date?: Date;
|
|
74
|
+
readonly from: readonly Mailbox[];
|
|
75
|
+
readonly to: readonly Mailbox[];
|
|
76
|
+
readonly cc: readonly Mailbox[];
|
|
77
|
+
readonly bcc: readonly Mailbox[];
|
|
78
|
+
readonly replyTo: readonly Mailbox[];
|
|
79
|
+
readonly inReplyTo: readonly string[];
|
|
80
|
+
readonly references: readonly string[];
|
|
81
|
+
readonly headers: readonly Header[];
|
|
82
|
+
readonly text?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Sanitized for display: no script, no event handler, no `javascript:`
|
|
85
|
+
* URL, and no remote content unless `remoteContent: "allow"`.
|
|
86
|
+
*/
|
|
87
|
+
readonly html?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Why `html` is absent although the message has an HTML body: over
|
|
90
|
+
* `maxHtmlBytes` (`E_GOLDSTONE_HTML_TOO_LARGE`), nested too deep
|
|
91
|
+
* (`…_HTML_TOO_DEEP`), or building a tree out of proportion to its markup
|
|
92
|
+
* (`…_HTML_TOO_COMPLEX`). Sanitizing such HTML would cost time that grows
|
|
93
|
+
* faster than its size; the text and the rest of the message are there.
|
|
94
|
+
*/
|
|
95
|
+
readonly htmlError?: GoldstoneError;
|
|
96
|
+
readonly attachments: readonly Attachment[];
|
|
97
|
+
/**
|
|
98
|
+
* Who really sent it — present when the message was read with
|
|
99
|
+
* {@link readMessage} (as a mailbox reads it), absent from
|
|
100
|
+
* {@link parseMessage}, which does no DNS.
|
|
101
|
+
*/
|
|
102
|
+
readonly authenticity?: Authenticity;
|
|
103
|
+
constructor(parsed: JsMessage, authenticity?: Authenticity);
|
|
104
|
+
/**
|
|
105
|
+
* The first header of that name, any case: the copy the message's
|
|
106
|
+
* fields (`from`, `subject`…) read too. Every copy is in `headers`.
|
|
107
|
+
*/
|
|
108
|
+
header(name: string): string | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* The HTML exactly as the sender wrote it. Never render it: it can carry
|
|
111
|
+
* scripts. It exists for what has to see the original — archiving,
|
|
112
|
+
* forwarding, forensic inspection.
|
|
113
|
+
*/
|
|
114
|
+
unsanitizedHtml(): string | undefined;
|
|
115
|
+
}
|
|
116
|
+
export interface ParseOptions {
|
|
117
|
+
limits?: Limits;
|
|
118
|
+
/**
|
|
119
|
+
* Whether the sanitized `html` may load remote content by itself —
|
|
120
|
+
* images, backgrounds, video posters. `"block"` (the default) removes
|
|
121
|
+
* those URLs: rendering a remote image tells the sender the message was
|
|
122
|
+
* opened, when, and from where. `cid:` references to the message's own
|
|
123
|
+
* parts are kept either way. Links stay: they are followed only when
|
|
124
|
+
* clicked.
|
|
125
|
+
*/
|
|
126
|
+
remoteContent?: "block" | "allow";
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parse one received message — raw RFC 5322 bytes, as IMAP fetches them or
|
|
130
|
+
* a provider posts them. The work runs off the event loop.
|
|
131
|
+
*
|
|
132
|
+
* Rejects with a `GoldstoneError` on a message over a limit
|
|
133
|
+
* (`E_GOLDSTONE_MESSAGE_TOO_LARGE`, `…_TOO_MANY_PARTS`, `…_TOO_DEEP`,
|
|
134
|
+
* `…_TOO_MANY_HEADERS`, `…_HEADERS_TOO_LARGE`, `…_MISSING_BOUNDARIES`,
|
|
135
|
+
* `…_BOUNDARY_TOO_LONG`, `…_TOO_MANY_ATTACHMENTS`, `…_ATTACHMENT_TOO_LARGE`) or not a message at
|
|
136
|
+
* all (`E_GOLDSTONE_NOT_A_MESSAGE`).
|
|
137
|
+
*/
|
|
138
|
+
export declare function parseMessage(raw: Uint8Array, options?: ParseOptions): Promise<ReceivedMessage>;
|
|
139
|
+
export interface ReadOptions extends ParseOptions {
|
|
140
|
+
/**
|
|
141
|
+
* Check DKIM, SPF and DMARC — `true` (the default), `false`, or the
|
|
142
|
+
* envelope and bounds {@link authenticate} takes.
|
|
143
|
+
*/
|
|
144
|
+
authenticate?: boolean | AuthenticateOptions;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Parse a received message AND check who sent it, the verdict on
|
|
148
|
+
* `message.authenticity`. Both come from one parse: the From the verdict
|
|
149
|
+
* speaks for is the From the message shows.
|
|
150
|
+
*/
|
|
151
|
+
export declare function readMessage(raw: Uint8Array, options?: ReadOptions): Promise<ReceivedMessage>;
|
|
152
|
+
//# sourceMappingURL=ReceivedMessage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReceivedMessage.d.ts","sourceRoot":"","sources":["../src/ReceivedMessage.ts"],"names":[],"mappings":"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"}
|