From 980fdda69497fb6cfadbdf215321f33686b247b3 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 26 Feb 2026 03:54:52 +0700 Subject: [PATCH] Scope site connection permissions per address allowedSites and deniedSites are now objects keyed by address instead of flat arrays, so approving a site for one address no longer grants access for all addresses. Old flat-array data is discarded on load. Settings view collects unique hostnames across all addresses and deleting removes the site from every address. --- src/background/index.js | 41 ++++++++++++++++++++++++++----------- src/popup/views/settings.js | 18 ++++++++++------ src/shared/state.js | 14 +++++++++---- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/background/index.js b/src/background/index.js index 3b3a7da..77d0958 100644 --- a/src/background/index.js +++ b/src/background/index.js @@ -19,7 +19,7 @@ const windowsApi = typeof browser !== "undefined" ? browser.windows : chrome.windows; const tabsApi = typeof browser !== "undefined" ? browser.tabs : chrome.tabs; -// Connected sites (in-memory, non-persisted): { origin: true } +// Connected sites (in-memory, non-persisted): { "origin:address": true } const connectedSites = {}; // Pending approval requests: { id: { origin, hostname, resolve } } @@ -33,8 +33,8 @@ async function getState() { wallets: [], rpcUrl: DEFAULT_RPC_URL, activeAddress: null, - allowedSites: [], - deniedSites: [], + allowedSites: {}, + deniedSites: {}, } ); } @@ -114,9 +114,11 @@ async function handleConnectionRequest(origin) { } const hostname = extractHostname(origin); + const allowed = s.allowedSites[activeAddress] || []; + const denied = s.deniedSites[activeAddress] || []; // Check denied list - if (s.deniedSites.includes(hostname)) { + if (denied.includes(hostname)) { return { error: { code: 4001, @@ -126,7 +128,10 @@ async function handleConnectionRequest(origin) { } // Check allowed list or in-memory connected - if (s.allowedSites.includes(hostname) || connectedSites[origin]) { + if ( + allowed.includes(hostname) || + connectedSites[origin + ":" + activeAddress] + ) { return { result: [activeAddress] }; } @@ -137,19 +142,25 @@ async function handleConnectionRequest(origin) { if (decision.remember) { // Reload state to get latest, add to allowed, persist await loadState(); - if (!state.allowedSites.includes(hostname)) { - state.allowedSites.push(hostname); + if (!state.allowedSites[activeAddress]) { + state.allowedSites[activeAddress] = []; + } + if (!state.allowedSites[activeAddress].includes(hostname)) { + state.allowedSites[activeAddress].push(hostname); } await saveState(); } else { - connectedSites[origin] = true; + connectedSites[origin + ":" + activeAddress] = true; } return { result: [activeAddress] }; } else { if (decision.remember) { await loadState(); - if (!state.deniedSites.includes(hostname)) { - state.deniedSites.push(hostname); + if (!state.deniedSites[activeAddress]) { + state.deniedSites[activeAddress] = []; + } + if (!state.deniedSites[activeAddress].includes(hostname)) { + state.deniedSites[activeAddress].push(hostname); } await saveState(); } @@ -198,7 +209,11 @@ async function handleRpc(method, params, origin) { const activeAddress = await getActiveAddress(); if (!activeAddress) return { result: [] }; const hostname = extractHostname(origin); - if (s.allowedSites.includes(hostname) || connectedSites[origin]) { + const allowed = s.allowedSites[activeAddress] || []; + if ( + allowed.includes(hostname) || + connectedSites[origin + ":" + activeAddress] + ) { return { result: [activeAddress] }; } return { result: [] }; @@ -256,8 +271,10 @@ async function handleRpc(method, params, origin) { const s = await getState(); const activeAddress = await getActiveAddress(); const hostname = extractHostname(origin); + const allowed = s.allowedSites[activeAddress] || []; const isConnected = - s.allowedSites.includes(hostname) || connectedSites[origin]; + allowed.includes(hostname) || + connectedSites[origin + ":" + activeAddress]; if (!isConnected || !activeAddress) { return { result: [] }; } diff --git a/src/popup/views/settings.js b/src/popup/views/settings.js index db9e345..11fcb45 100644 --- a/src/popup/views/settings.js +++ b/src/popup/views/settings.js @@ -6,25 +6,31 @@ const { log } = require("../../shared/log"); const runtime = typeof browser !== "undefined" ? browser.runtime : chrome.runtime; -function renderSiteList(containerId, list, stateKey) { +function renderSiteList(containerId, siteMap, stateKey) { const container = $(containerId); - if (list.length === 0) { + const hostnames = [...new Set(Object.values(siteMap).flat())]; + if (hostnames.length === 0) { container.innerHTML = '

None

'; return; } let html = ""; - list.forEach((hostname, i) => { + hostnames.forEach((hostname) => { html += `
`; html += `${hostname}`; - html += ``; + html += ``; html += `
`; }); container.innerHTML = html; container.querySelectorAll(".btn-remove-site").forEach((btn) => { btn.addEventListener("click", async () => { const key = btn.dataset.key; - const idx = parseInt(btn.dataset.index, 10); - state[key].splice(idx, 1); + const host = btn.dataset.hostname; + for (const addr of Object.keys(state[key])) { + state[key][addr] = state[key][addr].filter((h) => h !== host); + if (state[key][addr].length === 0) { + delete state[key][addr]; + } + } await saveState(); runtime.sendMessage({ type: "AUTISTMASK_REMOVE_SITE" }); renderSiteList(containerId, state[key], key); diff --git a/src/shared/state.js b/src/shared/state.js index 363fb75..c3f6e4a 100644 --- a/src/shared/state.js +++ b/src/shared/state.js @@ -15,8 +15,8 @@ const DEFAULT_STATE = { blockscoutUrl: DEFAULT_BLOCKSCOUT_URL, lastBalanceRefresh: 0, activeAddress: null, - allowedSites: [], - deniedSites: [], + allowedSites: {}, + deniedSites: {}, rememberSiteChoice: true, }; @@ -54,8 +54,14 @@ async function loadState() { saved.blockscoutUrl || DEFAULT_STATE.blockscoutUrl; state.lastBalanceRefresh = saved.lastBalanceRefresh || 0; state.activeAddress = saved.activeAddress || null; - state.allowedSites = saved.allowedSites || []; - state.deniedSites = saved.deniedSites || []; + state.allowedSites = + saved.allowedSites && !Array.isArray(saved.allowedSites) + ? saved.allowedSites + : {}; + state.deniedSites = + saved.deniedSites && !Array.isArray(saved.deniedSites) + ? saved.deniedSites + : {}; state.rememberSiteChoice = saved.rememberSiteChoice !== undefined ? saved.rememberSiteChoice