diff --git a/main.js b/main.js index 1b1b1b89..ecbe9833 100644 --- a/main.js +++ b/main.js @@ -5906,6 +5906,13 @@ function pumpJsDialog() { const i = jsDialogQueue.findIndex((q) => q.tabId == null || q.tabId === activeId); emitTabs(); if (i < 0) return; + // Nothing goes over a wallet approval or the unlock prompt. A dapp could + // ask for a signature and then alert(): its sheet covered the approval, + // and closing it handed focus back to the page while the approval's + // buttons were already armed, so a double-click on "OK" landed on + // "Approve". The dialog waits (its page is blocked anyway) until the + // approval or prompt is answered. + if (approvalCurrent || unlockCurrent) return; const next = jsDialogQueue.splice(i, 1)[0]; jsDialogCurrent = next; overlayReady(jsDialogPop).then(() => { @@ -5951,7 +5958,11 @@ function finishJsDialog(ok, value) { jsDialogCurrent = null; try { if (jsDialogPop) jsDialogPop.setVisible(false); } catch {} jsDialogReply(cur, ok, value); - try { const t = cur.tabId != null ? tabById(cur.tabId) : null; if (t && t.id === activeId) t.view.webContents.focus(); } catch {} + // Never hand focus to the page while an approval or the unlock prompt is + // up: keystrokes meant for the prompt would go to the page. + if (!approvalCurrent && !unlockCurrent) { + try { const t = cur.tabId != null ? tabById(cur.tabId) : null; if (t && t.id === activeId) t.view.webContents.focus(); } catch {} + } pumpJsDialog(); } // Theseus's own prompts — install this app / extension, remove, restart — @@ -6083,6 +6094,7 @@ ipcMain.handle("approval-pick", (e, reqId, action, checked, extra) => { result += "+" + cur.req.select.id + "=" + extra; } cur.resolve(result); + pumpJsDialog(); // a page dialog held back by the approval can show now pumpApproval(); return true; }); @@ -6893,6 +6905,7 @@ function finishUnlock(result) { try { unlockPop?.setVisible(false); } catch {} cur?.resolve(result); pumpUnlock(); // queued requests resolve at once if the vault is now open + pumpJsDialog(); } ipcMain.handle("unlock-submit", async (e, reqId, mode, value) => { if (!unlockPop || e.sender !== unlockPop.webContents) return { ok: false, error: "denied" };