@bobfrankston/rmfmail 1.2.272 → 1.2.274

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 (43) hide show
  1. package/client/android-bootstrap.bundle.js +15 -0
  2. package/client/android-bootstrap.bundle.js.map +2 -2
  3. package/client/app.bundle.js +112 -8
  4. package/client/app.bundle.js.map +4 -4
  5. package/client/app.js +19 -0
  6. package/client/app.js.map +1 -1
  7. package/client/app.ts +20 -0
  8. package/client/components/message-list.js +9 -1
  9. package/client/components/message-list.js.map +1 -1
  10. package/client/components/message-list.ts +9 -1
  11. package/client/components/message-viewer.js +40 -2
  12. package/client/components/message-viewer.js.map +1 -1
  13. package/client/components/message-viewer.ts +37 -2
  14. package/client/compose/compose.bundle.js +4 -0
  15. package/client/compose/compose.bundle.js.map +2 -2
  16. package/client/lib/api-client.js +6 -0
  17. package/client/lib/api-client.js.map +1 -1
  18. package/client/lib/api-client.ts +6 -0
  19. package/client/lib/approved-senders.js +66 -0
  20. package/client/lib/approved-senders.js.map +1 -0
  21. package/client/lib/approved-senders.ts +63 -0
  22. package/client/lib/mailxapi.js +3 -0
  23. package/client/package.json +1 -1
  24. package/package.json +5 -5
  25. package/packages/mailx-service/index.d.ts +15 -0
  26. package/packages/mailx-service/index.d.ts.map +1 -1
  27. package/packages/mailx-service/index.js +18 -0
  28. package/packages/mailx-service/index.js.map +1 -1
  29. package/packages/mailx-service/index.ts +19 -0
  30. package/packages/mailx-service/jsonrpc.js +2 -0
  31. package/packages/mailx-service/jsonrpc.js.map +1 -1
  32. package/packages/mailx-service/jsonrpc.ts +2 -0
  33. package/packages/mailx-service/package.json +1 -1
  34. package/packages/mailx-store-web/android-bootstrap.js +1 -0
  35. package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
  36. package/packages/mailx-store-web/android-bootstrap.ts +1 -0
  37. package/packages/mailx-store-web/package.json +1 -1
  38. package/packages/mailx-store-web/web-service.d.ts +11 -0
  39. package/packages/mailx-store-web/web-service.d.ts.map +1 -1
  40. package/packages/mailx-store-web/web-service.js +14 -0
  41. package/packages/mailx-store-web/web-service.js.map +1 -1
  42. package/packages/mailx-store-web/web-service.ts +15 -0
  43. /package/packages/mailx-imap/{node_modules.npmglobalize-stash-72180 → node_modules.npmglobalize-stash-31304}/.package-lock.json +0 -0
@@ -56,6 +56,7 @@ __export(api_client_exports, {
56
56
  flagSenderOrDomain: () => flagSenderOrDomain,
57
57
  formatJsonc: () => formatJsonc,
58
58
  getAccounts: () => getAccounts,
59
+ getAllowlist: () => getAllowlist,
59
60
  getAttachment: () => getAttachment,
60
61
  getAutocompleteSettings: () => getAutocompleteSettings,
61
62
  getCalendarEvents: () => getCalendarEvents,
@@ -350,6 +351,9 @@ function addUserDictWords(words) {
350
351
  function removeUserDictWord(word) {
351
352
  return ipc().removeUserDictWord?.(word) ?? Promise.resolve([]);
352
353
  }
354
+ function getAllowlist() {
355
+ return ipc().getAllowlist?.() ?? Promise.resolve({ senders: [], domains: [], recipients: [], flaggedSenders: [], flaggedDomains: [] });
356
+ }
353
357
  function flagSenderOrDomain(type, value) {
354
358
  return ipc().flagSenderOrDomain?.(type, value) ?? Promise.resolve({ flagged: false });
355
359
  }
@@ -1310,6 +1314,61 @@ var init_message_state = __esm({
1310
1314
  }
1311
1315
  });
1312
1316
 
1317
+ // client/lib/approved-senders.js
1318
+ var approved_senders_exports = {};
1319
+ __export(approved_senders_exports, {
1320
+ approvedCounts: () => approvedCounts,
1321
+ isSenderApproved: () => isSenderApproved,
1322
+ noteApprovedLocally: () => noteApprovedLocally,
1323
+ refreshApprovedSenders: () => refreshApprovedSenders
1324
+ });
1325
+ async function refreshApprovedSenders() {
1326
+ try {
1327
+ const list = await getAllowlist();
1328
+ senders = new Set((list.senders || []).map(norm));
1329
+ domains = new Set((list.domains || []).map(norm));
1330
+ loaded = true;
1331
+ } catch (e) {
1332
+ console.warn("[approved-senders] refresh failed:", e?.message || e);
1333
+ }
1334
+ }
1335
+ function isSenderApproved(address) {
1336
+ if (!loaded)
1337
+ return false;
1338
+ const a = norm(address);
1339
+ if (!a)
1340
+ return false;
1341
+ if (senders.has(a))
1342
+ return true;
1343
+ const d = domainOf(a);
1344
+ return !!d && domains.has(d);
1345
+ }
1346
+ function noteApprovedLocally(type, value) {
1347
+ const v = norm(value);
1348
+ if (!v)
1349
+ return;
1350
+ if (type === "sender")
1351
+ senders.add(v);
1352
+ else
1353
+ domains.add(v);
1354
+ loaded = true;
1355
+ }
1356
+ function approvedCounts() {
1357
+ return { senders: senders.size, domains: domains.size, loaded };
1358
+ }
1359
+ var senders, domains, loaded, norm, domainOf;
1360
+ var init_approved_senders = __esm({
1361
+ "client/lib/approved-senders.js"() {
1362
+ "use strict";
1363
+ init_api_client();
1364
+ senders = /* @__PURE__ */ new Set();
1365
+ domains = /* @__PURE__ */ new Set();
1366
+ loaded = false;
1367
+ norm = (s) => (s || "").trim().toLowerCase();
1368
+ domainOf = (addr) => norm(addr).split("@").pop() || "";
1369
+ }
1370
+ });
1371
+
1313
1372
  // packages/mailx-types/contact-rules.js
1314
1373
  var init_contact_rules = __esm({
1315
1374
  "packages/mailx-types/contact-rules.js"() {
@@ -2693,6 +2752,36 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
2693
2752
  items.push({ label: "", action: () => {
2694
2753
  }, separator: true });
2695
2754
  }
2755
+ if (el === fromEl && msg.from?.address) {
2756
+ const addr = String(msg.from.address);
2757
+ const dom = addr.split("@").pop() || "";
2758
+ const claimed = displayNameClaimsOtherAddress(String(msg.from.name || ""), addr);
2759
+ if (claimed && !isSenderApproved(addr)) {
2760
+ const approve = async (type, value) => {
2761
+ noteApprovedLocally(type, value);
2762
+ try {
2763
+ await allowRemoteContent(type, value);
2764
+ await refreshApprovedSenders();
2765
+ document.dispatchEvent(new CustomEvent("mailx-allowlist-changed"));
2766
+ const st = document.getElementById("status-sync");
2767
+ if (st)
2768
+ st.textContent = `Marked valid: ${value}`;
2769
+ } catch (e2) {
2770
+ const st = document.getElementById("status-sync");
2771
+ if (st) {
2772
+ st.textContent = `Couldn't save "${value}" to the allowlist \u2014 ${e2?.message || e2}`;
2773
+ st.style.color = "oklch(0.65 0.2 25)";
2774
+ }
2775
+ console.error("[allowlist] approve failed:", e2);
2776
+ }
2777
+ };
2778
+ items.push({ label: `\u2713 Mark ${addr} as a valid sender`, action: () => void approve("sender", addr) });
2779
+ if (dom)
2780
+ items.push({ label: `\u2713 Trust all senders at ${dom}`, action: () => void approve("domain", dom) });
2781
+ items.push({ label: "", action: () => {
2782
+ }, separator: true });
2783
+ }
2784
+ }
2696
2785
  if (omitted > 0) {
2697
2786
  items.push({
2698
2787
  label: `\u2026 ${omitted} more recipients \u2014 copy the whole list`,
@@ -3282,7 +3371,7 @@ ${escapeText(reputationBlind)}"` : ""}>${reputationText}</div>` : "") + `<div cl
3282
3371
  }
3283
3372
  function formatAddr(addr) {
3284
3373
  const { text, claimed } = formatSender(addr);
3285
- if (!claimed)
3374
+ if (!claimed || isSenderApproved(addr.address))
3286
3375
  return text;
3287
3376
  return `${text} \u2014 display name claims ${claimed}`;
3288
3377
  }
@@ -4107,6 +4196,7 @@ var init_message_viewer = __esm({
4107
4196
  "client/components/message-viewer.js"() {
4108
4197
  "use strict";
4109
4198
  init_api_client();
4199
+ init_approved_senders();
4110
4200
  init_context_menu();
4111
4201
  init_message_state();
4112
4202
  init_message_list();
@@ -5530,6 +5620,7 @@ var init_message_list = __esm({
5530
5620
  init_folder_picker();
5531
5621
  init_fold_text();
5532
5622
  init_mailx_types();
5623
+ init_approved_senders();
5533
5624
  currentSpecialUse = "";
5534
5625
  lastClickedRow = null;
5535
5626
  loading = false;
@@ -5644,7 +5735,7 @@ var init_message_list = __esm({
5644
5735
  from.textContent = msg.to.map((a) => a.name || a.address).join(", ");
5645
5736
  } else {
5646
5737
  const fromName2 = msg.from.name || msg.from.address;
5647
- const fromClaim = displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
5738
+ const fromClaim = isSenderApproved(msg.from.address || "") ? null : displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
5648
5739
  from.textContent = fromClaim ? `${fromName2} \u2014 actually ${msg.from.address}` : fromName2;
5649
5740
  if (fromClaim) {
5650
5741
  from.classList.add("ml-from-spoofed");
@@ -9902,12 +9993,12 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
9902
9993
  }
9903
9994
  if (msg && (mode === "editAsNew" || mode === "forward") && Array.isArray(msg.attachments) && msg.attachments.length) {
9904
9995
  const msgAccountId = current?.accountId || accountId;
9905
- const loaded = [];
9996
+ const loaded2 = [];
9906
9997
  for (const att of msg.attachments) {
9907
9998
  try {
9908
9999
  const data = await getAttachment(msgAccountId, msg.uid, att.id, msg.folderId);
9909
10000
  if (data?.content) {
9910
- loaded.push({
10001
+ loaded2.push({
9911
10002
  filename: data.filename || att.filename || "attachment",
9912
10003
  mimeType: data.contentType || att.contentType || "application/octet-stream",
9913
10004
  dataBase64: data.content
@@ -9917,7 +10008,7 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
9917
10008
  console.error(`[compose] ${mode}: failed to load attachment ${att.id}: ${e?.message || e}`);
9918
10009
  }
9919
10010
  }
9920
- if (loaded.length) init.attachments = loaded;
10011
+ if (loaded2.length) init.attachments = loaded2;
9921
10012
  }
9922
10013
  if (preferWindow && !frame) {
9923
10014
  try {
@@ -12379,6 +12470,19 @@ function applyThreadFilter() {
12379
12470
  console.error("pending mailto pickup failed:", e?.message || e);
12380
12471
  }
12381
12472
  })();
12473
+ (async () => {
12474
+ try {
12475
+ const { refreshApprovedSenders: refreshApprovedSenders2 } = await Promise.resolve().then(() => (init_approved_senders(), approved_senders_exports));
12476
+ await refreshApprovedSenders2();
12477
+ document.dispatchEvent(new CustomEvent("mailx-allowlist-changed"));
12478
+ } catch (e) {
12479
+ console.warn("approved-sender index load failed:", e?.message || e);
12480
+ }
12481
+ })();
12482
+ document.addEventListener("mailx-allowlist-changed", () => {
12483
+ void Promise.resolve().then(() => (init_message_list(), message_list_exports)).then((m) => m.reloadCurrentFolder?.()).catch(() => {
12484
+ });
12485
+ });
12382
12486
  (async () => {
12383
12487
  try {
12384
12488
  const { consumePendingShare: consumePendingShare2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
@@ -13630,12 +13734,12 @@ document.addEventListener("mailx-popout-message", (async (e) => {
13630
13734
  draftId: msg.mailxDraftId || ""
13631
13735
  };
13632
13736
  if (Array.isArray(msg.attachments) && msg.attachments.length) {
13633
- const loaded = [];
13737
+ const loaded2 = [];
13634
13738
  for (const att of msg.attachments) {
13635
13739
  try {
13636
13740
  const data = await getAttachment(accountId, msg.uid, att.id, msg.folderId);
13637
13741
  if (data?.content) {
13638
- loaded.push({
13742
+ loaded2.push({
13639
13743
  filename: data.filename || att.filename || "attachment",
13640
13744
  mimeType: data.contentType || att.contentType || "application/octet-stream",
13641
13745
  dataBase64: data.content
@@ -13645,7 +13749,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
13645
13749
  console.error(`[compose] edit draft: failed to load attachment ${att.id} ("${att.filename}"): ${e2?.message || e2}`);
13646
13750
  }
13647
13751
  }
13648
- if (loaded.length) init.attachments = loaded;
13752
+ if (loaded2.length) init.attachments = loaded2;
13649
13753
  }
13650
13754
  handOffComposeInit(showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft"), init);
13651
13755
  return;