diff --git a/addon-inject-preload.js b/addon-inject-preload.js index c049eb22..4f19b346 100644 --- a/addon-inject-preload.js +++ b/addon-inject-preload.js @@ -43,3 +43,23 @@ for (const inj of injections) { console.warn(`[theseus] add-on "${id}" page-inject failed:`, e?.message || e); } } + +// wiz:// links (WizardConnect pairing, "Open in wallet"). A same-tab click is +// caught by main on will-navigate; one that opens a new window +// (target="_blank") reaches main's window-open handler, which can tell the +// page's own link from a frame's only by the referrer, and rel="noreferrer", +// common on dapps, strips it. So those clicks were dropped and the wallet +// never saw them. A click the user really made on such a link in this, the +// top document, goes straight to main instead; main checks it came from the +// tab's main frame and routes it like any other pairing link. +document.addEventListener("click", (e) => { + if (!e.isTrusted || e.button !== 0) return; + // composedPath reaches into shadow roots, where web-component buttons live. + const a = (typeof e.composedPath === "function" ? e.composedPath() : [e.target]) + .find((n) => n && n.tagName === "A" && n.hasAttribute && n.hasAttribute("href")); + if (!a) return; + const href = String(a.getAttribute("href") || "").trim(); + if (!/^wiz:/i.test(href) || href.length > 4096) return; + e.preventDefault(); + ipcRenderer.send("wiz-link", href); +}, true); diff --git a/main.js b/main.js index 411777b9..95fcad4e 100644 --- a/main.js +++ b/main.js @@ -7368,6 +7368,16 @@ function routeWizUri(uri, pageUrl, tabId) { send(); return true; } +// A wiz:// link the user clicked in a page's top document, reported by +// addon-inject-preload.js. It covers links that open a new window with +// rel="noreferrer", which the window-open handler cannot credit to the page. +// Only a tab's main frame may report one: the preload runs nowhere else, and +// a frame's report would otherwise be credited to the tab's top origin. +ipcMain.on("wiz-link", (e, uri) => { + const tab = tabForSender(e.sender); + if (!tab || tab.settings || tab.addonId || e.senderFrame !== e.sender.mainFrame) return; + routeWizUri(String(uri || "").slice(0, 4096), e.sender.getURL(), tab.id); +}); ipcMain.handle("addon-page-msg", async (e, addonId, msg, payload) => { const tab = tabForSender(e.sender);