fix: only the user switches the wallet's network (closes #408)
A connected site's wallet_switchEthereumChain request for the other supported network now opens a prompt in its own window, through the existing approval machinery, naming the site and both networks. The network, endpoints, balances and caches change, and chainChanged is sent, only when the user approves it; rejecting or closing the prompt answers 4001. One such prompt per site at a time; a request for the active network needs none. The approval window no longer shows the connection prompt while it waits for the approval's description, since both prompts answer on the same port. Model: opus-5-5
This commit is contained in:
@@ -14,6 +14,10 @@
|
||||
// itself: the handler has to do it. tests/chainSwitchGate.test.js mocks the
|
||||
// state module wholesale and tests/networkEndpoints.test.js always loads
|
||||
// first, so neither can see this.
|
||||
//
|
||||
// A site's switch happens only once the user approves it on a prompt
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/408), so every switch here is
|
||||
// approved the way the popup approves one.
|
||||
|
||||
const { networkById } = require("../src/shared/networks");
|
||||
const { makeStorageStub } = require("./support/storageStub");
|
||||
@@ -90,6 +94,9 @@ function loadColdWorker(networkId) {
|
||||
const storage = makeStorageStub({ autistmask: storedProfile(networkId) });
|
||||
|
||||
let messageListener = null;
|
||||
let connectListener = null;
|
||||
// The URL of every approval window opened; the approval id is in it.
|
||||
const opened = [];
|
||||
const toTabs = [];
|
||||
|
||||
global.chrome = {
|
||||
@@ -101,12 +108,19 @@ function loadColdWorker(networkId) {
|
||||
messageListener = fn;
|
||||
},
|
||||
},
|
||||
onConnect: { addListener: () => {} },
|
||||
onConnect: {
|
||||
addListener: (fn) => {
|
||||
connectListener = fn;
|
||||
},
|
||||
},
|
||||
lastError: null,
|
||||
},
|
||||
windows: {
|
||||
getLastFocused: (cb) => cb(null),
|
||||
create: (options, cb) => cb({ id: 1 }),
|
||||
create: (options, cb) => {
|
||||
opened.push(options.url);
|
||||
cb({ id: opened.length });
|
||||
},
|
||||
remove: (id, cb) => {
|
||||
if (cb) cb();
|
||||
},
|
||||
@@ -124,6 +138,32 @@ function loadColdWorker(networkId) {
|
||||
|
||||
require("../src/background/index");
|
||||
|
||||
// The user approves the prompt the request opened, as the popup does: a
|
||||
// decision on the port named for the approval, from the extension's own
|
||||
// page.
|
||||
function approvePrompt() {
|
||||
const id = new URL(opened[opened.length - 1]).searchParams.get(
|
||||
"approval",
|
||||
);
|
||||
let onDecision = null;
|
||||
const port = {
|
||||
name: "approval:" + id,
|
||||
sender: { url: "chrome-extension://autistmask/src/popup/" },
|
||||
onMessage: {
|
||||
addListener: (fn) => {
|
||||
onDecision = fn;
|
||||
},
|
||||
},
|
||||
onDisconnect: { addListener: () => {} },
|
||||
};
|
||||
connectListener(port);
|
||||
onDecision(
|
||||
{ type: "AUTISTMASK_APPROVAL_DECISION", approved: true },
|
||||
port,
|
||||
);
|
||||
}
|
||||
|
||||
// A connected site asks for `chainId`, and the user approves it.
|
||||
async function switchChain(chainId) {
|
||||
let result = null;
|
||||
messageListener(
|
||||
@@ -138,6 +178,8 @@ function loadColdWorker(networkId) {
|
||||
},
|
||||
);
|
||||
await settle();
|
||||
approvePrompt();
|
||||
await settle();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user