@bobfrankston/rmfmail 1.2.3 → 1.2.4
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/app.bundle.js +18 -12
- package/client/app.bundle.js.map +2 -2
- package/client/app.js +14 -12
- package/client/app.js.map +1 -1
- package/client/app.ts +11 -12
- package/client/components/message-viewer.js +9 -2
- package/client/components/message-viewer.js.map +1 -1
- package/client/components/message-viewer.ts +3 -2
- package/client/lib/mailxapi.js +23 -2
- package/package.json +3 -3
- package/packages/mailx-service/index.d.ts +16 -0
- package/packages/mailx-service/index.d.ts.map +1 -1
- package/packages/mailx-service/index.js +45 -0
- package/packages/mailx-service/index.js.map +1 -1
- package/packages/mailx-service/index.ts +39 -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
|
@@ -2844,6 +2844,51 @@ export class MailxService {
|
|
|
2844
2844
|
}
|
|
2845
2845
|
return { ok: true, path: target };
|
|
2846
2846
|
}
|
|
2847
|
+
/** Open an http/https/mailto URL in the OS default browser/handler from the
|
|
2848
|
+
* Node process. The UI used to rely on `window.open(url, "_blank")`, but
|
|
2849
|
+
* inside msger's WebView2 that opens a local in-app window (or no-ops)
|
|
2850
|
+
* rather than the system browser — so clicking a link in a message, or an
|
|
2851
|
+
* unsubscribe "click here", "stayed local" (Bob 2026-06-13, "old bug
|
|
2852
|
+
* back"). `mailxapi.openExternal` now routes here.
|
|
2853
|
+
*
|
|
2854
|
+
* Security: the URL comes from untrusted email. We (1) parse it and allow
|
|
2855
|
+
* ONLY http/https/mailto — no file:, javascript:, data:, etc. — and (2)
|
|
2856
|
+
* pass it as a single spawn ARG with no shell, and on Windows use rundll32
|
|
2857
|
+
* (not `cmd /c start`, which re-parses `&`/`^` in query strings and is
|
|
2858
|
+
* injection-prone). Same cross-platform spawn pattern as openAttachment. */
|
|
2859
|
+
async openExternal(url) {
|
|
2860
|
+
let u;
|
|
2861
|
+
try {
|
|
2862
|
+
u = new URL(String(url));
|
|
2863
|
+
}
|
|
2864
|
+
catch {
|
|
2865
|
+
return { ok: false, reason: "unparseable URL" };
|
|
2866
|
+
}
|
|
2867
|
+
if (!["http:", "https:", "mailto:"].includes(u.protocol)) {
|
|
2868
|
+
console.error(` [openExternal] refused non-web scheme: ${u.protocol}`);
|
|
2869
|
+
return { ok: false, reason: `unsupported scheme ${u.protocol}` };
|
|
2870
|
+
}
|
|
2871
|
+
const target = u.href;
|
|
2872
|
+
try {
|
|
2873
|
+
const { spawn } = await import("node:child_process");
|
|
2874
|
+
if (process.platform === "win32") {
|
|
2875
|
+
// rundll32 receives the URL as a direct argv — no cmd, so query
|
|
2876
|
+
// strings with & can't break out into a second command.
|
|
2877
|
+
spawn("rundll32", ["url.dll,FileProtocolHandler", target], { detached: true, stdio: "ignore", windowsHide: true }).unref();
|
|
2878
|
+
}
|
|
2879
|
+
else if (process.platform === "darwin") {
|
|
2880
|
+
spawn("open", [target], { detached: true, stdio: "ignore" }).unref();
|
|
2881
|
+
}
|
|
2882
|
+
else {
|
|
2883
|
+
spawn("xdg-open", [target], { detached: true, stdio: "ignore" }).unref();
|
|
2884
|
+
}
|
|
2885
|
+
return { ok: true };
|
|
2886
|
+
}
|
|
2887
|
+
catch (e) {
|
|
2888
|
+
console.error(` [openExternal] spawn failed: ${e?.message || e}`);
|
|
2889
|
+
return { ok: false, reason: e?.message || String(e) };
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2847
2892
|
// ── Drafts ──
|
|
2848
2893
|
async saveDraft(accountId, subject, bodyHtml, bodyText, to, cc, previousDraftUid, draftId) {
|
|
2849
2894
|
// Local-first: commit the draft to the local filesystem synchronously
|