diff options
author | hackademix | 2018-08-15 16:41:55 +0200 |
---|---|---|
committer | hackademix | 2018-08-16 23:43:36 +0200 |
commit | 57d883d63e9b8232e275dac7eec24f84c040dd24 (patch) | |
tree | a4a9f05f0744ccef23e31643f80c400abe0dab37 /src/bg | |
parent | 2c75eedadddd8bda0522cddaf119e1e5c621c7c2 (diff) | |
download | noscript-57d883d63e9b8232e275dac7eec24f84c040dd24.tar.gz noscript-57d883d63e9b8232e275dac7eec24f84c040dd24.tar.xz noscript-57d883d63e9b8232e275dac7eec24f84c040dd24.zip |
Policy serialization using the contentScripts API.
Diffstat (limited to 'src/bg')
-rw-r--r-- | src/bg/ChildPolicies.js | 111 | ||||
-rw-r--r-- | src/bg/RequestGuard.js | 17 | ||||
-rw-r--r-- | src/bg/main.js | 5 |
3 files changed, 116 insertions, 17 deletions
diff --git a/src/bg/ChildPolicies.js b/src/bg/ChildPolicies.js new file mode 100644 index 0000000..fd790c9 --- /dev/null +++ b/src/bg/ChildPolicies.js @@ -0,0 +1,111 @@ +"use script"; +{ + let Scripts = { + references: new Set(), + opts: { + js: [{}], + allFrames: true, + matchAboutBlank: true, + runAt: "document_start" + }, + forget() { + for (let script of [...this.references]) { + script.unregister(); + this.references.delete(script); + } + }, + async register(code, matches, excludeMatches) { + debug("Registering child policy.", code, matches, excludeMatches); + if (!matches.length) return; + try { + this.opts.js[0].code = code; + this.opts.matches = matches; + if (excludeMatches && excludeMatches.length) { + this.opts.excludeMatches = excludeMatches; + } else { + delete this.opts.excludeMatches; + } + this.references.add(await browser.contentScripts.register(this.opts)); + } catch (e) { + error(e); + } + } + }; + + let flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []); + + let protocolRx = /^(https?):/i; + let pathRx = /[^:/]\//; + let portRx = /:\d+(?=\/|$)/; + let validMatchPatternRx = /^(?:https?|\*):\/\/(?:\*\.)?(?:[\w\u0100-\uf000][\w\u0100-\uf000.-]*)?[\w\u0100-\uf000]\/(\*|[^*]*)$/; + + let siteKey2MatchPattern = site => { + let hasProtocol = site.match(protocolRx); + let protocol = hasProtocol ? '' + : Sites.isSecureDomainKey(site) ? "https://" : "*://"; + let hostname = Sites.toggleSecureDomainKey(site, false) + .replace(portRx, ''); + if (!hasProtocol) hostname = `*.${hostname}`; + let path = pathRx.test(hostname) ? "" : "/*"; + let mp = `${protocol}${hostname}${path}`; + return validMatchPatternRx.test(mp) && (path ? mp : [mp, `${mp}?*`, `${mp}#*`]); + }; + + let siteKeys2MatchPatterns = keys => keys && flatten(keys.map(siteKey2MatchPattern)).filter(p => !!p) || []; + + var ChildPolicies = { + async update(policy) { + let serialized = policy.dry ? policy.dry(true) : policy; + let permsMap = new Map(); + let trusted = JSON.stringify(serialized.TRUSTED); + let untrusted = JSON.stringify(serialized.UNTRUSTED); + let presets = { + trusted, + untrusted, + temp: trusted + }; + // map presets to site keys + for (let [container, perms] of Object.entries(presets)) { + let newKeys = serialized.sites[container]; + if (!(newKeys && newKeys.length)) continue; + let keys = permsMap.get(perms); + if (keys) { + newKeys = keys.concat(newKeys); + } + permsMap.set(perms, newKeys); + } + // map custom permissions to site keys + for (let [key, perms] of Object.entries(serialized.sites.custom)) { + let permsKey = JSON.stringify(perms); + let keys = permsMap.get(permsKey); + if (keys) { + keys.push(key); + } else { + permsMap.set(permsKey, [key]); + } + } + + // compute exclusions + let permsMapEntries = [...permsMap]; + let excludeMap = new Map(); + for (let [perms, keys] of permsMapEntries) { + excludeMap.set(perms, siteKeys2MatchPatterns(flatten( + permsMapEntries.filter(([other]) => other !== perms) + .map(([otherPerms, otherKeys]) => otherKeys)) + .filter(k => k && k.includes("/")) + )); + } + + 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");`, + ["<all_urls>"]); + } + } +} diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js index fcd6fa7..703623f 100644 --- a/src/bg/RequestGuard.js +++ b/src/bg/RequestGuard.js @@ -437,22 +437,7 @@ var RequestGuard = (() => { blocker = CSP.createBlocker(...blockedTypes); } - if (canScript && !isObject) { - if (!capabilities.has("webgl")) { - RequestUtil.executeOnStart(request, { - file: "/content/webglHook.js" - }); - } - if (!capabilities.has("media")) { - RequestUtil.executeOnStart(request, { - code: "window.mediaBlocker = true;" - }); - } - - RequestUtil.executeOnStart(request, { - file: "/content/media.js" - }); - } else if (request.type === "main_frame" && !TabStatus.map.has(tabId)) { + if (request.type === "main_frame" && !TabStatus.map.has(tabId)) { debug("No TabStatus data yet for noscriptFrame", tabId); TabStatus.record(request, "noscriptFrame", true); } diff --git a/src/bg/main.js b/src/bg/main.js index 47ee89e..2eb2896 100644 --- a/src/bg/main.js +++ b/src/bg/main.js @@ -26,12 +26,14 @@ let policyData = (await Storage.get("sync", "policy")).policy; if (policyData && policyData.DEFAULT) { ns.policy = new Policy(policyData); + await ChildPolicies.update(policyData); } else { await include("/legacy/Legacy.js"); ns.policy = await Legacy.createOrMigratePolicy(); ns.savePolicy(); } - + + await include("/bg/defaults.js"); await ns.defaults; await include(["/bg/RequestGuard.js", "/bg/RequestUtil.js"]); @@ -226,6 +228,7 @@ async savePolicy() { if (this.policy) { + await ChildPolicies.update(this.policy); await Storage.set("sync", { policy: this.policy.dry() }); |