Theseus: page dialogs wait while a wallet approval or the unlock prompt is up

A dapp could request a signature and then call alert(): the page's
sheet was raised over the approval, and closing it focused the page
again while the approval's buttons were already armed, so a
double-click on the sheet's OK landed on Approve. Page dialogs and
Theseus's own sheets are now held until the approval or unlock prompt
is answered, and nothing hands focus to the page while one is open.
This commit is contained in:
Local Dev 2026-10-04 04:21:58 +02:00
parent db1acc1417
commit f214abaf1b

13
main.js
View file

@ -5906,6 +5906,13 @@ function pumpJsDialog() {
const i = jsDialogQueue.findIndex((q) => q.tabId == null || q.tabId === activeId); const i = jsDialogQueue.findIndex((q) => q.tabId == null || q.tabId === activeId);
emitTabs(); emitTabs();
if (i < 0) return; 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]; const next = jsDialogQueue.splice(i, 1)[0];
jsDialogCurrent = next; jsDialogCurrent = next;
overlayReady(jsDialogPop).then(() => { overlayReady(jsDialogPop).then(() => {
@ -5951,7 +5958,11 @@ function finishJsDialog(ok, value) {
jsDialogCurrent = null; jsDialogCurrent = null;
try { if (jsDialogPop) jsDialogPop.setVisible(false); } catch {} try { if (jsDialogPop) jsDialogPop.setVisible(false); } catch {}
jsDialogReply(cur, ok, value); jsDialogReply(cur, ok, value);
// 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 {} try { const t = cur.tabId != null ? tabById(cur.tabId) : null; if (t && t.id === activeId) t.view.webContents.focus(); } catch {}
}
pumpJsDialog(); pumpJsDialog();
} }
// Theseus's own prompts — install this app / extension, remove, restart — // 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; result += "+" + cur.req.select.id + "=" + extra;
} }
cur.resolve(result); cur.resolve(result);
pumpJsDialog(); // a page dialog held back by the approval can show now
pumpApproval(); pumpApproval();
return true; return true;
}); });
@ -6893,6 +6905,7 @@ function finishUnlock(result) {
try { unlockPop?.setVisible(false); } catch {} try { unlockPop?.setVisible(false); } catch {}
cur?.resolve(result); cur?.resolve(result);
pumpUnlock(); // queued requests resolve at once if the vault is now open pumpUnlock(); // queued requests resolve at once if the vault is now open
pumpJsDialog();
} }
ipcMain.handle("unlock-submit", async (e, reqId, mode, value) => { ipcMain.handle("unlock-submit", async (e, reqId, mode, value) => {
if (!unlockPop || e.sender !== unlockPop.webContents) return { ok: false, error: "denied" }; if (!unlockPop || e.sender !== unlockPop.webContents) return { ok: false, error: "denied" };