WizardConnect "Open in wallet" links that open a new window reach Aegis

Potidaea's "Open in wallet" is <a href="wiz://…" target="_blank"
rel="noopener noreferrer">, a shape many dapps use. A new-window wiz:// link
goes through the window-open handler, which credits a pairing to the page
only through the request's referrer, so it can tell the page's own link
from one in a frame. noreferrer strips the referrer, so the link was
dropped and the wallet never heard of it.

The inject preload, which runs in a tab's top document only, now hands a
trusted click on a wiz:// link straight to main, and main accepts it only
from the tab's main frame before routing it like any pairing link. Links
inside iframes still go the old way and are still refused without a
referrer.
This commit is contained in:
Local Dev 2026-10-22 19:14:57 +03:00
parent 2da64a5600
commit 727fa27ebd
2 changed files with 30 additions and 0 deletions

View file

@ -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);

10
main.js
View file

@ -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);