proton-mail-bridge-client 2.3.1 → 2.3.2

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 (34) hide show
  1. package/dist/index.d.ts.map +1 -1
  2. package/dist/index.js +54 -11
  3. package/dist/index.js.map +1 -1
  4. package/dist/services/delivery-queue-service.d.ts +4 -1
  5. package/dist/services/delivery-queue-service.d.ts.map +1 -1
  6. package/dist/services/delivery-queue-service.js +18 -19
  7. package/dist/services/delivery-queue-service.js.map +1 -1
  8. package/dist/services/draft-store-service.d.ts.map +1 -1
  9. package/dist/services/draft-store-service.js +10 -21
  10. package/dist/services/draft-store-service.js.map +1 -1
  11. package/dist/services/local-index-service.d.ts.map +1 -1
  12. package/dist/services/local-index-service.js +46 -24
  13. package/dist/services/local-index-service.js.map +1 -1
  14. package/dist/services/simple-imap-service.d.ts +1 -0
  15. package/dist/services/simple-imap-service.d.ts.map +1 -1
  16. package/dist/services/simple-imap-service.js +25 -5
  17. package/dist/services/simple-imap-service.js.map +1 -1
  18. package/dist/services/smtp-service.d.ts.map +1 -1
  19. package/dist/services/smtp-service.js +9 -2
  20. package/dist/services/smtp-service.js.map +1 -1
  21. package/dist/services/snooze-service.d.ts.map +1 -1
  22. package/dist/services/snooze-service.js +3 -10
  23. package/dist/services/snooze-service.js.map +1 -1
  24. package/dist/services/template-service.d.ts.map +1 -1
  25. package/dist/services/template-service.js +3 -10
  26. package/dist/services/template-service.js.map +1 -1
  27. package/dist/utils/corrupt-store.d.ts +4 -0
  28. package/dist/utils/corrupt-store.d.ts.map +1 -0
  29. package/dist/utils/corrupt-store.js +29 -0
  30. package/dist/utils/corrupt-store.js.map +1 -0
  31. package/dist/utils/helpers.d.ts.map +1 -1
  32. package/dist/utils/helpers.js +59 -6
  33. package/dist/utils/helpers.js.map +1 -1
  34. package/package.json +3 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAYnE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAuD,MAAM,mCAAmC,CAAC;AAC3H,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAA2H,iBAAiB,EAA+B,MAAM,mCAAmC,CAAC;AAC5N,OAAO,EAAmC,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,KAAK,EAMV,mBAAmB,EACnB,cAAc,EACd,WAAW,EAIX,WAAW,EAIX,gBAAgB,EAChB,cAAc,EAGf,MAAM,kBAAkB,CAAC;AAqB1B,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAstDnF,eAAO,MAAM,eAAe,aA2C1B,CAAC;AAqCH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,CAAC,CAEtE;AAiGD,wBAAsB,SAAS,CAAC,CAAC,EAC/B,YAAY,EAAE,YAAY,EAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwBZ;AAmDD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKtG;AA+CD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK3G;AAKD,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAI1G;AASD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAa9E;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAS7F;AA8ID,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrD;AAKD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAS3D;AA6CD,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAW5E;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAe/E;AAWD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,EACjB,kBAAkB,GAAE,MAAM,EAAO,GAChC;IAAE,EAAE,EAAE,MAAM,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,EAAE,CAAA;CAAE,CA8BhC;AA6ED,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CA4CtE;AAcD,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYlE;AAsBD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAQ/F;AAED,wBAAgB,4BAA4B,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAK,EAAE,CAAC,KAUhF;AAQD,wBAAgB,4BAA4B,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,cAAc,CAAA;CAAE,EAAE,MAAM,EAAE,CAAC,KA8B5F;AA+JD,wBAAsB,4BAA4B,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8BrH;AAoKD,eAAO,MAAM,iCAAiC,QAAS,CAAC;AAExD,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,CAAC,EAAE,EACZ,WAAW,SAAoC,GAC9C;IAAE,OAAO,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAYnC;AAYD,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,IAAI,CAAC,iBAAiB,EAAE,gBAAgB,CAAC,EACtD,iBAAiB,EAAE,IAAI,CAAC,iBAAiB,EAAE,sBAAsB,CAAC,EAClE,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAgID,wBAAgB,4BAA4B,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAKjI;AA8PD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAEzE;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAOzE;AAED,UAAU,mBAAmB;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AASD,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,EAC9B,MAAM,EAAE,MAAM,EACd,kBAAkB,CAAC,EAAE,MAAM,GAC1B,mBAAmB,EAAE,CA8CvB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,mBAAmB,EAC3B,gBAAgB,EAAE,mBAAmB,EAAE,GACtC,mBAAmB,CAmBrB;AAWD,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,cAAc,EAC9B,QAAQ,EAAE,MAAM,EAAE,GACjB,GAAG,CAAC,MAAM,GAAG,SAAS,EAAE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAYvE;AAOD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,CAQ3G;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,mBAAmB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,EAAE,CAK/G;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,mBAAmB,CASpF;AAsQD,wBAAgB,kBAAkB,IAAI,gBAAgB,CAoGrD;AAED,wBAAgB,YAAY,CAC1B,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+kJP;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAuE1C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -905,7 +905,7 @@ const TOOLS = [
905
905
  },
906
906
  {
907
907
  name: "count_messages",
908
- description: "Count messages matching search criteria. Plain IMAP criteria are answered by the server without fetching messages; non-ASCII values (accented letters, ł, ß) and local-only filters (hasAttachment, senderDomain, label, threadId) are checked locally, and the result carries approximate: true when only the newest 500 candidates could be checked. Use to preview how many results a search would return before running it. Prefer folder_stats for a simple unread/total count on one folder without filters.",
908
+ description: "Count messages matching search criteria. Plain IMAP criteria are answered by the server without fetching messages; non-ASCII values (accented letters, ł, ß) and local-only filters (hasAttachment, senderDomain, threadId, attachmentName, mailboxRole) are checked locally, and the result carries approximate: true when only the newest 500 candidates could be checked. A label that names a folder (Proton: Labels/<name>) counts that folder, as search_emails does. Across several accounts the counts are summed and an account that fails (for example one without that folder) is listed in failedAccounts instead of failing the whole call. Use to preview how many results a search would return before running it. Prefer folder_stats for a simple unread/total count on one folder without filters.",
909
909
  annotations: { readOnlyHint: true },
910
910
  inputSchema: {
911
911
  type: "object",
@@ -2179,7 +2179,9 @@ export function formatQuoteDate(value) {
2179
2179
  // (a broken-image box) and copies its base64 into every reply, and a cid: image refers to a part
2180
2180
  // that is not attached here. Replace each with its alt text, or nothing.
2181
2181
  export function stripUnshippableImages(html) {
2182
- return html.replace(/<img\b[^>]*>/gi, (tag) => {
2182
+ // A tag is a run of non-quote characters and quoted strings, so a ">" inside alt="a>b" does not end
2183
+ // it and an unclosed "<img" stops at the next "<" instead of scanning to the end of the text.
2184
+ return html.replace(/<img\b(?:[^<>"']|"[^"]*"|'[^']*')*>/gi, (tag) => {
2183
2185
  const src = /\bsrc\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tag);
2184
2186
  const value = (src?.[1] ?? src?.[2] ?? src?.[3] ?? "").trim().toLowerCase();
2185
2187
  if (!value.startsWith("data:") && !value.startsWith("cid:"))
@@ -2189,6 +2191,13 @@ export function stripUnshippableImages(html) {
2189
2191
  return text ? `[${text}]` : "";
2190
2192
  });
2191
2193
  }
2194
+ // References for a reply: the original's own chain followed by the original's Message-ID (RFC 5322),
2195
+ // so mail clients that thread by References keep the whole conversation together.
2196
+ function replyReferences(detail) {
2197
+ const chain = [...(detail.references ?? []), detail.messageId].filter((id) => Boolean(id));
2198
+ const unique = [...new Set(chain)];
2199
+ return unique.length > 0 ? unique : undefined;
2200
+ }
2192
2201
  function buildReplyText(detail, body) {
2193
2202
  const originalText = detail.text || detail.preview || "";
2194
2203
  const fromText = formatAddressList(detail.from);
@@ -2636,7 +2645,7 @@ function parseResourceUri(uri) {
2636
2645
  // created here are owner-only (0700) and the file is 0600, existing files included.
2637
2646
  export async function writeAttachmentToDownloadDir(downloadDir, saveTo, data) {
2638
2647
  const { resolve: pathResolve, join: pathJoin, dirname, basename, sep } = await import("node:path");
2639
- const { realpathSync } = await import("node:fs");
2648
+ const { realpathSync, existsSync } = await import("node:fs");
2640
2649
  const { writeFile: wf, mkdir: mkd, chmod: chm } = await import("node:fs/promises");
2641
2650
  const absDir = pathResolve(downloadDir);
2642
2651
  const absTarget = pathJoin(absDir, saveTo);
@@ -2645,8 +2654,26 @@ export async function writeAttachmentToDownloadDir(downloadDir, saveTo, data) {
2645
2654
  if (!absTarget.startsWith(absDir + sep) && absTarget !== absDir) {
2646
2655
  throw new McpError(ErrorCode.InvalidParams, "saveTo path escapes the allowed directory.");
2647
2656
  }
2648
- await mkd(pathResolve(absTarget, ".."), { recursive: true, mode: 0o700 });
2657
+ // The allowed directory itself may be created. Then check, BEFORE creating anything below it, that the
2658
+ // deepest directory that already exists on the way to the target really is inside it: otherwise a
2659
+ // symlink in the allowed dir could make mkdir create new directories outside it before the final
2660
+ // containment check below refuses the save.
2661
+ await mkd(absDir, { recursive: true, mode: 0o700 });
2649
2662
  const realDir = realpathSync(absDir);
2663
+ let probe = pathResolve(absTarget, "..");
2664
+ while (!existsSync(probe))
2665
+ probe = dirname(probe);
2666
+ let realProbe;
2667
+ try {
2668
+ realProbe = realpathSync(probe);
2669
+ }
2670
+ catch {
2671
+ throw new McpError(ErrorCode.InvalidParams, "saveTo path escapes the allowed directory.");
2672
+ }
2673
+ if (!realProbe.startsWith(realDir + sep) && realProbe !== realDir) {
2674
+ throw new McpError(ErrorCode.InvalidParams, "saveTo path escapes the allowed directory.");
2675
+ }
2676
+ await mkd(pathResolve(absTarget, ".."), { recursive: true, mode: 0o700 });
2650
2677
  let realTarget;
2651
2678
  try {
2652
2679
  realTarget = realpathSync(absTarget);
@@ -4140,7 +4167,11 @@ export function createServer(config, options = {}) {
4140
4167
  // Signature goes right after the user's own reply text, before the
4141
4168
  // quoted original — not at the very end, after the quote.
4142
4169
  const signedReply = applySignature(body, htmlBody, normalizeBoolean(args.appendSignature, true), isHtml);
4143
- const replyBody = includeQuoteReply ? buildReplyText(detail, signedReply.body) : signedReply.body;
4170
+ // With isHtml the body is HTML source, so the quoted original (untrusted text) must be HTML-escaped
4171
+ // by the HTML builder, not appended as raw plain text.
4172
+ const replyBody = includeQuoteReply
4173
+ ? (isHtml ? buildReplyHtml(detail, signedReply.body) : buildReplyText(detail, signedReply.body))
4174
+ : signedReply.body;
4144
4175
  // A separate htmlBody (the markdown-rendered case) needs the SAME quoted
4145
4176
  // original merged in — see buildReplyHtml's comment for why this was
4146
4177
  // previously missing entirely from the html part.
@@ -4165,7 +4196,7 @@ export function createServer(config, options = {}) {
4165
4196
  from: fromReply,
4166
4197
  sanitizeHtml: sanitizeHtmlReply,
4167
4198
  inReplyTo: detail.messageId,
4168
- references: detail.messageId ? [detail.messageId] : undefined,
4199
+ references: replyReferences(detail),
4169
4200
  attachments,
4170
4201
  // Already applied above, before quote-wrapping.
4171
4202
  appendSignature: false,
@@ -4237,7 +4268,9 @@ export function createServer(config, options = {}) {
4237
4268
  // Signature goes right after the user's own reply text, before the
4238
4269
  // quoted original — not at the very end, after the quote.
4239
4270
  const signedReplyRa = applySignature(bodyRa, htmlBodyRa, normalizeBoolean(args.appendSignature, true), isHtmlRa);
4240
- const replyBodyRa = includeQuoteRa ? buildReplyText(detailRa, signedReplyRa.body) : signedReplyRa.body;
4271
+ const replyBodyRa = includeQuoteRa
4272
+ ? (isHtmlRa ? buildReplyHtml(detailRa, signedReplyRa.body) : buildReplyText(detailRa, signedReplyRa.body))
4273
+ : signedReplyRa.body;
4241
4274
  // Same fix as reply_to_email — see buildReplyHtml's comment.
4242
4275
  const replyHtmlBodyRa = includeQuoteRa && signedReplyRa.htmlBody !== undefined
4243
4276
  ? buildReplyHtml(detailRa, signedReplyRa.htmlBody)
@@ -4360,7 +4393,7 @@ export function createServer(config, options = {}) {
4360
4393
  cc,
4361
4394
  bcc,
4362
4395
  subject: prefixedSubject(detail.subject, "Fwd:"),
4363
- body: buildForwardText(detail, signedFwd.body),
4396
+ body: isHtml ? buildForwardHtml(detail, signedFwd.body) : buildForwardText(detail, signedFwd.body),
4364
4397
  isHtml,
4365
4398
  htmlBody: forwardHtmlBody,
4366
4399
  fromName: fromNameFwd,
@@ -4523,7 +4556,7 @@ export function createServer(config, options = {}) {
4523
4556
  // sender instead of the alias the caller asked for.
4524
4557
  from: optionalString(args, "from"),
4525
4558
  inReplyTo: detail.messageId,
4526
- references: detail.messageId ? [detail.messageId] : undefined,
4559
+ references: replyReferences(detail),
4527
4560
  attachments,
4528
4561
  sourceEmailId: detail.id,
4529
4562
  sourceMessageId: detail.messageId,
@@ -5422,14 +5455,24 @@ export function createServer(config, options = {}) {
5422
5455
  // Merge strategy: count in every account's mailbox and sum — folder is
5423
5456
  // reported from the request (all accounts are counted against the same
5424
5457
  // folder name), with a per-account breakdown alongside the total.
5425
- const perAccount = await Promise.all(accountManager.all().map(async (bundle) => ({
5458
+ // One account lacking the folder or label (or unreachable) must not fail the whole count, as in
5459
+ // search_emails: report it and return the rest. Every account failing still throws.
5460
+ const settled = await Promise.allSettled(accountManager.all().map(async (bundle) => ({
5426
5461
  slug: bundle.account.slug,
5427
5462
  ...(await bundle.imapService.countMessages(countInput)),
5428
5463
  })));
5464
+ const perAccount = settled.flatMap((entry) => (entry.status === "fulfilled" ? [entry.value] : []));
5465
+ if (perAccount.length === 0) {
5466
+ throw settled[0].reason;
5467
+ }
5468
+ const failedAccounts = settled.flatMap((entry, index) => entry.status === "rejected"
5469
+ ? [{ account: accountManager.all()[index].account.slug, error: entry.reason instanceof Error ? entry.reason.message : String(entry.reason) }]
5470
+ : []);
5429
5471
  return createTextResult({
5430
5472
  folder: countInput.folder ?? "INBOX",
5431
5473
  count: perAccount.reduce((sum, entry) => sum + entry.count, 0),
5432
5474
  ...(perAccount.some((entry) => entry.approximate) ? { approximate: true } : {}),
5475
+ ...(failedAccounts.length > 0 ? { failedAccounts } : {}),
5433
5476
  byAccount: perAccount,
5434
5477
  });
5435
5478
  }
@@ -7226,7 +7269,7 @@ export function createServer(config, options = {}) {
7226
7269
  // Same fix as create_reply_draft — see its comment.
7227
7270
  from: optionalString(args, "from"),
7228
7271
  inReplyTo: detail.messageId,
7229
- references: detail.messageId ? [detail.messageId] : undefined,
7272
+ references: replyReferences(detail),
7230
7273
  attachments,
7231
7274
  sourceEmailId: detail.id,
7232
7275
  sourceMessageId: detail.messageId,