feat(theseus+aegis): WizardConnect auto-detection — wiz:// links + page scan
Completes the three detection paths. The injected provider shipped in
0.8.8; these two needed host support, because nothing in the add-on API
could reach the active tab's content (captureTab is pixels, not DOM).
wiz:// links (main.js)
A click on a wiz:// anchor is intercepted in will-navigate and in the
window-open handler (target="_blank" lands there instead), and routed
to the wallet with the offering page's origin attached, so the
approval names the real site. The tab never navigates. This needs
nothing from the dapp beyond rendering the URI as a link, so it works
for third-party dapps that will never adopt a Silent Mode API.
scan-page capability (addons-host.js + main.js)
New capability backing api.scanActiveTabForUris({scheme, limit}).
Deliberately NOT a "read the page" API: the host runs the match and
returns only the URIs found, so an add-on holding this still cannot
see page text, markup or form values. It sits well below page-inject
on the trust ladder — it learns that a page offers a wiz:// code and
nothing else. Scheme is validated against [a-z][a-z0-9+.-]* and the
result count is capped.
The matcher also accepts WizardConnect's QR-alphanumeric spelling
(WIZ://%3FP%3D…), which is frequently the only form present when a
dapp renders its pairing code as a QR, and decodes it. Verified
against the SDK: decodeKeyExchangeURI accepts standard, QR-raw and
QR-decoded alike.
Regex sources are built host-side and passed as JSON rather than
assembled inside the injected string — hand-escaping backslashes and
quotes through two levels of literal was both wrong on the first
attempt and unreviewable.
Aegis
Declares scan-page, adds the wcScanPage handler and a "Scan page"
button next to Connect. A scan fills the URI field and stops there
rather than pairing outright: the user still chooses which wallet
signs and still presses Connect, because a scan that silently paired
would carry far more consequence than the button implies. Older hosts
without the capability get a clear "update Theseus" message instead of
a dead button.
This commit is contained in:
parent
85236a66da
commit
deab66fe0e
3 changed files with 54 additions and 4 deletions
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"id": "aegis",
|
||||
"name": "Aegis Wallet",
|
||||
"version": "0.8.9",
|
||||
"version": "0.9.0",
|
||||
"category": "plugin",
|
||||
"description": "Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) derived from your Theseus vault. Dapps get window.bitcoincash on .x sites; window.tronWeb / window.tronLink / window.ethereum / window.solana on any https page.",
|
||||
"author": "Silent Mode",
|
||||
"icon": "data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none'%3E%3Cpolygon points='16,2 28,9 28,23 16,30 4,23 4,9' fill='%230a0a0d' stroke='%23D6FF3D' stroke-width='1.6' stroke-linejoin='round'/%3E%3Ccircle cx='16' cy='16' r='4.5' fill='none' stroke='%23D6FF3D' stroke-width='1.4'/%3E%3Ccircle cx='16' cy='16' r='1.6' fill='%23D6FF3D'/%3E%3C/svg%3E",
|
||||
"main": "index.js",
|
||||
"updateURL": "https://navigate.st/bns/theseus.x/extensions/aegis/updates.json",
|
||||
"capabilities": ["sidebar-panel", "vault-derive", "page-inject", "approval-modal"],
|
||||
"capabilities": ["sidebar-panel", "vault-derive", "page-inject", "approval-modal", "scan-page"],
|
||||
"absorbs": ["bchwallet", "siawallet"],
|
||||
"page-inject": {
|
||||
"preload": "wallet-inject.js",
|
||||
|
|
|
|||
14
index.js
14
index.js
|
|
@ -1585,6 +1585,20 @@ function registerPanelMessages(api) {
|
|||
return fullState();
|
||||
});
|
||||
|
||||
// Scan the open dapp tab for a wiz:// pairing code, for dapps that render
|
||||
// one but haven't adopted window.wizardconnect. Strictly user-initiated —
|
||||
// it runs when someone presses "Scan page", never on a timer and never in
|
||||
// the background. The host does the matching and returns only the URIs, so
|
||||
// Aegis never receives page content.
|
||||
api.onMessage("wcScanPage", async (_p, m) => {
|
||||
fromPanel(m);
|
||||
if (typeof api.scanActiveTabForUris !== "function") {
|
||||
throw new Error("This Theseus build can't scan pages yet — update Theseus, or paste the wiz:// code manually.");
|
||||
}
|
||||
const { origin, uris } = await api.scanActiveTabForUris({ scheme: "wiz", limit: 10 });
|
||||
return { origin: origin || null, uris: Array.isArray(uris) ? uris : [] };
|
||||
});
|
||||
|
||||
// ---- WizardConnect from the page (0.8.8) --------------------------------
|
||||
//
|
||||
// WC was built for cross-device pairing: the dapp renders a QR, a phone
|
||||
|
|
|
|||
40
panel.js
40
panel.js
|
|
@ -1892,7 +1892,7 @@ function renderConnectPane(bchWallets) {
|
|||
</div>`).join("")
|
||||
: `<div class="hint" style="padding:6px 8px">No dapps paired yet.</div>`;
|
||||
return `<div style="padding:6px">
|
||||
<div class="hint" style="margin-bottom:8px">Dapps that support Aegis directly can hand the pairing over with one click — no copying. Otherwise paste a <span class="mono">wiz://</span> URI from the dapp's Connect dialog. Aegis signs every request after your approval.</div>
|
||||
<div class="hint" style="margin-bottom:8px">Dapps that support Aegis hand the pairing over with one click. Otherwise open the dapp's Connect dialog and press <b>Scan page</b>, or paste its <span class="mono">wiz://</span> code below. Aegis signs every request after your approval.</div>
|
||||
${blockedNote}
|
||||
<div class="field">
|
||||
<div class="lbl">Sign with</div>
|
||||
|
|
@ -1901,8 +1901,9 @@ function renderConnectPane(bchWallets) {
|
|||
<div class="field">
|
||||
<input type="text" id="pkConnectUri" spellcheck="false" placeholder="wiz://?p=…&s=…">
|
||||
</div>
|
||||
<div class="actions">
|
||||
<div class="actions" style="gap:6px">
|
||||
<button class="btn primary" id="pkConnectBtn">Connect</button>
|
||||
<button class="btn" id="pkConnectScanBtn" title="Look for a wiz:// pairing code on the dapp tab you have open">Scan page</button>
|
||||
</div>
|
||||
<div class="msg err" id="pkConnectMsg" hidden></div>
|
||||
<div class="lbl" style="margin-top:14px">Paired dapps</div>
|
||||
|
|
@ -1948,6 +1949,41 @@ function wireConnectPane() {
|
|||
fillPicker();
|
||||
} catch (e) { msg.textContent = cleanErr(e); msg.hidden = false; }
|
||||
});
|
||||
const scanBtn = document.getElementById("pkConnectScanBtn");
|
||||
if (scanBtn) scanBtn.addEventListener("click", async (e) => {
|
||||
e.stopPropagation();
|
||||
const msg = document.getElementById("pkConnectMsg"); msg.hidden = true;
|
||||
const field = document.getElementById("pkConnectUri");
|
||||
const prev = scanBtn.textContent;
|
||||
scanBtn.textContent = "Scanning…"; scanBtn.disabled = true;
|
||||
try {
|
||||
const res = await S.invoke("wcScanPage");
|
||||
const uris = res?.uris || [];
|
||||
if (!uris.length) {
|
||||
msg.textContent = res?.origin
|
||||
? `No wiz:// pairing code found on ${res.origin}. Open the dapp's Connect dialog first, then scan again.`
|
||||
: "No pairing code found on the open tab.";
|
||||
msg.hidden = false;
|
||||
return;
|
||||
}
|
||||
// Fill the field rather than pairing outright: the user still picks
|
||||
// which wallet signs, and still presses Connect. A scan that silently
|
||||
// paired would be a click with a much larger consequence than the
|
||||
// button implies.
|
||||
field.value = uris[0];
|
||||
msg.textContent = uris.length > 1
|
||||
? `Found ${uris.length} codes on ${res.origin || "the page"} — filled the first. Press Connect to pair.`
|
||||
: `Found a pairing code on ${res.origin || "the page"}. Press Connect to pair.`;
|
||||
msg.classList.remove("err");
|
||||
msg.hidden = false;
|
||||
} catch (err) {
|
||||
msg.textContent = cleanErr(err);
|
||||
msg.classList.add("err");
|
||||
msg.hidden = false;
|
||||
} finally {
|
||||
scanBtn.textContent = prev; scanBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
document.querySelectorAll("[data-wcpick]").forEach((b) => b.addEventListener("click", async () => {
|
||||
const [walletId, connId] = b.dataset.wcpick.split("|");
|
||||
try { state = await S.invoke("wcDisconnect", { walletId, connId }); fillPicker(); }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue