diff --git a/src/bg/ChildPolicies.js b/src/bg/ChildPolicies.js index 99402ca..e8608ad 100644 --- a/src/bg/ChildPolicies.js +++ b/src/bg/ChildPolicies.js @@ -102,7 +102,7 @@ let preamble = info ? `${marker} + ${JSON.stringify(JSON.stringify([info]))} + ${marker} + "," + ` : ""; await browser.tabs.executeScript(tabId, { code: `window.name = ${preamble}window.name.split(${marker} + ",").pop();`, - allFrames: false, + allFrames: true, matchAboutBlank: true, runAt: "document_start", }); diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js index 299e1a3..8850542 100644 --- a/src/bg/RequestGuard.js +++ b/src/bg/RequestGuard.js @@ -317,6 +317,10 @@ var RequestGuard = (() => { await ChildPolicies.update(policy); } capabilities = perms.capabilities; + } else { + if (!isMainFrame && type === "sub_frame") { + await Settings.enforceTabRestrictions(tabId); + } } if (isMainFrame && !TabStatus.map.has(tabId)) { debug("No TabStatus data yet for noscriptFrame", tabId); diff --git a/src/bg/Settings.js b/src/bg/Settings.js index 56c88f4..a5fca55 100644 --- a/src/bg/Settings.js +++ b/src/bg/Settings.js @@ -90,7 +90,7 @@ var Settings = { if (typeof unrestrictedTab === "boolean") { ns.unrestrictedTabs[unrestrictedTab ? "add" : "delete"](tabId); - ChildPolicies.storeTabInfo(tabId, unrestrictedTab && {unrestricted: true}); + this.enforceTabRestrictions(tabId, unrestrictedTab); } if (reloadAffected) { browser.tabs.reload(tabId); @@ -123,4 +123,8 @@ var Settings = { }, null, 2); }, + async enforceTabRestrictions(tabId, unrestricted = ns.unrestrictedTabs.has(tabId)) { + await ChildPolicies.storeTabInfo(tabId, unrestricted && {unrestricted: true}); + return unrestricted; + } } diff --git a/src/content/staticNS.js b/src/content/staticNS.js index 817351a..5deb1ab 100644 --- a/src/content/staticNS.js +++ b/src/content/staticNS.js @@ -2,7 +2,7 @@ { let listenersMap = new Map(); let backlog = new Set(); - + let ns = { debug: true, // DEV_ONLY get embeddingDocument() { @@ -32,39 +32,46 @@ } backlog.add(eventName); }, - + setup(DEFAULT, MARKER) { this.config.DEFAULT = DEFAULT; if(!this.config.CURRENT) this.config.CURRENT = DEFAULT; // ugly hack: since now we use registerContentScript instead of the - // filterRequest dynamic script injection hack, we use top.name + // filterRequest dynamic script injection hack, we use window.name // to store per-tab information. We don't want web content to // mess with it, though, so we wrap it around auto-hiding accessors - this.config.MARKER = MARKER; - let eraseTabInfoRx = new RegExp(`[^]*${MARKER},?`); - if (eraseTabInfoRx.test(top.name)) { - let _name = top.name; + + if (this.config.MARKER = MARKER) { + let tabInfoRx = new RegExp(`^${MARKER}\\[([^]*?)\\]${MARKER},`); - if (top === window) { // wrap to hide - Reflect.defineProperty(top.wrappedJSObject, "name", { - get: exportFunction(() => top.name.replace(eraseTabInfoRx, ""), top.wrappedJSObject), - set: exportFunction(value => { - let preamble = top.name.match(tabInfoRx); - top.name = `${preamble && preamble[0] || ""}${value}`; - return value; - }, top.wrappedJSObject) - }); + let name = window.name; + try { + name = top.name; + } catch(e) { + // won't work cross-origin } - let tabInfoMatch = _name.match(tabInfoRx); - if (tabInfoMatch) try { - this.config.tabInfo = JSON.parse(tabInfoMatch[1]); - } catch (e) { - error(e); + let tabInfoMatch = name.match(tabInfoRx); + if (tabInfoMatch) { + try { + this.config.tabInfo = JSON.parse(tabInfoMatch[1]); + } catch (e) { + error(e); + } } + let splitter = `${MARKER},`; + this.getWindowName = () => window.name.split(splitter).pop(); + Reflect.defineProperty(window.wrappedJSObject, "name", { + get: exportFunction(() => this.getWindowName(), window.wrappedJSObject), + set: exportFunction(value => { + let tabInfoMatch = window.name.match(tabInfoRx); + window.name = tabInfoMatch ? `${tabInfoMatch[0]}${value}` : value; + return value; + }, window.wrappedJSObject) + }); } - if (!this.config.DEFAULT || this.config.tabInfo.unrestricted) { + debug("%s is loading unrestricted by user's choice (%o).", document.URL, this.config); this.allows = () => true; this.capabilities = Object.assign( new Set(["script"]), { has() { return true; } }); @@ -73,24 +80,21 @@ this.capabilities = new Set(perms.capabilities); new DocumentCSP(document).apply(this.capabilities, this.embeddingDocument); } - + this.canScript = this.allows("script"); this.fire("capabilities"); }, config: { DEFAULT: null, CURRENT: null, tabInfo: {}, MARKER: "" }, - + allows(cap) { return this.capabilities && this.capabilities.has(cap); }, - + getWindowName() { - let marker = this.config.MARKER; - return (top === window && marker) ? - window.name.split(`${marker},`).pop() - : window.name; + return window.name; } }; - + if (this.ns) { this.ns.merge(ns); } else {