harden: key remembered site permissions by full origin (closes #402)
check / check (push) Failing after 2s
e2e / e2e-chrome (push) Failing after 2s
e2e / e2e-firefox (push) Failing after 1s

allowedSites and deniedSites held the bare hostname, so a grant to
https://dapp.example also authorised http://dapp.example and every port
on that host, and the connection, transaction and signature prompts
named only the hostname. Both lists now store and match the full origin
(scheme://host[:port]), the key the connections approved without
Remember already used. The prompts, the Settings site lists and
AUTISTMASK_REMOVE_SITE use the origin too. Entries saved by hostname
are not migrated (pre-1.0): they match no site.

Model: opus-5-5
This commit was merged in pull request #431.
This commit is contained in:
2026-10-04 18:09:04 +02:00
parent f24b5bca19
commit 1144fdb71b
29 changed files with 470 additions and 231 deletions
+10 -10
View File
@@ -304,7 +304,7 @@ function mergeAddress(base, ours, theirs) {
}
// Merge a plain object keyed by string (allowedSites/deniedSites: address ->
// hostname list; networkEndpoints: networkId -> {rpcUrl, blockscoutUrl}) the
// origin list; networkEndpoints: networkId -> {rpcUrl, blockscoutUrl}) the
// same way mergeListByIdentity() merges an array — by key, not by whole-
// object diff — so a key one page added or removed applies independently of
// a key another page edited. Unlike an array's identity function, an object
@@ -353,25 +353,25 @@ function mergeMapByKey(base, ours, theirs, mergeLeaf) {
return result;
}
// allowedSites/deniedSites: { [address]: [hostname, ...] }. The hostname
// allowedSites/deniedSites: { [address]: [origin, ...] }. The origin
// list is itself membership, not a leaf — the background appends a newly
// approved/denied hostname to it, and the Settings "revoke" button
// (src/popup/views/settings.js) filters a hostname out of it in place, from a
// approved/denied origin to it, and the Settings "revoke" button
// (src/popup/views/settings.js) filters an origin out of it in place, from a
// different page. Merge it the same way wallets are merged: identity is the
// hostname itself, so a merged pair is always equal and mergeItem is a no-op
// origin itself, so a merged pair is always equal and mergeItem is a no-op
// pick.
function mergeHostnameList(base, ours, theirs) {
function mergeOriginList(base, ours, theirs) {
return mergeListByIdentity(
base,
ours,
theirs,
(hostname) => hostname,
(origin) => origin,
(b, o, t) => t,
);
}
function mergeSiteMap(base, ours, theirs) {
return mergeMapByKey(base, ours, theirs, mergeHostnameList);
return mergeMapByKey(base, ours, theirs, mergeOriginList);
}
// networkEndpoints: { [networkId]: {rpcUrl, blockscoutUrl} }.
@@ -422,8 +422,8 @@ function mergeNetworkEndpoints(base, ours, theirs) {
// address) apply independently instead of colliding as the same field.
//
// `allowedSites` and `deniedSites` get the same treatment (mergeSiteMap(),
// by address key and then by hostname within each address's list), for the
// identical reason: the background appends a newly approved/denied hostname
// by address key and then by origin within each address's list), for the
// identical reason: the background appends a newly approved/denied origin
// to them, and the Settings "revoke" button (src/popup/views/settings.js)
// filters one out in place, from a different page. A whole-field diff here
// doesn't just lose data, it is a security defect — a stale page's save can