@rndmjoker/proton-mcp 0.4.11 → 0.4.13

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.
Files changed (97) hide show
  1. package/README.md +61 -16
  2. package/dist/bridge/certificate.d.ts +33 -1
  3. package/dist/bridge/certificate.js +82 -9
  4. package/dist/bridge/certificate.js.map +1 -1
  5. package/dist/bridge/connection.js +31 -6
  6. package/dist/bridge/connection.js.map +1 -1
  7. package/dist/bridge/errors.d.ts +8 -0
  8. package/dist/bridge/errors.js +28 -3
  9. package/dist/bridge/errors.js.map +1 -1
  10. package/dist/config.d.ts +6 -0
  11. package/dist/config.js +1 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/credentials/availability.d.ts +5 -0
  14. package/dist/credentials/availability.js +7 -0
  15. package/dist/credentials/availability.js.map +1 -1
  16. package/dist/credentials/encrypted-file.js +7 -2
  17. package/dist/credentials/encrypted-file.js.map +1 -1
  18. package/dist/credentials/keyring.d.ts +12 -2
  19. package/dist/credentials/keyring.js +44 -6
  20. package/dist/credentials/keyring.js.map +1 -1
  21. package/dist/credentials/plain-file.js +8 -2
  22. package/dist/credentials/plain-file.js.map +1 -1
  23. package/dist/credentials/session-bus.d.ts +38 -0
  24. package/dist/credentials/session-bus.js +68 -0
  25. package/dist/credentials/session-bus.js.map +1 -0
  26. package/dist/credentials/store.d.ts +5 -1
  27. package/dist/credentials/store.js.map +1 -1
  28. package/dist/mail/attachments.d.ts +12 -2
  29. package/dist/mail/attachments.js +19 -11
  30. package/dist/mail/attachments.js.map +1 -1
  31. package/dist/mail/compose.d.ts +65 -9
  32. package/dist/mail/compose.js +147 -11
  33. package/dist/mail/compose.js.map +1 -1
  34. package/dist/mail/drafts.d.ts +13 -2
  35. package/dist/mail/drafts.js +69 -18
  36. package/dist/mail/drafts.js.map +1 -1
  37. package/dist/mail/ids.js +6 -4
  38. package/dist/mail/ids.js.map +1 -1
  39. package/dist/mail/messages.d.ts +25 -2
  40. package/dist/mail/messages.js +37 -4
  41. package/dist/mail/messages.js.map +1 -1
  42. package/dist/mail/saved-attachments.d.ts +128 -0
  43. package/dist/mail/saved-attachments.js +448 -0
  44. package/dist/mail/saved-attachments.js.map +1 -0
  45. package/dist/mail/search.d.ts +67 -3
  46. package/dist/mail/search.js +134 -23
  47. package/dist/mail/search.js.map +1 -1
  48. package/dist/mail/send.js +24 -9
  49. package/dist/mail/send.js.map +1 -1
  50. package/dist/mail/uid-search.d.ts +17 -0
  51. package/dist/mail/uid-search.js +25 -0
  52. package/dist/mail/uid-search.js.map +1 -0
  53. package/dist/mime/filenames.d.ts +24 -0
  54. package/dist/mime/filenames.js +58 -0
  55. package/dist/mime/filenames.js.map +1 -0
  56. package/dist/mime/parts.d.ts +34 -0
  57. package/dist/mime/parts.js +92 -0
  58. package/dist/mime/parts.js.map +1 -0
  59. package/dist/server.js +39 -6
  60. package/dist/server.js.map +1 -1
  61. package/dist/session.d.ts +15 -3
  62. package/dist/session.js +35 -8
  63. package/dist/session.js.map +1 -1
  64. package/dist/tools/confirm.js +39 -11
  65. package/dist/tools/confirm.js.map +1 -1
  66. package/dist/tools/drafts.d.ts +3 -0
  67. package/dist/tools/drafts.js +18 -6
  68. package/dist/tools/drafts.js.map +1 -1
  69. package/dist/tools/filters.d.ts +40 -0
  70. package/dist/tools/filters.js +89 -0
  71. package/dist/tools/filters.js.map +1 -0
  72. package/dist/tools/format.d.ts +8 -0
  73. package/dist/tools/format.js +29 -6
  74. package/dist/tools/format.js.map +1 -1
  75. package/dist/tools/guidance.js +27 -3
  76. package/dist/tools/guidance.js.map +1 -1
  77. package/dist/tools/messages.js +7 -2
  78. package/dist/tools/messages.js.map +1 -1
  79. package/dist/tools/pending-view.d.ts +7 -0
  80. package/dist/tools/pending-view.js +4 -1
  81. package/dist/tools/pending-view.js.map +1 -1
  82. package/dist/tools/saved.d.ts +15 -0
  83. package/dist/tools/saved.js +107 -0
  84. package/dist/tools/saved.js.map +1 -0
  85. package/dist/tools/send.js +4 -1
  86. package/dist/tools/send.js.map +1 -1
  87. package/dist/web/layout.js +2 -0
  88. package/dist/web/layout.js.map +1 -1
  89. package/dist/web/pages.js +1 -0
  90. package/dist/web/pages.js.map +1 -1
  91. package/dist/web/pending.d.ts +4 -0
  92. package/dist/web/pending.js +32 -4
  93. package/dist/web/pending.js.map +1 -1
  94. package/dist/web/server.d.ts +16 -5
  95. package/dist/web/server.js +12 -8
  96. package/dist/web/server.js.map +1 -1
  97. package/package.json +16 -8
@@ -12,24 +12,115 @@
12
12
  *
13
13
  * Metadata queries are cheap by comparison: unread came back in 3 ms, a size
14
14
  * filter in 437 ms.
15
+ *
16
+ * Text is the exception to "the Bridge searches". Measured on 2026-11-02 and
17
+ * read in the source of gluon, its IMAP library: SUBJECT, FROM and TO compare
18
+ * against the header as it is stored, and a header with one letter outside
19
+ * ASCII is stored encoded, "Mit Anhang" as "Mit_Anhang", or in base64, where no
20
+ * word is legible at all. Up to 0.4.11 a subject search for "Mit Anhang" found
21
+ * nothing, and the answer read like a search without matches. So the Bridge
22
+ * now filters by everything but those three, and this server compares them
23
+ * against the envelope, which imapflow decodes. Full text stays with the
24
+ * Bridge, which compares the raw bytes; a word outside ASCII is also asked for
25
+ * in the form a quoted-printable part carries it, and a part sent as base64
26
+ * stays out of reach, which every answer says.
15
27
  */
16
28
  import { BridgeError } from '../bridge/errors.js';
17
- import { fetchDates, fetchHeaders, orderNewestFirst, MAX_LIST_LIMIT, withTrashMarks, } from './messages.js';
18
- /** Translates the criteria into what imapflow expects. */
19
- export function buildQuery(criteria) {
29
+ import { searchUids } from './uid-search.js';
30
+ import { fetchEnvelopes, fetchHeaders, orderNewestFirst, MAX_LIST_LIMIT, withTrashMarks, } from './messages.js';
31
+ /**
32
+ * How many envelopes a search compares itself, at most.
33
+ *
34
+ * Without other criteria a subject search reads the envelope of every message
35
+ * in the mailbox. Reading one per hit is what the ordering has always cost, and
36
+ * a common word matched 6803 messages in a mailbox of 26816, but there has to
37
+ * be an end. Past it, the most recently added messages are compared and the
38
+ * answer says so; there is no silent cut.
39
+ */
40
+ export const MAX_COMPARED = 20_000;
41
+ /** Whether a byte sequence has anything outside ASCII. */
42
+ const outsideAscii = (text) => /[^\x00-\x7f]/.test(text);
43
+ /**
44
+ * A word as a quoted-printable part carries it: every byte of its UTF-8 form
45
+ * outside printable ASCII, and the equals sign, as =XX.
46
+ */
47
+ export function quotedPrintable(text) {
48
+ let out = '';
49
+ for (const byte of Buffer.from(text.normalize('NFC'), 'utf8')) {
50
+ out +=
51
+ byte > 0x7e || byte < 0x20 || byte === 0x3d
52
+ ? `=${byte.toString(16).toUpperCase().padStart(2, '0')}`
53
+ : String.fromCharCode(byte);
54
+ }
55
+ return out;
56
+ }
57
+ /**
58
+ * The forms a full-text word is asked for in.
59
+ *
60
+ * The Bridge compares the raw bytes of a message, lower cased, so a word with a
61
+ * letter outside ASCII is found only where a part carries it unencoded. Most
62
+ * text with umlauts travels as quoted-printable, where a u with umlaut is the
63
+ * six characters "=C3=BC" and an a with umlaut "=C3=A4". Lower casing does not reach into
64
+ * that encoding, so the usual spellings of a word are each asked for: as given,
65
+ * in lower case, and capitalised. Forms that differ only in the case of ASCII
66
+ * letters are asked once, since the Bridge lower cases both sides. A word
67
+ * broken across a line by the encoding is still missed, and so is anything in
68
+ * base64.
69
+ */
70
+ export function textForms(term) {
71
+ if (!outsideAscii(term))
72
+ return [term];
73
+ const lower = term.toLowerCase();
74
+ const capitalised = lower.charAt(0).toUpperCase() + lower.slice(1);
75
+ const forms = new Map([[term.toLowerCase(), term]]);
76
+ for (const spelling of [term, lower, capitalised]) {
77
+ const form = quotedPrintable(spelling);
78
+ if (!forms.has(form.toLowerCase()))
79
+ forms.set(form.toLowerCase(), form);
80
+ }
81
+ return [...forms.values()];
82
+ }
83
+ /** Folded for comparison: one Unicode form, lower case. */
84
+ const fold = (text) => text.normalize('NFC').toLowerCase();
85
+ /** How an address reads in a header, which is what FROM and TO used to match. */
86
+ const shown = (a) => (a.name ? `${a.name} <${a.address}>` : a.address);
87
+ /** Whether a message passes what this server compares itself. */
88
+ export function matchesLocally(entry, local) {
89
+ if (local.subject !== undefined && !fold(entry.subject).includes(fold(local.subject)))
90
+ return false;
91
+ if (local.from !== undefined && !entry.from.some((a) => fold(shown(a)).includes(fold(local.from ?? '')))) {
92
+ return false;
93
+ }
94
+ if (local.to !== undefined && !entry.to.some((a) => fold(shown(a)).includes(fold(local.to ?? '')))) {
95
+ return false;
96
+ }
97
+ return true;
98
+ }
99
+ /**
100
+ * Splits the criteria into what the Bridge is asked and what this server
101
+ * compares itself.
102
+ */
103
+ export function planSearch(criteria) {
20
104
  // Typed as what it is rather than built loosely and cast at the end. The cast
21
105
  // was how `since` survived: a field name imapflow does not know is silently
22
106
  // an ignored criterion, so the search returns too much and nothing complains.
23
107
  // With the real type a wrong name is a compile error.
24
108
  const query = {};
25
- if (criteria.text)
26
- query.text = criteria.text;
109
+ const local = {};
110
+ if (criteria.text) {
111
+ const forms = textForms(criteria.text);
112
+ if (forms.length === 1)
113
+ query.text = criteria.text;
114
+ else
115
+ query.or = forms.map((form) => ({ text: form }));
116
+ }
117
+ // Compared here rather than by the Bridge, see the top of this file.
27
118
  if (criteria.subject)
28
- query.header = { subject: criteria.subject };
119
+ local.subject = criteria.subject;
29
120
  if (criteria.from)
30
- query.from = criteria.from;
121
+ local.from = criteria.from;
31
122
  if (criteria.to)
32
- query.to = criteria.to;
123
+ local.to = criteria.to;
33
124
  // sentSince and sentBefore, not since and before. Those two are IMAP SINCE
34
125
  // and BEFORE, which compare INTERNALDATE, the moment the server received the
35
126
  // message. Everything this server shows and sorts by comes from the envelope,
@@ -50,11 +141,16 @@ export function buildQuery(criteria) {
50
141
  query.larger = criteria.largerThan;
51
142
  // An empty query would match everything, which is list_messages rather than
52
143
  // a search. Saying so is better than silently returning the whole mailbox.
53
- if (Object.keys(query).length === 0) {
144
+ const comparedHere = Object.keys(local).length > 0;
145
+ if (Object.keys(query).length === 0 && !comparedHere) {
54
146
  throw new BridgeError('A search needs at least one criterion. Pass text, subject, from, to, since, before, ' +
55
147
  'unread, starred or largerThan. To see everything in a mailbox use list_messages instead.');
56
148
  }
57
- return query;
149
+ // Only the comparison here narrows it down, so the Bridge hands over every
150
+ // message and this server reads their envelopes.
151
+ if (Object.keys(query).length === 0)
152
+ query.all = true;
153
+ return { query, local };
58
154
  }
59
155
  /** Whether a query contains the expensive full-text part. */
60
156
  export function isFullText(criteria) {
@@ -71,15 +167,15 @@ export async function searchMessages(connection, path, options) {
71
167
  const limit = Math.min(Math.max(rawLimit ?? 25, 1), MAX_LIST_LIMIT);
72
168
  const offset = Math.max(rawOffset ?? 0, 0);
73
169
  // Built before opening the mailbox, so an empty query fails fast.
74
- const query = buildQuery(criteria);
170
+ const { query, local } = planSearch(criteria);
171
+ const comparedHere = Object.keys(local).length > 0;
172
+ const fullText = isFullText(criteria);
173
+ const encodedForms = Boolean(criteria.text) && textForms(criteria.text ?? '').length > 1;
75
174
  const started = process.hrtime.bigint();
76
175
  const uids = await connection.withMailbox(path, async (client, status) => {
77
176
  if (status.messages === 0)
78
177
  return [];
79
- const hits = await client.search(query, { uid: true });
80
- // imapflow answers with false rather than an empty array when a search
81
- // yields nothing, and `?? []` would let that through.
82
- return Array.isArray(hits) ? hits : [];
178
+ return searchUids(client, query, `messages in "${path}"`);
83
179
  });
84
180
  const elapsedMs = Math.round(Number(process.hrtime.bigint() - started) / 1e6);
85
181
  if (uids.length === 0) {
@@ -90,17 +186,30 @@ export async function searchMessages(connection, path, options) {
90
186
  headers: [],
91
187
  elapsedMs,
92
188
  ordering: { messages: 0, elapsedMs: 0 },
93
- fullText: isFullText(criteria),
189
+ fullText,
190
+ encodedForms,
94
191
  };
95
192
  }
96
- // Ordering reads the date of every hit, because a page can only be cut out of
97
- // a list that is already in order. Only the dates: the full header fetch below
98
- // still covers one page, which is what keeps this affordable. A common word
99
- // matched 6803 messages in the measured mailbox.
193
+ // Past the limit the most recently added are compared: the highest uids. The
194
+ // answer says so, see MAX_COMPARED.
195
+ let candidates = uids;
196
+ let compared;
197
+ if (comparedHere && uids.length > MAX_COMPARED) {
198
+ candidates = [...uids].sort((a, b) => b - a).slice(0, MAX_COMPARED);
199
+ compared = { compared: MAX_COMPARED, of: uids.length };
200
+ }
201
+ // Ordering reads the envelope of every candidate, because a page can only be
202
+ // cut out of a list that is already in order. The same read carries the
203
+ // subject, sender and recipients compared here. Only the envelopes: the full
204
+ // header fetch below still covers one page, which is what keeps this
205
+ // affordable. A common word matched 6803 messages in the measured mailbox.
100
206
  const orderStarted = process.hrtime.bigint();
101
- const ordered = await connection.withMailbox(path, async (client) => orderNewestFirst(await fetchDates(client, uids)));
207
+ const ordered = await connection.withMailbox(path, async (client) => {
208
+ const entries = await fetchEnvelopes(client, candidates);
209
+ return orderNewestFirst(comparedHere ? entries.filter((entry) => matchesLocally(entry, local)) : entries);
210
+ });
102
211
  const ordering = {
103
- messages: uids.length,
212
+ messages: candidates.length,
104
213
  elapsedMs: Math.round(Number(process.hrtime.bigint() - orderStarted) / 1e6),
105
214
  };
106
215
  const page = ordered.slice(offset, offset + limit);
@@ -113,7 +222,9 @@ export async function searchMessages(connection, path, options) {
113
222
  headers,
114
223
  elapsedMs,
115
224
  ordering,
116
- fullText: isFullText(criteria),
225
+ fullText,
226
+ encodedForms,
227
+ ...(compared ? { compared } : {}),
117
228
  });
118
229
  }
119
230
  //# sourceMappingURL=search.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/mail/search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/mail/search.ts"],"names":[],"mappings":"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"}
package/dist/mail/send.js CHANGED
@@ -40,8 +40,8 @@
40
40
  * envelope is stated separately below.
41
41
  */
42
42
  import { createTransport } from 'nodemailer';
43
- import { BridgeError } from '../bridge/errors.js';
44
- import { ensurePinned } from '../bridge/certificate.js';
43
+ import { BridgeError, explainError, isConnectionFailure } from '../bridge/errors.js';
44
+ import { certificateChanged, pinFor } from '../bridge/certificate.js';
45
45
  import { buildMessage, allRecipients } from './compose.js';
46
46
  /**
47
47
  * Opens an authenticated SMTP connection to the Bridge.
@@ -49,12 +49,7 @@ import { buildMessage, allRecipients } from './compose.js';
49
49
  * Built per send rather than held open. Sending is rare, and a connection that
50
50
  * sits idle holding the Bridge password is a worse trade than a handshake.
51
51
  */
52
- async function transport(config, credentials) {
53
- // The pin is recorded against the IMAP port because that is where the first
54
- // connection happens. Measured to be the same certificate on the SMTP port,
55
- // so this is the material to verify against; a difference fails the
56
- // handshake rather than being waved through.
57
- const pinned = await ensurePinned(config.host, config.imapPort);
52
+ function transport(config, credentials, pinned) {
58
53
  return createTransport({
59
54
  host: config.host,
60
55
  port: config.smtpPort,
@@ -104,7 +99,17 @@ export async function sendMessage(config, getCredentials, readOnly, draft) {
104
99
  // Built without the blind copies in the headers. They travel in the envelope
105
100
  // below, where the other recipients never see them.
106
101
  const raw = await buildMessage(draft, { keepBcc: false });
107
- const mailer = await transport(config, credentials);
102
+ // The pin is recorded against the IMAP port because that is where the first
103
+ // connection happens. Measured to be the same certificate on the SMTP port,
104
+ // so this is the material to verify against; a difference fails the
105
+ // handshake rather than being waved through.
106
+ //
107
+ // On first use reading it is the first thing that reaches the Bridge, so a
108
+ // Bridge that is not running fails here, before the try below.
109
+ const pinned = await pinFor(config.host, config.imapPort).catch((error) => {
110
+ throw error instanceof BridgeError ? error : explainError(error, config.host, config.imapPort);
111
+ });
112
+ const mailer = transport(config, credentials, pinned);
108
113
  try {
109
114
  const info = await mailer.sendMail({
110
115
  // The bytes, not the fields: what was confirmed is what goes out.
@@ -122,6 +127,16 @@ export async function sendMessage(config, getCredentials, readOnly, draft) {
122
127
  };
123
128
  }
124
129
  catch (error) {
130
+ // A certificate other than the pinned one fails the handshake before AUTH,
131
+ // and from here that looks like any other failure. Only now is a probe
132
+ // worth it.
133
+ const changed = await certificateChanged(config.host, config.imapPort, pinned);
134
+ if (changed)
135
+ throw changed;
136
+ // With a pin there is no probe in front of the send any more, so a Bridge
137
+ // that is not running is first noticed here, and is explained the same way.
138
+ if (isConnectionFailure(error))
139
+ throw explainError(error, config.host, config.smtpPort);
125
140
  throw new BridgeError(`The Bridge did not accept the message: ${error.message}. ` +
126
141
  'Nothing was sent, and it can be sent again once the Bridge is reachable.', 'unreachable', { cause: error });
127
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/mail/send.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"send.js","sourceRoot":"","sources":["../../src/mail/send.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A UID SEARCH that tells a failure apart from an empty result.
3
+ *
4
+ * imapflow answers a search that matched nothing with an empty array, and a
5
+ * search that failed with `false`: it catches the error, logs it and returns.
6
+ * The logger is switched off here, so `false` is all that arrives. Read as
7
+ * "nothing matched", a failed search makes a mailbox look empty and a message
8
+ * look as though it did not exist, and the assistant goes on to act on an
9
+ * answer that never came.
10
+ */
11
+ import type { ImapFlow, SearchObject } from 'imapflow';
12
+ /**
13
+ * Runs the search and returns the matching UIDs, or throws when it failed.
14
+ *
15
+ * `what` names what was being looked for, so the refusal can say it.
16
+ */
17
+ export declare function searchUids(client: ImapFlow, query: SearchObject, what: string): Promise<number[]>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * A UID SEARCH that tells a failure apart from an empty result.
3
+ *
4
+ * imapflow answers a search that matched nothing with an empty array, and a
5
+ * search that failed with `false`: it catches the error, logs it and returns.
6
+ * The logger is switched off here, so `false` is all that arrives. Read as
7
+ * "nothing matched", a failed search makes a mailbox look empty and a message
8
+ * look as though it did not exist, and the assistant goes on to act on an
9
+ * answer that never came.
10
+ */
11
+ import { BridgeError } from '../bridge/errors.js';
12
+ /**
13
+ * Runs the search and returns the matching UIDs, or throws when it failed.
14
+ *
15
+ * `what` names what was being looked for, so the refusal can say it.
16
+ */
17
+ export async function searchUids(client, query, what) {
18
+ const hits = await client.search(query, { uid: true });
19
+ if (Array.isArray(hits))
20
+ return hits;
21
+ throw new BridgeError(`The search for ${what} failed, so this says nothing about which messages match: it is not ` +
22
+ 'an empty result. The Bridge gave no reason. Try again, and if it fails again, check that ' +
23
+ 'the Bridge is running and unlocked.');
24
+ }
25
+ //# sourceMappingURL=uid-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uid-search.js","sourceRoot":"","sources":["../../src/mail/uid-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAEjD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAgB,EAChB,KAAmB,EACnB,IAAY;IAEZ,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAA;IACtD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IACpC,MAAM,IAAI,WAAW,CACnB,kBAAkB,IAAI,sEAAsE;QAC1F,2FAA2F;QAC3F,qCAAqC,CACxC,CAAA;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * File names taken from a message, made safe to hand on.
3
+ *
4
+ * A name in a message was chosen by whoever wrote it. It ends up as the name of
5
+ * an attachment this server builds, and with save_attachment as a name on this
6
+ * machine's disk, so the same rule serves both.
7
+ *
8
+ * Letters and digits of every script stay. An attachment name may carry them
9
+ * (RFC 2231), and a name with underscores where its umlauts were helps nobody:
10
+ * up to 0.4.11 a forwarded original named after a German subject lost every
11
+ * one of them. Everything else becomes an underscore: path separators, the
12
+ * characters Windows forbids in a name, control characters, and formatting
13
+ * characters such as U+202E, which can make "txt.exe" read as "exe.txt".
14
+ */
15
+ /**
16
+ * Reduces a name to a plain file name.
17
+ *
18
+ * Never empty and never a path: the result has no separator, does not start
19
+ * with a dot and is not a device name on Windows. `fallback` is used when
20
+ * nothing usable is left, and has to be plain itself.
21
+ */
22
+ export declare function plainFileName(name: string, fallback: string, maxLength?: number): string;
23
+ /** The name a forwarded original travels under, built from its subject. */
24
+ export declare function forwardedFileName(subject: string | undefined): string;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * File names taken from a message, made safe to hand on.
3
+ *
4
+ * A name in a message was chosen by whoever wrote it. It ends up as the name of
5
+ * an attachment this server builds, and with save_attachment as a name on this
6
+ * machine's disk, so the same rule serves both.
7
+ *
8
+ * Letters and digits of every script stay. An attachment name may carry them
9
+ * (RFC 2231), and a name with underscores where its umlauts were helps nobody:
10
+ * up to 0.4.11 a forwarded original named after a German subject lost every
11
+ * one of them. Everything else becomes an underscore: path separators, the
12
+ * characters Windows forbids in a name, control characters, and formatting
13
+ * characters such as U+202E, which can make "txt.exe" read as "exe.txt".
14
+ */
15
+ /** Everything that is not a letter, a mark, a digit or one of a few separators. */
16
+ const OUTSIDE_PLAIN = /[^\p{L}\p{M}\p{N} ._()-]/gu;
17
+ /** Names Windows reserves for devices, with or without an extension. */
18
+ const RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i;
19
+ /** An extension worth keeping when a name has to be shortened. */
20
+ const EXTENSION = /\.[\p{L}\p{N}]{1,10}$/u;
21
+ /** Drops the dots and spaces Windows strips without asking, and hidden-file dots. */
22
+ const trimEdges = (name) => name.replace(/^[. ]+/, '').replace(/[. ]+$/, '');
23
+ /**
24
+ * Shortens to a number of characters, not UTF-16 units, so a letter outside the
25
+ * basic plane is never cut in half. The extension survives when there is one.
26
+ */
27
+ function shorten(name, maxLength) {
28
+ const chars = Array.from(name);
29
+ if (chars.length <= maxLength)
30
+ return name;
31
+ const extension = EXTENSION.exec(name)?.[0] ?? '';
32
+ const extensionChars = Array.from(extension);
33
+ const base = chars.slice(0, chars.length - extensionChars.length);
34
+ const room = maxLength - extensionChars.length;
35
+ // Cutting can leave a dot or a space at the new end, which trimEdges would
36
+ // have removed had it been there before.
37
+ return trimEdges(base.slice(0, Math.max(room, 1)).join('')) + extension;
38
+ }
39
+ /**
40
+ * Reduces a name to a plain file name.
41
+ *
42
+ * Never empty and never a path: the result has no separator, does not start
43
+ * with a dot and is not a device name on Windows. `fallback` is used when
44
+ * nothing usable is left, and has to be plain itself.
45
+ */
46
+ export function plainFileName(name, fallback, maxLength = 100) {
47
+ let result = trimEdges(name.normalize('NFC').replace(OUTSIDE_PLAIN, '_'));
48
+ if (!result)
49
+ result = fallback;
50
+ if (RESERVED.test(result))
51
+ result = `_${result}`;
52
+ return shorten(result, maxLength);
53
+ }
54
+ /** The name a forwarded original travels under, built from its subject. */
55
+ export function forwardedFileName(subject) {
56
+ return `${plainFileName(subject ?? '', 'message', 60)}.eml`;
57
+ }
58
+ //# sourceMappingURL=filenames.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filenames.js","sourceRoot":"","sources":["../../src/mime/filenames.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,mFAAmF;AACnF,MAAM,aAAa,GAAG,4BAA4B,CAAA;AAElD,wEAAwE;AACxE,MAAM,QAAQ,GAAG,+CAA+C,CAAA;AAEhE,kEAAkE;AAClE,MAAM,SAAS,GAAG,wBAAwB,CAAA;AAE1C,qFAAqF;AACrF,MAAM,SAAS,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;AAE5F;;;GAGG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,SAAiB;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAA;IAE1C,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IACjD,MAAM,cAAc,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC5C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;IACjE,MAAM,IAAI,GAAG,SAAS,GAAG,cAAc,CAAC,MAAM,CAAA;IAC9C,2EAA2E;IAC3E,yCAAyC;IACzC,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,QAAgB,EAAE,SAAS,GAAG,GAAG;IAC3E,IAAI,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,CAAA;IACzE,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,QAAQ,CAAA;IAC9B,IAAI,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;IAChD,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;AACnC,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC,MAAM,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The parts of a stored message, read so that they can be built into a message
3
+ * again unchanged.
4
+ *
5
+ * mailparser is the wrong tool for this, measured with mailparser 3.14.1. It
6
+ * descends into a forwarded original (message/rfc822) and writes it into the
7
+ * body as a table of its headers, so the original disappears from the
8
+ * attachments and turns up as markup nobody wrote. And it rewrites every cid:
9
+ * image into a data: address, which the markup check refuses at every level. A
10
+ * stored draft read back that way could not be sent as it was stored.
11
+ *
12
+ * mailsplit, the splitter mailparser itself is built on, keeps a forwarded
13
+ * original as one part when asked to and hands out the bytes of every part.
14
+ * The body here is the first text/plain and the first text/html part that is
15
+ * not an attachment; everything else is a file, carried along as it was.
16
+ */
17
+ /** A file inside a stored message, with its content. */
18
+ export interface CarriedFile {
19
+ filename: string;
20
+ contentType: string;
21
+ content: Buffer;
22
+ /** Set when the markup refers to the file by cid. */
23
+ contentId?: string;
24
+ }
25
+ export interface StoredParts {
26
+ /** The plain text body, when there is one. */
27
+ text?: string;
28
+ /** The markup body, with its cid: references as they were. */
29
+ html?: string;
30
+ /** Every other part, in the order the message carries them. */
31
+ files: CarriedFile[];
32
+ }
33
+ /** Reads a stored message into its body and the files it carries. */
34
+ export declare function readParts(source: Buffer): Promise<StoredParts>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The parts of a stored message, read so that they can be built into a message
3
+ * again unchanged.
4
+ *
5
+ * mailparser is the wrong tool for this, measured with mailparser 3.14.1. It
6
+ * descends into a forwarded original (message/rfc822) and writes it into the
7
+ * body as a table of its headers, so the original disappears from the
8
+ * attachments and turns up as markup nobody wrote. And it rewrites every cid:
9
+ * image into a data: address, which the markup check refuses at every level. A
10
+ * stored draft read back that way could not be sent as it was stored.
11
+ *
12
+ * mailsplit, the splitter mailparser itself is built on, keeps a forwarded
13
+ * original as one part when asked to and hands out the bytes of every part.
14
+ * The body here is the first text/plain and the first text/html part that is
15
+ * not an attachment; everything else is a file, carried along as it was.
16
+ */
17
+ import { Splitter } from '@zone-eu/mailsplit';
18
+ import libmime from 'libmime';
19
+ import { isProtonPublicKey } from './parse.js';
20
+ /** Runs bytes through a stream and collects what comes out. */
21
+ async function through(stream, chunks) {
22
+ const out = [];
23
+ const done = (async () => {
24
+ for await (const chunk of stream)
25
+ out.push(Buffer.from(chunk));
26
+ })();
27
+ for (const chunk of chunks)
28
+ stream.write(chunk);
29
+ stream.end();
30
+ await done;
31
+ return Buffer.concat(out);
32
+ }
33
+ async function asText(node, decoded) {
34
+ const text = (await through(libmime.createDecodeStream(node.charset || 'utf-8'), [decoded])).toString('utf8');
35
+ return node.flowed ? libmime.decodeFlowed(text, node.delSp) : text;
36
+ }
37
+ /** Splits the message into its nodes, each with the raw bytes of its body. */
38
+ async function split(source) {
39
+ // ignoreEmbedded keeps a forwarded original as one part instead of
40
+ // descending into it, which is the whole reason this module exists.
41
+ const splitter = new Splitter({ ignoreEmbedded: true });
42
+ const nodes = [];
43
+ let current;
44
+ const done = (async () => {
45
+ for await (const chunk of splitter) {
46
+ if (chunk.type === 'node') {
47
+ current = { node: chunk, body: [] };
48
+ nodes.push(current);
49
+ }
50
+ else if (chunk.type === 'body' && current && chunk.value) {
51
+ current.body.push(Buffer.from(chunk.value));
52
+ }
53
+ }
54
+ })();
55
+ splitter.end(source);
56
+ await done;
57
+ return nodes;
58
+ }
59
+ /** Reads a stored message into its body and the files it carries. */
60
+ export async function readParts(source) {
61
+ const parts = { files: [] };
62
+ for (const { node, body } of await split(source)) {
63
+ // A multipart node is only a container; its children follow as nodes.
64
+ if (node.multipart)
65
+ continue;
66
+ const contentType = (node.contentType || 'text/plain').toLowerCase();
67
+ const decoded = await through(node.getDecoder(), body);
68
+ const isBody = node.disposition !== 'attachment' &&
69
+ !node.filename &&
70
+ (contentType === 'text/plain' || contentType === 'text/html');
71
+ if (isBody && contentType === 'text/html' && parts.html === undefined) {
72
+ parts.html = await asText(node, decoded);
73
+ continue;
74
+ }
75
+ if (isBody && contentType === 'text/plain' && parts.text === undefined) {
76
+ parts.text = await asText(node, decoded);
77
+ continue;
78
+ }
79
+ const filename = node.filename || `part-${parts.files.length + 1}`;
80
+ // Proton attaches its own key to whatever it sends, so a key carried over
81
+ // from a stored draft would go out twice.
82
+ if (isProtonPublicKey(contentType, filename))
83
+ continue;
84
+ const id = node.headers ? node.headers.getFirst('content-id').trim() : '';
85
+ const file = { filename, contentType, content: decoded };
86
+ if (id)
87
+ file.contentId = id.replace(/^<|>$/g, '');
88
+ parts.files.push(file);
89
+ }
90
+ return parts;
91
+ }
92
+ //# sourceMappingURL=parts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parts.js","sourceRoot":"","sources":["../../src/mime/parts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAE7C,OAAO,OAAO,MAAM,SAAS,CAAA;AAE7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAoB9C,+DAA+D;AAC/D,KAAK,UAAU,OAAO,CAAC,MAAiB,EAAE,MAAgB;IACxD,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QACvB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAkB;YAAE,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC,CAAA;IACtF,CAAC,CAAC,EAAE,CAAA;IACJ,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC/C,MAAM,CAAC,GAAG,EAAE,CAAA;IACZ,MAAM,IAAI,CAAA;IACV,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;AAC3B,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAc,EAAE,OAAe;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CACnG,MAAM,CACP,CAAA;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACpE,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,KAAK,CAAC,MAAc;IACjC,mEAAmE;IACnE,oEAAoE;IACpE,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAA;IACvD,MAAM,KAAK,GAA8C,EAAE,CAAA;IAC3D,IAAI,OAAuD,CAAA;IAE3D,MAAM,IAAI,GAAG,CAAC,KAAK,IAAI,EAAE;QACvB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAmD,EAAE,CAAC;YAC9E,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBAC1B,OAAO,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;gBACnC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACrB,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC3D,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,EAAE,CAAA;IACJ,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACpB,MAAM,IAAI,CAAA;IACV,OAAO,KAAK,CAAA;AACd,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc;IAC5C,MAAM,KAAK,GAAgB,EAAE,KAAK,EAAE,EAAE,EAAE,CAAA;IAExC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;QACjD,sEAAsE;QACtE,IAAI,IAAI,CAAC,SAAS;YAAE,SAAQ;QAE5B,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,YAAY,CAAC,CAAC,WAAW,EAAE,CAAA;QACpE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,UAAU,EAAe,EAAE,IAAI,CAAC,CAAA;QACnE,MAAM,MAAM,GACV,IAAI,CAAC,WAAW,KAAK,YAAY;YACjC,CAAC,IAAI,CAAC,QAAQ;YACd,CAAC,WAAW,KAAK,YAAY,IAAI,WAAW,KAAK,WAAW,CAAC,CAAA;QAE/D,IAAI,MAAM,IAAI,WAAW,KAAK,WAAW,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACtE,KAAK,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACxC,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,IAAI,WAAW,KAAK,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACvE,KAAK,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;YACxC,SAAQ;QACV,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAA;QAClE,0EAA0E;QAC1E,0CAA0C;QAC1C,IAAI,iBAAiB,CAAC,WAAW,EAAE,QAAQ,CAAC;YAAE,SAAQ;QAEtD,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACzE,MAAM,IAAI,GAAgB,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,CAAA;QACrE,IAAI,EAAE;YAAE,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;QACjD,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxB,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC"}