// Which site a page's request is attributed to. // // The background takes a request's origin from what the browser says sent the // message: sender.origin, or on Firefox before 126, which has no // sender.origin, the origin of sender.url — the frame that sent it. It used to // fall back to the tab's page and then to an origin the message itself // carried, so a request from a frame was credited to the site embedding it, // and a request the browser said nothing about was credited to whatever the // page wrote (https://git.eeqj.de/sneak/AutistMask/issues/407). // // Every sender here lacks sender.origin, as on old Firefox. The connection // check on eth_accounts is what shows which site a request was credited to. const { makeStorageStub } = require("./support/storageStub"); const ADDRESS = "0x66133E8ea0f5D1d612D2502a968757D1048c214a"; // The site the persisted state has connected, and one it has never heard of. const CONNECTED_ORIGIN = "https://dapp.example"; const STRANGER_ORIGIN = "https://stranger.example"; async function settle() { for (let i = 0; i < 50; i++) await Promise.resolve(); } afterEach(() => { delete global.chrome; }); function loadBackground() { jest.resetModules(); jest.doMock("../src/shared/balances", () => ({ getProvider: () => ({}), refreshBalances: jest.fn(async () => {}), })); jest.doMock("../src/shared/phishingDomains", () => ({ isPhishingDomain: () => false, })); jest.doMock("../src/shared/alarms", () => ({ BALANCE_REFRESH_ALARM: "balance", BALANCE_REFRESH_PERIOD_MINUTES: 1, ensureRecurringAlarms: jest.fn(async () => {}), registerAlarmHandlers: jest.fn(), })); const storage = makeStorageStub({ autistmask: { networkId: "mainnet", wallets: [ { name: "Wallet 1", type: "hd", addresses: [ { address: ADDRESS, balance: "0", tokenBalances: [] }, ], }, ], activeAddress: ADDRESS, allowedSites: { [ADDRESS]: [CONNECTED_ORIGIN] }, deniedSites: {}, }, }); let messageListener = null; global.chrome = { storage, runtime: { getURL: (path) => "chrome-extension://autistmask/" + path, onMessage: { addListener: (fn) => { messageListener = fn; }, }, onConnect: { addListener: () => {} }, lastError: null, }, windows: { onRemoved: { addListener: () => {} } }, action: { setPopup: () => {} }, }; require("../src/background/index"); // Ask for eth_accounts. `claimedOrigin` is an origin written into the // message, as the content script used to send. return async function accounts(sender, claimedOrigin) { let result = null; messageListener( { type: "AUTISTMASK_RPC", method: "eth_accounts", params: [], origin: claimedOrigin, }, sender, (r) => { result = r; }, ); await settle(); return result; }; } describe("a request is attributed to the frame that sent it", () => { test("a stranger's frame on a connected site gets no address", async () => { const accounts = loadBackground(); const result = await accounts({ url: STRANGER_ORIGIN + "/frame.html", tab: { url: CONNECTED_ORIGIN + "/" }, }); expect(result).toEqual({ result: [] }); }); test("a connected site's frame on a stranger's page gets the address", async () => { const accounts = loadBackground(); const result = await accounts({ url: CONNECTED_ORIGIN + "/frame.html", tab: { url: STRANGER_ORIGIN + "/" }, }); expect(result).toEqual({ result: [ADDRESS] }); }); }); describe("a request the browser does not say the sender of", () => { test("is refused, whatever the tab or the message says", async () => { const accounts = loadBackground(); const result = await accounts( { tab: { url: CONNECTED_ORIGIN + "/" } }, CONNECTED_ORIGIN, ); expect(result).toEqual({ error: { code: 4100, message: "The wallet could not tell which site sent this request.", }, }); }); });