Scope site connection permissions per address
Some checks failed
check / check (push) Has been cancelled
Some checks failed
check / check (push) Has been cancelled
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.
This commit is contained in:
@@ -19,7 +19,7 @@ const windowsApi =
|
|||||||
typeof browser !== "undefined" ? browser.windows : chrome.windows;
|
typeof browser !== "undefined" ? browser.windows : chrome.windows;
|
||||||
const tabsApi = typeof browser !== "undefined" ? browser.tabs : chrome.tabs;
|
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 = {};
|
const connectedSites = {};
|
||||||
|
|
||||||
// Pending approval requests: { id: { origin, hostname, resolve } }
|
// Pending approval requests: { id: { origin, hostname, resolve } }
|
||||||
@@ -33,8 +33,8 @@ async function getState() {
|
|||||||
wallets: [],
|
wallets: [],
|
||||||
rpcUrl: DEFAULT_RPC_URL,
|
rpcUrl: DEFAULT_RPC_URL,
|
||||||
activeAddress: null,
|
activeAddress: null,
|
||||||
allowedSites: [],
|
allowedSites: {},
|
||||||
deniedSites: [],
|
deniedSites: {},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -114,9 +114,11 @@ async function handleConnectionRequest(origin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hostname = extractHostname(origin);
|
const hostname = extractHostname(origin);
|
||||||
|
const allowed = s.allowedSites[activeAddress] || [];
|
||||||
|
const denied = s.deniedSites[activeAddress] || [];
|
||||||
|
|
||||||
// Check denied list
|
// Check denied list
|
||||||
if (s.deniedSites.includes(hostname)) {
|
if (denied.includes(hostname)) {
|
||||||
return {
|
return {
|
||||||
error: {
|
error: {
|
||||||
code: 4001,
|
code: 4001,
|
||||||
@@ -126,7 +128,10 @@ async function handleConnectionRequest(origin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check allowed list or in-memory connected
|
// Check allowed list or in-memory connected
|
||||||
if (s.allowedSites.includes(hostname) || connectedSites[origin]) {
|
if (
|
||||||
|
allowed.includes(hostname) ||
|
||||||
|
connectedSites[origin + ":" + activeAddress]
|
||||||
|
) {
|
||||||
return { result: [activeAddress] };
|
return { result: [activeAddress] };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,19 +142,25 @@ async function handleConnectionRequest(origin) {
|
|||||||
if (decision.remember) {
|
if (decision.remember) {
|
||||||
// Reload state to get latest, add to allowed, persist
|
// Reload state to get latest, add to allowed, persist
|
||||||
await loadState();
|
await loadState();
|
||||||
if (!state.allowedSites.includes(hostname)) {
|
if (!state.allowedSites[activeAddress]) {
|
||||||
state.allowedSites.push(hostname);
|
state.allowedSites[activeAddress] = [];
|
||||||
|
}
|
||||||
|
if (!state.allowedSites[activeAddress].includes(hostname)) {
|
||||||
|
state.allowedSites[activeAddress].push(hostname);
|
||||||
}
|
}
|
||||||
await saveState();
|
await saveState();
|
||||||
} else {
|
} else {
|
||||||
connectedSites[origin] = true;
|
connectedSites[origin + ":" + activeAddress] = true;
|
||||||
}
|
}
|
||||||
return { result: [activeAddress] };
|
return { result: [activeAddress] };
|
||||||
} else {
|
} else {
|
||||||
if (decision.remember) {
|
if (decision.remember) {
|
||||||
await loadState();
|
await loadState();
|
||||||
if (!state.deniedSites.includes(hostname)) {
|
if (!state.deniedSites[activeAddress]) {
|
||||||
state.deniedSites.push(hostname);
|
state.deniedSites[activeAddress] = [];
|
||||||
|
}
|
||||||
|
if (!state.deniedSites[activeAddress].includes(hostname)) {
|
||||||
|
state.deniedSites[activeAddress].push(hostname);
|
||||||
}
|
}
|
||||||
await saveState();
|
await saveState();
|
||||||
}
|
}
|
||||||
@@ -198,7 +209,11 @@ async function handleRpc(method, params, origin) {
|
|||||||
const activeAddress = await getActiveAddress();
|
const activeAddress = await getActiveAddress();
|
||||||
if (!activeAddress) return { result: [] };
|
if (!activeAddress) return { result: [] };
|
||||||
const hostname = extractHostname(origin);
|
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: [activeAddress] };
|
||||||
}
|
}
|
||||||
return { result: [] };
|
return { result: [] };
|
||||||
@@ -256,8 +271,10 @@ async function handleRpc(method, params, origin) {
|
|||||||
const s = await getState();
|
const s = await getState();
|
||||||
const activeAddress = await getActiveAddress();
|
const activeAddress = await getActiveAddress();
|
||||||
const hostname = extractHostname(origin);
|
const hostname = extractHostname(origin);
|
||||||
|
const allowed = s.allowedSites[activeAddress] || [];
|
||||||
const isConnected =
|
const isConnected =
|
||||||
s.allowedSites.includes(hostname) || connectedSites[origin];
|
allowed.includes(hostname) ||
|
||||||
|
connectedSites[origin + ":" + activeAddress];
|
||||||
if (!isConnected || !activeAddress) {
|
if (!isConnected || !activeAddress) {
|
||||||
return { result: [] };
|
return { result: [] };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,25 +6,31 @@ const { log } = require("../../shared/log");
|
|||||||
const runtime =
|
const runtime =
|
||||||
typeof browser !== "undefined" ? browser.runtime : chrome.runtime;
|
typeof browser !== "undefined" ? browser.runtime : chrome.runtime;
|
||||||
|
|
||||||
function renderSiteList(containerId, list, stateKey) {
|
function renderSiteList(containerId, siteMap, stateKey) {
|
||||||
const container = $(containerId);
|
const container = $(containerId);
|
||||||
if (list.length === 0) {
|
const hostnames = [...new Set(Object.values(siteMap).flat())];
|
||||||
|
if (hostnames.length === 0) {
|
||||||
container.innerHTML = '<p class="text-xs text-muted">None</p>';
|
container.innerHTML = '<p class="text-xs text-muted">None</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let html = "";
|
let html = "";
|
||||||
list.forEach((hostname, i) => {
|
hostnames.forEach((hostname) => {
|
||||||
html += `<div class="flex justify-between items-center text-xs py-1 border-b border-border-light">`;
|
html += `<div class="flex justify-between items-center text-xs py-1 border-b border-border-light">`;
|
||||||
html += `<span>${hostname}</span>`;
|
html += `<span>${hostname}</span>`;
|
||||||
html += `<button class="btn-remove-site border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-key="${stateKey}" data-index="${i}">[x]</button>`;
|
html += `<button class="btn-remove-site border border-border px-1 hover:bg-fg hover:text-bg cursor-pointer" data-key="${stateKey}" data-hostname="${hostname}">[x]</button>`;
|
||||||
html += `</div>`;
|
html += `</div>`;
|
||||||
});
|
});
|
||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
container.querySelectorAll(".btn-remove-site").forEach((btn) => {
|
container.querySelectorAll(".btn-remove-site").forEach((btn) => {
|
||||||
btn.addEventListener("click", async () => {
|
btn.addEventListener("click", async () => {
|
||||||
const key = btn.dataset.key;
|
const key = btn.dataset.key;
|
||||||
const idx = parseInt(btn.dataset.index, 10);
|
const host = btn.dataset.hostname;
|
||||||
state[key].splice(idx, 1);
|
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();
|
await saveState();
|
||||||
runtime.sendMessage({ type: "AUTISTMASK_REMOVE_SITE" });
|
runtime.sendMessage({ type: "AUTISTMASK_REMOVE_SITE" });
|
||||||
renderSiteList(containerId, state[key], key);
|
renderSiteList(containerId, state[key], key);
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ const DEFAULT_STATE = {
|
|||||||
blockscoutUrl: DEFAULT_BLOCKSCOUT_URL,
|
blockscoutUrl: DEFAULT_BLOCKSCOUT_URL,
|
||||||
lastBalanceRefresh: 0,
|
lastBalanceRefresh: 0,
|
||||||
activeAddress: null,
|
activeAddress: null,
|
||||||
allowedSites: [],
|
allowedSites: {},
|
||||||
deniedSites: [],
|
deniedSites: {},
|
||||||
rememberSiteChoice: true,
|
rememberSiteChoice: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,8 +54,14 @@ async function loadState() {
|
|||||||
saved.blockscoutUrl || DEFAULT_STATE.blockscoutUrl;
|
saved.blockscoutUrl || DEFAULT_STATE.blockscoutUrl;
|
||||||
state.lastBalanceRefresh = saved.lastBalanceRefresh || 0;
|
state.lastBalanceRefresh = saved.lastBalanceRefresh || 0;
|
||||||
state.activeAddress = saved.activeAddress || null;
|
state.activeAddress = saved.activeAddress || null;
|
||||||
state.allowedSites = saved.allowedSites || [];
|
state.allowedSites =
|
||||||
state.deniedSites = saved.deniedSites || [];
|
saved.allowedSites && !Array.isArray(saved.allowedSites)
|
||||||
|
? saved.allowedSites
|
||||||
|
: {};
|
||||||
|
state.deniedSites =
|
||||||
|
saved.deniedSites && !Array.isArray(saved.deniedSites)
|
||||||
|
? saved.deniedSites
|
||||||
|
: {};
|
||||||
state.rememberSiteChoice =
|
state.rememberSiteChoice =
|
||||||
saved.rememberSiteChoice !== undefined
|
saved.rememberSiteChoice !== undefined
|
||||||
? saved.rememberSiteChoice
|
? saved.rememberSiteChoice
|
||||||
|
|||||||
Reference in New Issue
Block a user