fix: refuse an unsupported method with EIP-1193 code 4200 (closes #279)
handleRpc() answered a method it does not implement with "Unsupported method: <method>" and no code, so a site probing for an optional method could not tell "not implemented" from "the call failed" and fall back. It now carries code 4200, which EIP-1193 defines for this case; the message is unchanged. The provider already passes any code through to the page. The new test hands the real background's reply to the provider and checks the page sees 4200. Model: opus-5-5
This commit is contained in:
@@ -54,6 +54,7 @@ class StubCustomEvent extends StubEvent {
|
||||
// through whatever arrived — but the cases below are the real ones.
|
||||
const REJECTED = 4001; // user rejected the request
|
||||
const UNAUTHORIZED = 4100; // site not connected / wrong address
|
||||
const UNSUPPORTED_METHOD = 4200; // a method the wallet does not implement
|
||||
const UNRECOGNIZED_CHAIN = 4902; // switch/add to an unsupported chain
|
||||
|
||||
// A stub window with the four things inpage.js touches: message listeners,
|
||||
@@ -115,6 +116,41 @@ async function rejectionFrom(start, response) {
|
||||
return outcome.error;
|
||||
}
|
||||
|
||||
// The reply the real background worker (src/background/index.js) sends for
|
||||
// `method`, loaded against just enough of the extension API to receive one
|
||||
// RPC message. Same shape as tests/coldWorkerChainId.test.js.
|
||||
function backgroundReply(method) {
|
||||
jest.resetModules();
|
||||
jest.doMock("../src/shared/alarms", () => ({
|
||||
BALANCE_REFRESH_ALARM: "balance",
|
||||
BALANCE_REFRESH_PERIOD_MINUTES: 1,
|
||||
ensureRecurringAlarms: async () => {},
|
||||
registerAlarmHandlers: () => {},
|
||||
}));
|
||||
|
||||
let messageListener = null;
|
||||
global.chrome = {
|
||||
runtime: {
|
||||
onMessage: {
|
||||
addListener: (fn) => {
|
||||
messageListener = fn;
|
||||
},
|
||||
},
|
||||
onConnect: { addListener: () => {} },
|
||||
},
|
||||
};
|
||||
|
||||
require("../src/background/index");
|
||||
|
||||
return new Promise((resolve) => {
|
||||
messageListener(
|
||||
{ type: "AUTISTMASK_RPC", method, params: [] },
|
||||
{ origin: "https://dapp.example" },
|
||||
resolve,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
describe("an EIP-1193 code reaches the page", () => {
|
||||
test("a user rejection arrives as code 4001", async () => {
|
||||
const err = await rejectionFrom(
|
||||
@@ -203,6 +239,26 @@ describe("an EIP-1193 code reaches the page", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// The reply here is the background's own, not one written in this file: it
|
||||
// used to carry no code for a method the wallet does not implement
|
||||
// (https://git.eeqj.de/sneak/AutistMask/issues/279), so a site probing for an
|
||||
// optional method could not tell "not implemented" from "the call failed".
|
||||
describe("a method the wallet does not implement", () => {
|
||||
afterEach(() => {
|
||||
delete global.chrome;
|
||||
});
|
||||
|
||||
test("reaches the page as code 4200", async () => {
|
||||
const method = "wallet_noSuchMethod";
|
||||
const err = await rejectionFrom(
|
||||
(p) => p.request({ method }),
|
||||
await backgroundReply(method),
|
||||
);
|
||||
expect(err.code).toBe(UNSUPPORTED_METHOD);
|
||||
expect(err.message).toBe("Unsupported method: " + method);
|
||||
});
|
||||
});
|
||||
|
||||
describe("the message is untouched", () => {
|
||||
test("a coded error keeps the message byte for byte", async () => {
|
||||
const message =
|
||||
|
||||
Reference in New Issue
Block a user