From 3af98f77302ed95e9f62715da421017e7f26a71c Mon Sep 17 00:00:00 2001 From: Aaron Kollasch Date: Sat, 6 Nov 2021 16:07:09 -0400 Subject: [PATCH 1/4] Add support for container tabs --- .gitmodules | 1 + src/bg/LifeCycle.js | 15 ++++- src/bg/RequestGuard.js | 28 ++++---- src/bg/Settings.js | 9 +++ src/bg/main.js | 69 ++++++++++++++++---- src/manifest.json | 4 +- src/nscl | 2 +- src/ui/options.css | 32 +++++++++ src/ui/options.html | 21 ++++++ src/ui/options.js | 144 +++++++++++++++++++++++++++++++++++++---- src/ui/popup.css | 8 +++ src/ui/popup.html | 1 + src/ui/popup.js | 20 +++++- src/ui/ui.js | 87 +++++++++++++++++-------- 14 files changed, 373 insertions(+), 68 deletions(-) diff --git a/.gitmodules b/.gitmodules index c93b31b8..0185a08d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "nscl"] path = src/nscl url = ../nscl.git + branch = container-tabs diff --git a/src/bg/LifeCycle.js b/src/bg/LifeCycle.js index 32c2d6d7..f72d037c 100644 --- a/src/bg/LifeCycle.js +++ b/src/bg/LifeCycle.js @@ -104,6 +104,7 @@ var LifeCycle = (() => { let {url} = tab; let {cypherText, key, iv} = await encrypt(JSON.stringify({ policy: ns.policy.dry(true), + contextStore: ns.contextStore.dry(true), allSeen, unrestrictedTabs: [...ns.unrestrictedTabs] })); @@ -188,7 +189,7 @@ var LifeCycle = (() => { iv }, key, cypherText ); - let {policy, allSeen, unrestrictedTabs} = JSON.parse(new TextDecoder().decode(encoded)); + let {policy, contextStore, allSeen, unrestrictedTabs} = JSON.parse(new TextDecoder().decode(encoded)); if (!policy) { throw new error("Ephemeral policy not found in survival tab %s!", tabId); } @@ -196,6 +197,7 @@ var LifeCycle = (() => { destroyIfNeeded(); if (ns.initializing) await ns.initializing; ns.policy = new Policy(policy); + ns.contextStore = new ContextStore(contextStore); await Promise.all( Object.entries(allSeen).map( async ([tabId, seen]) => { @@ -274,6 +276,17 @@ var LifeCycle = (() => { if (changed) { await ns.savePolicy(); } + if (ns.contextStore) { + changed = false; + for (let k of Object.keys(ns.contextStore.policies)){ + for (let p of ns.contextStore.policies[k].getPresets(presetNames)) { + if (callback(p)) changed = true; + } + } + if (changed) { + await ns.saveContextStore(); + } + } }; let configureNewCap = async (cap, presetNames, capsFilter) => { diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js index f3a0e638..c46ae4eb 100644 --- a/src/bg/RequestGuard.js +++ b/src/bg/RequestGuard.js @@ -280,8 +280,10 @@ var RequestGuard = (() => { } let key = [siteKey, origin][ret.option || 0]; if (!key) return; + let cookieStoreId = sender.tab && sender.tab.cookieStoreId; + let policy = ns.getPolicy(cookieStoreId); let contextUrl = sender.tab.url || documentUrl; - let {siteMatch, contextMatch, perms} = ns.policy.get(key, contextUrl); + let {siteMatch, contextMatch, perms} = policy.get(key, contextUrl); let {capabilities} = perms; if (!capabilities.has(policyType)) { let temp = sender.tab.incognito; // we don't want to store in PBM @@ -294,8 +296,9 @@ var RequestGuard = (() => { perms = new Permissions(new Set(capabilities), false, contextualSites); } */ - ns.policy.set(key, perms); + policy.set(key, perms); await ns.savePolicy(); + await ns.saveContextStore(); } return {enable: key}; }, @@ -397,7 +400,7 @@ var RequestGuard = (() => { }; function intersectCapabilities(perms, request) { - let {frameId, frameAncestors, tabId} = request; + let {frameId, frameAncestors, tabId, cookieStoreId} = request; if (frameId !== 0 && ns.sync.cascadeRestrictions) { let topUrl = frameAncestors && frameAncestors.length && frameAncestors[frameAncestors.length - 1].url; @@ -406,7 +409,8 @@ var RequestGuard = (() => { if (tab) topUrl = tab.url; } if (topUrl) { - return ns.policy.cascadeRestrictions(perms, topUrl).capabilities; + let policy = ns.getPolicy(cookieStoreId); + return policy.cascadeRestrictions(perms, topUrl).capabilities; } } return perms.capabilities; @@ -468,9 +472,10 @@ var RequestGuard = (() => { function checkLANRequest(request) { if (!ns.isEnforced(request.tabId)) return ALLOW; - let {originUrl, url} = request; + let {originUrl, url, cookieStoreId} = request; + let policy = ns.getPolicy(cookieStoreId); if (originUrl && !Sites.isInternal(originUrl) && url.startsWith("http") && - !ns.policy.can(originUrl, "lan", ns.policyContext(request))) { + !policy.can(originUrl, "lan", ns.policyContext(request))) { // we want to block any request whose origin resolves to at least one external WAN IP // and whose destination resolves to at least one LAN IP let {proxyInfo} = request; // see https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/proxy/ProxyInfo @@ -504,7 +509,6 @@ var RequestGuard = (() => { normalizeRequest(request); initPendingRequest(request); - let {policy} = ns let {tabId, type, url, originUrl} = request; if (type in policyTypesMap) { @@ -527,7 +531,9 @@ var RequestGuard = (() => { } return ALLOW; } + let {cookieStoreId} = request; let isFetch = "fetch" === policyType; + let policy = ns.getPolicy(cookieStoreId); if ((isFetch || "frame" === policyType) && (((isFetch && !originUrl @@ -639,12 +645,12 @@ var RequestGuard = (() => { let promises = []; pending.headersProcessed = true; - let {url, documentUrl, tabId, responseHeaders, type} = request; + let {url, documentUrl, tabId, cookieStoreId, responseHeaders, type} = request; let isMainFrame = type === "main_frame"; try { let capabilities; if (ns.isEnforced(tabId)) { - let policy = ns.policy; + let policy = ns.getPolicy(cookieStoreId); let {perms} = policy.get(url, ns.policyContext(request)); if (isMainFrame) { if (policy.autoAllowTop && perms === policy.DEFAULT) { @@ -769,8 +775,8 @@ var RequestGuard = (() => { } function injectPolicyScript(details) { - let {url, tabId, frameId} = details; - let policy = ns.computeChildPolicy({url}, {tab: {id: tabId}, frameId}); + let {url, tabId, frameId, cookieStoreId} = details; + let policy = ns.computeChildPolicy({url}, {tab: {id: tabId}, frameId, cookieStoreId}); policy.navigationURL = url; let debugStatement = ns.local.debug ? ` let mark = Date.now() + ":" + Math.random(); diff --git a/src/bg/Settings.js b/src/bg/Settings.js index 03126062..b942c6f4 100644 --- a/src/bg/Settings.js +++ b/src/bg/Settings.js @@ -98,6 +98,7 @@ var Settings = { async update(settings) { let { policy, + contextStore, xssUserChoices, tabId, unrestrictedTab, @@ -146,6 +147,7 @@ var Settings = { if (settings.sync === null) { // user is resetting options policy = this.createDefaultDryPolicy(); + contextStore = new ContextStore().dry(); // overriden defaults when user manually resets options @@ -170,6 +172,12 @@ var Settings = { await ns.savePolicy(); } + if (contextStore) { + let newContextStore = new ContextStore(contextStore); + ns.contextStore = newContextStore + await ns.saveContextStore(); + } + if (typeof unrestrictedTab === "boolean") { ns.unrestrictedTabs[unrestrictedTab ? "add" : "delete"](tabId); } @@ -213,6 +221,7 @@ var Settings = { export() { return JSON.stringify({ policy: ns.policy.dry(), + contextStore: ns.contextStore.dry(), local: ns.local, sync: ns.sync, xssUserChoices: XSS.getUserChoices(), diff --git a/src/bg/main.js b/src/bg/main.js index 1748bb5e..4dfede6e 100644 --- a/src/bg/main.js +++ b/src/bg/main.js @@ -82,6 +82,19 @@ } } + if (!ns.contextStore) { // it could have been already retrieved by LifeCycle + let contextStoreData = (await Storage.get("sync", "contextStore")).contextStore; + if (contextStoreData) { + ns.contextStore = new ContextStore(contextStoreData); + await ns.contextStore.updateContainers(ns.policy); + } else { + log("No container data found. Initializing new policies.") + ns.contextStore = new ContextStore(); + await ns.contextStore.updateContainers(ns.policy); + await ns.saveContextStore(); + } + } + let {isTorBrowser} = ns.local; Sites.onionSecure = isTorBrowser; @@ -178,11 +191,13 @@ tabId = -1 }) { let policy = ns.policy.dry(true); + let contextStore = ns.contextStore.dry(true); let seen = tabId !== -1 ? await ns.collectSeen(tabId) : null; let xssUserChoices = await XSS.getUserChoices(); let anonymyzedTabInfo = await Messages.send("settings", { policy, + contextStore, seen, xssUserChoices, local: ns.local, @@ -272,6 +287,7 @@ var ns = { running: false, policy: null, + contextStore: null, local: null, sync: null, initializing: null, @@ -293,21 +309,22 @@ return !this.isEnforced(request.tabId) || this.policy.can(request.url, capability, this.policyContext(request)); }, - computeChildPolicy({url, contextUrl}, sender) { - let {tab, frameId} = sender; - let policy = ns.policy; - let {isTorBrowser} = ns.local; - if (!policy) { - console.log("Policy is null, initializing: %o, sending fallback.", ns.initializing); - return { - permissions: new Permissions(Permissions.DEFAULT).dry(), - unrestricted: false, - cascaded: false, - fallback: true, - isTorBrowser, - }; + getPolicy(cookieStoreId){ + if ( + ns.contextStore && + ns.contextStore.enabled && + ns.contextStore.policies.hasOwnProperty(cookieStoreId) + ) { + let currentPolicy = ns.contextStore.policies[cookieStoreId]; + debug("id", cookieStoreId, "has cookiestore", currentPolicy); + if (currentPolicy) return currentPolicy; } + debug("default cookiestore", cookieStoreId); + return ns.policy; + }, + computeChildPolicy({url, contextUrl}, sender) { + let {tab, frameId, cookieStoreId} = sender; let tabId = tab ? tab.id : -1; let topUrl; if (frameId === 0) { @@ -319,6 +336,20 @@ if (!topUrl) topUrl = url; if (!contextUrl) contextUrl = topUrl; + if (!cookieStoreId && tab) cookieStoreId = tab.cookieStoreId; + let policy = ns.getPolicy(cookieStoreId); + let {isTorBrowser} = ns.local; + if (!policy) { + console.log("Policy is null, initializing: %o, sending fallback.", ns.initializing); + return { + permissions: new Permissions(Permissions.DEFAULT).dry(), + unrestricted: false, + cascaded: false, + fallback: true, + isTorBrowser, + }; + } + if (Sites.isInternal(url) || !ns.isEnforced(tabId)) { policy = null; } @@ -384,7 +415,7 @@ await Storage.set("sync", { policy: this.policy.dry() }); - await browser.webRequest.handlerBehaviorChanged() + await browser.webRequest.handlerBehaviorChanged(); } return this.policy; }, @@ -401,6 +432,16 @@ browser.tabs.create({url: url.toString() }); }, + async saveContextStore() { + if (this.contextStore) { + await Storage.set("sync", { + contextStore: this.contextStore.dry() + }); + await browser.webRequest.handlerBehaviorChanged(); + } + return this.contextStore; + }, + async save(obj) { if (obj && obj.storage) { let toBeSaved = { diff --git a/src/manifest.json b/src/manifest.json index 5b45d065..94cad092 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -36,7 +36,8 @@ "webRequest", "webRequestBlocking", "dns", - "" + "", + "contextualIdentities" ], "background": { @@ -58,6 +59,7 @@ "/nscl/common/Sites.js", "/nscl/common/Permissions.js", "/nscl/common/Policy.js", + "/nscl/common/ContextStore.js", "/nscl/common/locale.js", "/nscl/common/Storage.js", "/nscl/common/include.js", diff --git a/src/nscl b/src/nscl index 08593a23..1a0a8045 160000 --- a/src/nscl +++ b/src/nscl @@ -1 +1 @@ -Subproject commit 08593a23b46e2616ffadf2836291ef233e62ac89 +Subproject commit 1a0a8045ba82cac3c6f1decd05a91bac8871f7e2 diff --git a/src/ui/options.css b/src/ui/options.css index c126d49b..9099945f 100644 --- a/src/ui/options.css +++ b/src/ui/options.css @@ -82,6 +82,24 @@ fieldset:disabled { flex: 2 2; } +.per-site-buttons { + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + width: 100%; + text-align: right; + margin: .5em 0 0 0; +} +#btn-clear-container { + margin-inline-start: .5em; +} +#copy-container { + margin-inline: .5em; +} +#copy-container-label { + margin-block: auto; +} + #policy { display: block; margin-top: .5em; @@ -91,6 +109,12 @@ fieldset:disabled { .hide, body:not(.debug) div.debug { display: none; } +#context-store { + display: block; + margin-top: .5em; + min-height: 20em; + width: 90%; +} #debug-tools { padding-left: 2.5em; @@ -110,6 +134,14 @@ fieldset:disabled { font-weight: bold; } +#context-store-error { + background: red; + color: #ff8; + padding: 0; + margin: 0; + font-weight: bold; +} + input, button { font-size: 1em; } diff --git a/src/ui/options.html b/src/ui/options.html index 5c1bbf9c..899c4726 100644 --- a/src/ui/options.html +++ b/src/ui/options.html @@ -53,6 +53,9 @@

+ +
+
+ + +
+ +
@@ -198,6 +213,12 @@

diff --git a/src/ui/popup.js b/src/ui/popup.js index 52d33625..c3a1a47b 100644 --- a/src/ui/popup.js +++ b/src/ui/popup.js @@ -80,6 +80,7 @@ addEventListener("unload", e => { } else { tabId = tab.id; } + let cookieStoreId = pageTab.cookieStoreId; addEventListener("keydown", e => { if (e.code === "Enter") { @@ -108,6 +109,19 @@ addEventListener("unload", e => { }); } + if (UI.contextStore && UI.contextStore.enabled && browser.contextualIdentities) { + try { + let containerName = (await browser.contextualIdentities.get(cookieStoreId)).name; + document.querySelector("#container-id").textContent = containerName; + debug("found container name", containerName, "for cookieStoreId", cookieStoreId); + } catch(err) { + document.querySelector("#container-id").textContent = "Default"; + debug("no container for cookieStoreId", cookieStoreId, "error:", err.message); + } + } else { + document.querySelector("#container-id").style.visibility = 'hidden'; + } + await include("/ui/toolbar.js"); UI.toolbarInit(); { @@ -298,7 +312,9 @@ addEventListener("unload", e => { let justDomains = !UI.local.showFullAddresses; - sitesUI = new UI.Sites(document.getElementById("sites")); + let policy = await UI.getPolicy(cookieStoreId); + debug("popup policy", policy); + sitesUI = new UI.Sites(document.getElementById("sites"), UI.DEF_PRESETS, policy); sitesUI.onChange = (row) => { pendingReload(sitesUI.anyPermissionsChanged()); @@ -330,7 +346,7 @@ addEventListener("unload", e => { typesMap } = sitesUI; typesMap.clear(); - let policySites = UI.policy.sites; + let policySites = policy.sites; let domains = new Map(); let protocols = new Set(); function urlToLabel(url) { diff --git a/src/ui/ui.js b/src/ui/ui.js index 2e5b5b3c..e6e865b4 100644 --- a/src/ui/ui.js +++ b/src/ui/ui.js @@ -45,6 +45,7 @@ var UI = (() => { "/nscl/common/Sites.js", "/nscl/common/Permissions.js", "/nscl/common/Policy.js", + "/nscl/common/ContextStore.js" ]; this.mobile = UA.mobile; let root = document.documentElement; @@ -58,7 +59,8 @@ var UI = (() => { async settings(m) { if (UI.tabId !== m.tabId) return; UI.policy = new Policy(m.policy); - UI.snapshot = UI.policy.snapshot; + UI.contextStore = new ContextStore(m.contextStore); + UI.snapshot = UI.policy.snapshot+UI.contextStore.snapshot; UI.seen = m.seen; UI.unrestrictedTab = m.unrestrictedTab; UI.xssUserChoices = m.xssUserChoices; @@ -96,7 +98,7 @@ var UI = (() => { await inited; this.initialized = true; - debug("Imported", Policy); + debug("Imported", Policy, ContextStore); }, async pullSettings() { try { @@ -106,10 +108,12 @@ var UI = (() => { browser.runtime.reload(); } }, - async updateSettings({policy, xssUserChoices, unrestrictedTab, local, sync, reloadAffected, command}) { + async updateSettings({policy, contextStore, xssUserChoices, unrestrictedTab, local, sync, reloadAffected, command}) { if (policy) policy = policy.dry(true); + if (contextStore) contextStore = contextStore.dry(true); return await Messages.send("updateSettings", { policy, + contextStore, xssUserChoices, unrestrictedTab, local, @@ -130,13 +134,41 @@ var UI = (() => { async revokeTemp(reloadAffected = false) { let policy = this.policy; Policy.hydrate(policy.dry(), policy); + let contextStore = this.contextStore + ContextStore.hydrate(contextStore.dry(), contextStore) if (this.isDirty(true)) { - await this.updateSettings({policy, reloadAffected}); + await this.updateSettings({policy, contextStore, reloadAffected}); + } + }, + + async getPolicy(cookieStoreId) { + await this.contextStore.updateContainers(this.policy); + if (this.contextStore.enabled && this.contextStore.policies.hasOwnProperty(cookieStoreId)) { + let currentPolicy = this.contextStore.policies[cookieStoreId]; + debug("id", cookieStoreId, "has cookiestore", currentPolicy); + return currentPolicy; + } else { + debug("default cookiestore", cookieStoreId); + return this.policy; + } + }, + + async replacePolicy(cookieStoreId, policy) { + await this.contextStore.updateContainers(this.policy); + if (this.contextStore.policies.hasOwnProperty(cookieStoreId)) { + this.contextStore.policies[cookieStoreId] = policy; + debug("replaced id", cookieStoreId, "with policy", policy); + let currentPolicy = this.contextStore.policies[cookieStoreId]; + return currentPolicy; + } else { + this.policy = policy; + debug("replaced default cookiestore", cookieStoreId, "with policy", policy); + return this.policy; } }, isDirty(reset = false) { - let currentSnapshot = this.policy.snapshot; + let currentSnapshot = this.policy.snapshot+this.contextStore.snapshot; let dirty = currentSnapshot != this.snapshot; if (reset) this.snapshot = currentSnapshot; return dirty; @@ -322,7 +354,7 @@ var UI = (() => { function fireOnChange(sitesUI, data) { if (UI.isDirty(true)) { - UI.updateSettings({policy: UI.policy}); + UI.updateSettings({policy: UI.policy, contextStore: UI.contextStore}); if (sitesUI.onChange) sitesUI.onChange(data, this); } } @@ -397,11 +429,11 @@ var UI = (() => { const INCOGNITO_PRESETS = ["DEFAULT", "T_TRUSTED", "CUSTOM"]; UI.Sites = class { - constructor(parentNode, presets = DEF_PRESETS) { + constructor(parentNode, presets = DEF_PRESETS, policy = null) { this.parentNode = parentNode; - let policy = UI.policy; + this.policy = (policy)? policy : UI.policy; this.uiCount = UI.Sites.count = (UI.Sites.count || 0) + 1; - this.sites = policy.sites; + this.sites = this.policy.sites; this.presets = presets; this.customizing = null; this.typesMap = new Map(); @@ -510,6 +542,11 @@ var UI = (() => { this.customize(null); this.sitesCount = 0; + this.sites = ({ + trusted: [], + untrusted: [], + custom: {}, + }) } siteNeeds(site, type) { @@ -549,7 +586,6 @@ var UI = (() => { let tempToggle = preset.parentNode.querySelector("input.temp"); if (ev.type === "change") { - let {policy} = UI; if (!row._originalPerms) { row._originalPerms = row.perms.clone(); Object.defineProperty(row, "permissionsChanged", { @@ -563,7 +599,7 @@ var UI = (() => { if (!opt) return; let context = opt.value; if (context === "*") context = null; - ({siteMatch, perms, contextMatch} = policy.get(siteMatch, context)); + ({siteMatch, perms, contextMatch} = this.policy.get(siteMatch, context)); if (!context) { row._customPerms = perms; } else if (contextMatch !== context) { @@ -582,7 +618,7 @@ var UI = (() => { let presetValue = preset.value; - let policyPreset = presetValue.startsWith("T_") ? policy[presetValue.substring(2)].tempTwin : policy[presetValue]; + let policyPreset = presetValue.startsWith("T_") ? this.policy[presetValue.substring(2)].tempTwin : this.policy[presetValue]; if (policyPreset && row.perms !== policyPreset) { row.perms = policyPreset; @@ -600,7 +636,7 @@ var UI = (() => { row.perms = policyPreset; delete row._customPerms; if (siteMatch) { - policy.set(siteMatch, policyPreset); + this.policy.set(siteMatch, policyPreset); } else { this.customize(policyPreset, preset, row); } @@ -614,7 +650,7 @@ var UI = (() => { let perms = row._customPerms || (row._customPerms = new Permissions(new Set(row.perms.capabilities), temp)); row.perms = perms; - policy.set(siteMatch, perms); + this.policy.set(siteMatch, perms); this.customize(perms, preset, row); } } @@ -705,7 +741,7 @@ var UI = (() => { let selected = ctxSelect.querySelector("option:checked"); ctxReset.disabled = !(selected && selected.value !== "*"); ctxReset.onclick = () => { - let perms = UI.policy.get(row.siteMatch).perms; + let perms = this.policy.get(row.siteMatch).perms; perms.contextual.delete(row.contextMatch); fireOnChange(this, row); selected.previousElementSibling.selected = true; @@ -883,7 +919,7 @@ var UI = (() => { site = site.site; context = site.context; } - let {siteMatch, perms, contextMatch} = UI.policy.get(site, context); + let {siteMatch, perms, contextMatch} = this.policy.get(site, context); this.append(site, siteMatch, perms, contextMatch); if (!hasTemp) hasTemp = perms.temp; } @@ -936,30 +972,28 @@ var UI = (() => { } async tempTrustAll() { - let {policy} = UI; let changed = 0; for (let row of this.allSiteRows()) { if (row._preset === "DEFAULT") { - policy.set(row._site, policy.TRUSTED.tempTwin); + this.policy.set(row._site, this.policy.TRUSTED.tempTwin); changed++; } } if (changed && UI.isDirty(true)) { - await UI.updateSettings({policy, reloadAffected: true}); + await UI.updateSettings({policy: UI.policy, contextStore: UI.contextStore, reloadAffected: true}); } return changed; } createSiteRow(site, siteMatch, perms, contextMatch = null, sitesCount = this.sitesCount++) { debug("Creating row for site: %s, matching %s / %s, %o", site, siteMatch, contextMatch, perms); - let policy = UI.policy; let row = this.rowTemplate.cloneNode(true); row.sitesCount = sitesCount; let url; try { url = new URL(site); if (siteMatch !== site && siteMatch === url.protocol) { - perms = policy.DEFAULT; + perms = this.policy.DEFAULT; } } catch (e) { if (/^(\w+:)\/*$/.test(site)) { @@ -976,7 +1010,7 @@ var UI = (() => { let {hostname} = url; let overrideDefault = site && url.protocol && site !== url.protocol ? - policy.get(url.protocol, contextMatch) : null; + this.policy.get(url.protocol, contextMatch) : null; if (overrideDefault && !overrideDefault.siteMatch) overrideDefault = null; let domain = tld.getDomain(hostname); @@ -1036,7 +1070,7 @@ var UI = (() => { let getPresetName = perms => { let presetName = "CUSTOM"; for (let p of ["TRUSTED", "UNTRUSTED", "DEFAULT"]) { - let preset = policy[p]; + let preset = this.policy[p]; switch (perms) { case preset: presetName = p; @@ -1078,7 +1112,7 @@ var UI = (() => { for (let p of TEMP_PRESETS) { if (p in this.presets && (unsafeMatch || tempFirst && p === "TRUSTED")) { row.querySelector(`.presets input[value="${p}"]`).parentNode.querySelector("input.temp").checked = true; - perms = policy.TRUSTED.tempTwin; + perms = this.policy.TRUSTED.tempTwin; } } } @@ -1112,9 +1146,8 @@ var UI = (() => { if (site !== row.siteMatch) { this.customize(null); let focused = document.activeElement; - let {policy} = UI; - policy.set(row.siteMatch, policy.DEFAULT); - policy.set(site, row.perms); + this.policy.set(row.siteMatch, this.policy.DEFAULT); + this.policy.set(site, row.perms); for(let r of this.allSiteRows()) { if (r !== row && r.siteMatch === site && r.contextMatch === row.contextMatch) { r.remove(); From 581dab4ef5ec263db6883c06f3556a289fdf29b9 Mon Sep 17 00:00:00 2001 From: Aaron Kollasch Date: Thu, 7 Apr 2022 02:40:51 -0400 Subject: [PATCH 2/4] Prevent replacing the default policy --- src/ui/options.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ui/options.js b/src/ui/options.js index 8cefd5a1..68cc9a85 100644 --- a/src/ui/options.js +++ b/src/ui/options.js @@ -237,6 +237,11 @@ document.querySelector("#version").textContent = _("Version", async function copyContainer() { cookieStoreId = containerSelect.value; + if (cookieStoreId == "default") { + alert("Cannot replace the default policy.") + containerCopy.value = "blank"; + return; + } let copyCookieStoreId = containerCopy.value; let copyContainerName = containerCopy.options[containerCopy.selectedIndex].text; let copyPolicy = await UI.getPolicy(copyCookieStoreId); From be840e42cbf05b6b7b5122899384768d92cb4166 Mon Sep 17 00:00:00 2001 From: Aaron Kollasch Date: Thu, 7 Apr 2022 02:42:12 -0400 Subject: [PATCH 3/4] Add blank default to copy container selector --- src/ui/options.html | 1 + src/ui/options.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ui/options.html b/src/ui/options.html index 899c4726..eb6df2f4 100644 --- a/src/ui/options.html +++ b/src/ui/options.html @@ -95,6 +95,7 @@