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/ChildPolicies.js | |
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/ChildPolicies.js')
-rw-r--r-- | src/bg/ChildPolicies.js | 111 |
1 files changed, 111 insertions, 0 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>"]); + } + } +} |