@bobfrankston/rmfmail 1.2.270 → 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.
- package/client/android-bootstrap.bundle.js +28 -2
- package/client/android-bootstrap.bundle.js.map +2 -2
- package/client/app.bundle.js +125 -10
- package/client/app.bundle.js.map +4 -4
- package/client/app.js +19 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +20 -0
- package/client/components/message-list.js +9 -1
- package/client/components/message-list.js.map +1 -1
- package/client/components/message-list.ts +9 -1
- package/client/components/message-viewer.js +40 -2
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +37 -2
- package/client/compose/compose.bundle.js +4 -0
- package/client/compose/compose.bundle.js.map +2 -2
- package/client/lib/api-client.js +6 -0
- package/client/lib/api-client.js.map +1 -1
- package/client/lib/api-client.ts +6 -0
- package/client/lib/approved-senders.js +66 -0
- package/client/lib/approved-senders.js.map +1 -0
- package/client/lib/approved-senders.ts +63 -0
- package/client/lib/mailxapi.js +3 -0
- package/client/package.json +1 -1
- package/package.json +5 -5
- package/packages/mailx-imap/package-lock.json +2 -2
- package/packages/mailx-imap/package.json +1 -1
- package/packages/mailx-service/index.d.ts +15 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +18 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +19 -0
- package/packages/mailx-service/jsonrpc.js +2 -0
- package/packages/mailx-service/jsonrpc.js.map +1 -1
- package/packages/mailx-service/jsonrpc.ts +2 -0
- package/packages/mailx-service/package.json +1 -1
- package/packages/mailx-settings/package.json +1 -1
- package/packages/mailx-store/package.json +1 -1
- package/packages/mailx-store-web/android-bootstrap.js +1 -0
- package/packages/mailx-store-web/android-bootstrap.js.map +1 -1
- package/packages/mailx-store-web/android-bootstrap.ts +1 -0
- package/packages/mailx-store-web/package.json +1 -1
- package/packages/mailx-store-web/web-service.d.ts +11 -0
- package/packages/mailx-store-web/web-service.d.ts.map +1 -1
- package/packages/mailx-store-web/web-service.js +14 -0
- package/packages/mailx-store-web/web-service.js.map +1 -1
- package/packages/mailx-store-web/web-service.ts +15 -0
- package/packages/mailx-types/index.d.ts.map +1 -1
- package/packages/mailx-types/index.js +25 -2
- package/packages/mailx-types/index.js.map +1 -1
- package/packages/mailx-types/index.ts +21 -1
- package/packages/mailx-types/package.json +1 -1
- /package/packages/mailx-imap/{node_modules.npmglobalize-stash-18100 → node_modules.npmglobalize-stash-31304}/.package-lock.json +0 -0
package/client/app.bundle.js
CHANGED
|
@@ -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"() {
|
|
@@ -1382,9 +1441,20 @@ function displayNameClaimsOtherAddress(name, address) {
|
|
|
1382
1441
|
const m = n.match(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g);
|
|
1383
1442
|
if (!m)
|
|
1384
1443
|
return null;
|
|
1444
|
+
const realDomain = real.split("@").pop() || "";
|
|
1385
1445
|
for (const claimed of m) {
|
|
1386
|
-
if (claimed.toLowerCase()
|
|
1387
|
-
|
|
1446
|
+
if (claimed.toLowerCase() === real)
|
|
1447
|
+
continue;
|
|
1448
|
+
const claimedDomain = claimed.toLowerCase().split("@").pop() || "";
|
|
1449
|
+
if (claimedDomain && realDomain) {
|
|
1450
|
+
if (claimedDomain === realDomain)
|
|
1451
|
+
continue;
|
|
1452
|
+
if (claimedDomain.endsWith("." + realDomain))
|
|
1453
|
+
continue;
|
|
1454
|
+
if (realDomain.endsWith("." + claimedDomain))
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
return claimed;
|
|
1388
1458
|
}
|
|
1389
1459
|
return null;
|
|
1390
1460
|
}
|
|
@@ -2682,6 +2752,36 @@ async function showMessage(accountId, uid, folderId, specialUse, isRetry = false
|
|
|
2682
2752
|
items.push({ label: "", action: () => {
|
|
2683
2753
|
}, separator: true });
|
|
2684
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
|
+
}
|
|
2685
2785
|
if (omitted > 0) {
|
|
2686
2786
|
items.push({
|
|
2687
2787
|
label: `\u2026 ${omitted} more recipients \u2014 copy the whole list`,
|
|
@@ -3271,7 +3371,7 @@ ${escapeText(reputationBlind)}"` : ""}>${reputationText}</div>` : "") + `<div cl
|
|
|
3271
3371
|
}
|
|
3272
3372
|
function formatAddr(addr) {
|
|
3273
3373
|
const { text, claimed } = formatSender(addr);
|
|
3274
|
-
if (!claimed)
|
|
3374
|
+
if (!claimed || isSenderApproved(addr.address))
|
|
3275
3375
|
return text;
|
|
3276
3376
|
return `${text} \u2014 display name claims ${claimed}`;
|
|
3277
3377
|
}
|
|
@@ -4096,6 +4196,7 @@ var init_message_viewer = __esm({
|
|
|
4096
4196
|
"client/components/message-viewer.js"() {
|
|
4097
4197
|
"use strict";
|
|
4098
4198
|
init_api_client();
|
|
4199
|
+
init_approved_senders();
|
|
4099
4200
|
init_context_menu();
|
|
4100
4201
|
init_message_state();
|
|
4101
4202
|
init_message_list();
|
|
@@ -5519,6 +5620,7 @@ var init_message_list = __esm({
|
|
|
5519
5620
|
init_folder_picker();
|
|
5520
5621
|
init_fold_text();
|
|
5521
5622
|
init_mailx_types();
|
|
5623
|
+
init_approved_senders();
|
|
5522
5624
|
currentSpecialUse = "";
|
|
5523
5625
|
lastClickedRow = null;
|
|
5524
5626
|
loading = false;
|
|
@@ -5633,7 +5735,7 @@ var init_message_list = __esm({
|
|
|
5633
5735
|
from.textContent = msg.to.map((a) => a.name || a.address).join(", ");
|
|
5634
5736
|
} else {
|
|
5635
5737
|
const fromName2 = msg.from.name || msg.from.address;
|
|
5636
|
-
const fromClaim = displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
|
|
5738
|
+
const fromClaim = isSenderApproved(msg.from.address || "") ? null : displayNameClaimsOtherAddress(msg.from.name || "", msg.from.address || "");
|
|
5637
5739
|
from.textContent = fromClaim ? `${fromName2} \u2014 actually ${msg.from.address}` : fromName2;
|
|
5638
5740
|
if (fromClaim) {
|
|
5639
5741
|
from.classList.add("ml-from-spoofed");
|
|
@@ -9891,12 +9993,12 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
|
|
|
9891
9993
|
}
|
|
9892
9994
|
if (msg && (mode === "editAsNew" || mode === "forward") && Array.isArray(msg.attachments) && msg.attachments.length) {
|
|
9893
9995
|
const msgAccountId = current?.accountId || accountId;
|
|
9894
|
-
const
|
|
9996
|
+
const loaded2 = [];
|
|
9895
9997
|
for (const att of msg.attachments) {
|
|
9896
9998
|
try {
|
|
9897
9999
|
const data = await getAttachment(msgAccountId, msg.uid, att.id, msg.folderId);
|
|
9898
10000
|
if (data?.content) {
|
|
9899
|
-
|
|
10001
|
+
loaded2.push({
|
|
9900
10002
|
filename: data.filename || att.filename || "attachment",
|
|
9901
10003
|
mimeType: data.contentType || att.contentType || "application/octet-stream",
|
|
9902
10004
|
dataBase64: data.content
|
|
@@ -9906,7 +10008,7 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
|
|
|
9906
10008
|
console.error(`[compose] ${mode}: failed to load attachment ${att.id}: ${e?.message || e}`);
|
|
9907
10009
|
}
|
|
9908
10010
|
}
|
|
9909
|
-
if (
|
|
10011
|
+
if (loaded2.length) init.attachments = loaded2;
|
|
9910
10012
|
}
|
|
9911
10013
|
if (preferWindow && !frame) {
|
|
9912
10014
|
try {
|
|
@@ -12368,6 +12470,19 @@ function applyThreadFilter() {
|
|
|
12368
12470
|
console.error("pending mailto pickup failed:", e?.message || e);
|
|
12369
12471
|
}
|
|
12370
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
|
+
});
|
|
12371
12486
|
(async () => {
|
|
12372
12487
|
try {
|
|
12373
12488
|
const { consumePendingShare: consumePendingShare2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
@@ -13619,12 +13734,12 @@ document.addEventListener("mailx-popout-message", (async (e) => {
|
|
|
13619
13734
|
draftId: msg.mailxDraftId || ""
|
|
13620
13735
|
};
|
|
13621
13736
|
if (Array.isArray(msg.attachments) && msg.attachments.length) {
|
|
13622
|
-
const
|
|
13737
|
+
const loaded2 = [];
|
|
13623
13738
|
for (const att of msg.attachments) {
|
|
13624
13739
|
try {
|
|
13625
13740
|
const data = await getAttachment(accountId, msg.uid, att.id, msg.folderId);
|
|
13626
13741
|
if (data?.content) {
|
|
13627
|
-
|
|
13742
|
+
loaded2.push({
|
|
13628
13743
|
filename: data.filename || att.filename || "attachment",
|
|
13629
13744
|
mimeType: data.contentType || att.contentType || "application/octet-stream",
|
|
13630
13745
|
dataBase64: data.content
|
|
@@ -13634,7 +13749,7 @@ document.addEventListener("mailx-popout-message", (async (e) => {
|
|
|
13634
13749
|
console.error(`[compose] edit draft: failed to load attachment ${att.id} ("${att.filename}"): ${e2?.message || e2}`);
|
|
13635
13750
|
}
|
|
13636
13751
|
}
|
|
13637
|
-
if (
|
|
13752
|
+
if (loaded2.length) init.attachments = loaded2;
|
|
13638
13753
|
}
|
|
13639
13754
|
handOffComposeInit(showComposeOverlay(msg.subject ? `Edit: ${msg.subject}` : "Edit draft"), init);
|
|
13640
13755
|
return;
|