From e959accb70ea00f99fa611c9f1af40e1be5bde92 Mon Sep 17 00:00:00 2001 From: hackademix Date: Fri, 17 Aug 2018 09:07:11 +0200 Subject: Hack: use top.name to store per-tab content-side configuration (e.g. unrestricted tab status). --- src/bg/ChildPolicies.js | 30 ++++++++++++++++++++++++------ src/bg/Settings.js | 3 ++- src/bg/defaults.js | 1 - src/content/content.js | 42 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/bg/ChildPolicies.js b/src/bg/ChildPolicies.js index fd790c9..0a77b8b 100644 --- a/src/bg/ChildPolicies.js +++ b/src/bg/ChildPolicies.js @@ -1,5 +1,7 @@ -"use script"; +"use strict"; { + let marker = JSON.stringify(uuid()); + let Scripts = { references: new Set(), opts: { @@ -54,7 +56,27 @@ let siteKeys2MatchPatterns = keys => keys && flatten(keys.map(siteKey2MatchPattern)).filter(p => !!p) || []; var ChildPolicies = { + async storeTabInfo(tabId, info) { + try { + await browser.tabs.executeScript(tabId, { + code: `window.name = ${marker} + ${JSON.stringify(JSON.stringify([info]))} + ${marker} + "," + window.name;`, + allFrames: false, + matchAboutBlank: true, + runAt: "document_start", + }); + } catch (e) { + error(e); + } + }, async update(policy) { + Scripts.forget(); + + if (!policy.enforced) { + await Scripts.register(`ns.setup(null, ${marker});`, + [""]); + return; + } + let serialized = policy.dry ? policy.dry(true) : policy; let permsMap = new Map(); let trusted = JSON.stringify(serialized.TRUSTED); @@ -96,15 +118,11 @@ )); } - Scripts.forget(); // register new content scripts for (let [perms, keys] of [...permsMap]) { await Scripts.register(`ns.perms.CURRENT = ${perms};`, siteKeys2MatchPatterns(keys), excludeMap.get(perms)); } - await Scripts.register( - `ns.perms.DEFAULT = ${JSON.stringify(serialized.DEFAULT)}; - if(!ns.perms.CURRENT) ns.perms.CURRENT = ns.perms.DEFAULT; - ns.fire("perms");`, + await Scripts.register(`ns.setup(${JSON.stringify(serialized.DEFAULT)}, ${marker});`, [""]); } } diff --git a/src/bg/Settings.js b/src/bg/Settings.js index 4fb656f..09f0edd 100644 --- a/src/bg/Settings.js +++ b/src/bg/Settings.js @@ -89,7 +89,8 @@ var Settings = { } if (typeof unrestrictedTab === "boolean") { - ns.unrestrictedTabs[settings.unrestrictedTab ? "add" : "delete"](tabId); + ns.unrestrictedTabs[unrestrictedTab ? "add" : "delete"](tabId); + ChildPolicies.storeTabInfo(tabId, {unrestricted: unrestrictedTab}); } if (reloadAffected) { browser.tabs.reload(tabId); diff --git a/src/bg/defaults.js b/src/bg/defaults.js index 220bd23..4d071b4 100644 --- a/src/bg/defaults.js +++ b/src/bg/defaults.js @@ -28,7 +28,6 @@ ns.defaults = (async () => { // dynamic settings if (!ns.local.uuid) { - await include("/lib/uuid.js"); ns.local.uuid = uuid(); await ns.save(ns.local); } diff --git a/src/content/content.js b/src/content/content.js index 37d0d32..2f10d5a 100644 --- a/src/content/content.js +++ b/src/content/content.js @@ -21,7 +21,47 @@ } } }, - perms: { DEFAULT: null, CURRENT: null }, + setup(DEFAULT, MARKER) { + this.perms.DEFAULT = DEFAULT; + if(!this.perms.CURRENT) this.perms.CURRENT = DEFAULT; + + // ugly hack: since now we use registerContentScript instead of the + // filterRequest dynamic script injection hack, we use top.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.perms.MARKER = MARKER; + let eraseTabInfoRx = new RegExp(`[^]*${MARKER},?`); + if (eraseTabInfoRx.test(top.name)) { + let _name = top.name; + let tabInfoRx = new RegExp(`^${MARKER}\\[([^]*?)\\]${MARKER},`); + if (top === window) { // wrap to hide + Reflect.defineProperty(top.wrappedJSObject, "name", { + get: exportFunction(() => _name.replace(eraseTabInfoRx, ""), top.wrappedJSObject), + set: exportFunction(value => { + let preamble = _name.match(tabInfoRx); + _name = `${preamble && preamble[0] || ""}${value}`; + return value; + }, top.wrappedJSObject) + }); + } + let tabInfoMatch = _name.match(tabInfoRx); + if (tabInfoMatch) try { + this.perms.tabInfo = JSON.parse(tabInfoMatch[1]); + } catch (e) { + error(e); + } + } + + if (!this.perms.DEFAULT || this.perms.tabInfo.unrestricted) { + this.allows = () => true; + } + ns.fire("perms"); + }, + storeTabInfo(info) { + let {MARKER} = this.perms; + window.name = `${MARKER}${JSON.stringify([info])}${MARKER},${window.name.split(marker).pop()}`; + }, + perms: { DEFAULT: null, CURRENT: null, tabInfo: {} }, allows(cap) { let perms = this.perms.CURRENT; return perms && perms.capabilities.includes(cap); -- cgit v1.2.3