Remove ChildPolicies and its dependencies.

This commit is contained in:
hackademix 2019-09-27 15:33:11 +02:00
parent c9e06983ba
commit 78063f3412
6 changed files with 43 additions and 245 deletions

View File

@ -1,200 +0,0 @@
"use strict";
{
let marker = uuid();
let allUrls = ["<all_urls>"];
let Scripts = {
references: new Set(),
opts: {
js: [{file: "/content/dynamicNS.js"}, {}],
allFrames: true,
matchAboutBlank: true,
runAt: "document_start"
},
async init() {
this.init = this.forget;
},
forget() {
for (let script of [...this.references]) {
script.unregister();
this.references.delete(script);
}
},
debug: false,
trace(code) {
return this.debug
? `console.debug("Executing child policy on %s", document.URL, ${JSON.stringify(code)});${code}`
: code
;
},
async register(code, matches, excludeMatches) {
debug("Registering child policy.", code, matches, excludeMatches);
if (!matches.length) return;
try {
let opts = Object.assign({}, this.opts);
opts.js[1].code = this.trace(code);
opts.matches = matches;
if (excludeMatches && excludeMatches.length) {
opts.excludeMatches = excludeMatches;
}
this.references.add(await browser.contentScripts.register(opts));
} catch (e) {
error(e);
}
},
buildPerms(perms) {
if (typeof perms !== "string") {
perms = JSON.stringify(perms);
}
return `ns.setup(${perms}, "${marker}");`
}
};
let flatten = arr => arr.reduce((a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), []);
let protocolRx = /^(\w+):/i;
let portRx = /:\d+(?=\/|$)/;
let validMatchPatternRx = /^(?:\*|(?:http|ws|ftp)s?|file):\/\/(?:\*|(?:\*\.)?[\w\u0100-\uf000][\w\u0100-\uf000.-]*|\[[\w:]+\])?\/(\*|[^*]*)$/;
let validMatchPattern = mp => validMatchPatternRx.test(mp);
let siteKey2MatchPattern = site => {
let hasProtocol = site.match(protocolRx);
let mp = site;
if (hasProtocol) {
mp = Sites.cleanUrl(mp);
if (!mp) return false;
} else {
mp = Sites.isSecureDomainKey(site) ? "https://" : "*://";
let hostname = Sites.toggleSecureDomainKey(site, false).replace(portRx, '');
if (hostname && hostname !== ".") {
if (tld.isIp(hostname) || hostname.includes("*")) {
mp += hostname;
} else {
if (!tld.preserveFQDNs) hostname = tld.normalize(hostname);
mp += hostname.startsWith(".") ? `*${hostname}` : `*.${hostname}`;
}
} else {
mp += "*";
}
if (!(hostname && hostname.includes("/"))) mp += "/";
}
return validMatchPattern(mp) &&
(mp.endsWith("/") ? `${mp}*` : [mp, `${mp}?*`, `${mp}#*`]);
};
let withFQDNs = patterns => {
if (tld.preserveFQDNs) return patterns;
let rx = /^(?:\w+|\*):\/\/([^/]*[^.*/])/;
return patterns.concat(
patterns.map(p => p.replace(rx, (m, host) => tld.isIp(host) ? m : m + ".")
).filter(validMatchPattern)
);
};
let extraProtocols = patterns => patterns.concat(
patterns.filter(p => p.startsWith("*://"))
.map(p => p.replace("*", "ftp")));
let siteKeys2MatchPatterns = keys =>
keys ? [... new Set(
extraProtocols(withFQDNs(flatten(keys.map(siteKey2MatchPattern)).filter(p => !!p))))]
: [];
var ChildPolicies = {
addTabInfoCookie(request, info) {
let {tabId, frameId} = request;
let h = {
name: "Set-Cookie",
value: `${marker}_${tabId}_${frameId}=${JSON.stringify(info)}`
};
let {responseHeaders} = request;
if (responseHeaders.some(({value, name}) => h.value === value && h.name === name)) {
return false;
}
responseHeaders.push(h);
return true;
},
async update(policy, tracing) {
if (tracing !== "undefined") Scripts.debug = tracing;
let t0 = Date.now();
await Scripts.init();
if (!policy.enforced) {
await Scripts.register(Scripts.buildPerms("null"), allUrls);
return;
}
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("/") && keys.some(by => Sites.isImplied(k, by)))
));
}
// register new content scripts
let registering = [];
let allMatching = [];
for (let [perms, keys] of [...permsMap]) {
let match = siteKeys2MatchPatterns(keys);
allMatching.push(...match);
registering.push(Scripts.register(Scripts.buildPerms(perms), match, excludeMap.get(perms)));
}
registering.push(Scripts.register(Scripts.buildPerms(serialized.DEFAULT), allUrls, allMatching));
await Promise.all(registering);
if (tracing) {
debug("All the child policies registered in %sms", Date.now() - t0);
}
},
getForDocument(policy, url, context = null) {
return {
permissions: policy && policy.get(url, context).perms.dry(),
MARKER: marker
};
},
};
if (!browser.contentScripts) { // #chromium fallback
Scripts.register = ChildPolicies.update = () => {};
}
}

View File

@ -262,14 +262,11 @@ var RequestGuard = (() => {
}
function intersectCapabilities(perms, frameAncestors) {
if (frameAncestors && frameAncestors.length > 0 && ns.sync.cascadeRestrictions) {
if (frameAncestors && frameAncestors.length && ns.sync.cascadeRestrictions) {
// cascade top document's restrictions to subframes
let topUrl = frameAncestors[frameAncestors.length - 1].url;
let topPerms = ns.policy.get(topUrl, topUrl).perms;
if (topPerms !== perms) {
let topCaps = topPerms.capabilities;
return new Set([...perms.capabilities].filter(c => topCaps.has(c)));
}
perms = policy.cascadeRestrictions(perms,
frameAncestors[frameAncestors.length - 1].url)
.capabilities;
}
return perms.capabilities;
}
@ -347,20 +344,12 @@ var RequestGuard = (() => {
if (isMainFrame) {
if (policy.autoAllowTop && perms === policy.DEFAULT) {
policy.set(Sites.optimalKey(url), perms = policy.TRUSTED.tempTwin);
promises.push(ChildPolicies.update(policy));
}
capabilities = perms.capabilities;
} else {
capabilities = intersectCapabilities(perms, request.frameAncestors);
}
} else {
if (isMainFrame || type === "sub_frame") {
let unrestricted = ns.unrestrictedTabs.has(tabId) && {unrestricted: true};
if (unrestricted) {
headersModified = ChildPolicies.addTabInfoCookie(request, unrestricted);
}
}
}
} // else unrestricted, either globally or per-tab
if (isMainFrame && !TabStatus.map.has(tabId)) {
debug("No TabStatus data yet for noscriptFrame", tabId);
TabStatus.record(request, "noscriptFrame",

View File

@ -28,7 +28,6 @@
let policyData = (await Storage.get("sync", "policy")).policy;
if (policyData && policyData.DEFAULT) {
ns.policy = new Policy(policyData);
await ChildPolicies.update(policyData, ns.local.debug);
} else {
await include("/legacy/Legacy.js");
ns.policy = await Legacy.createOrMigratePolicy();
@ -141,11 +140,25 @@
return await Settings.import(data);
},
async fetchChildPolicy({url, contextUrl}, sender) {
let {tab} = sender;
fetchChildPolicy({url, contextUrl}, sender) {
if (!url) url = sender.url;
let policy = !Sites.isInternal(url) && ns.isEnforced(tab.id) ? ns.policy : null;
return ChildPolicies.getForDocument(policy, url, contextUrl || tab.url);
let {tab} = sender;
let tabUrl = tab.url;
if (!contextUrl) contextUrl = tabUrl;
let policy = !Sites.isInternal(url) && ns.isEnforced(tab.id)
? ns.policy : null;
let permissions = Permissions.ALL;
if (policy) {
let perms = policy.get(url, contextUrl).perms;
if (tabUrl && ns.sync.cascadeRestrictions) {
perms = policy.cascadeRestrictions(perms, tabUrl);
}
permissions = perms.dry();
} // otherwise either internal URL or unrestricted
return {permissions};
},
async openStandalonePopup() {
@ -170,7 +183,13 @@
},
};
function onSyncMessage(msg, sender) {
switch(msg.id) {
case "fetchPolicy":
return messageHandler.fetchChildPolicy(msg, sender);
break;
}
}
var ns = {
running: false,
@ -190,6 +209,8 @@
if (this.running) return;
this.running = true;
browser.runtime.onSyncMessage.addListener(onSyncMessage);
deferWebTraffic(init(),
async () => {
Commands.install();
@ -208,6 +229,7 @@
stop() {
if (!this.running) return;
this.running = false;
browser.runtime.onSyncMessage.removeListener(onSyncMessage);
Messages.removeHandler(messageHandler);
RequestGuard.stop();
log("STOPPED");
@ -215,7 +237,6 @@
async savePolicy() {
if (this.policy) {
await ChildPolicies.update(this.policy, this.local.debug);
await Storage.set("sync", {
policy: this.policy.dry()
});

View File

@ -451,6 +451,16 @@ var {Permissions, Policy, Sites} = (() => {
return JSON.stringify(this.dry(true));
}
cascadeRestrictions(perms, topUrl) {
let topPerms = ns.policy.get(topUrl, topUrl).perms;
if (topPerms !== perms) {
let topCaps = topPerms.capabilities;
perms = new Permissions([...perms.capabilities].filter(c => topCaps.has(c)),
perms.temp, perms.contextual);
}
return perms;
}
equals(other) {
this.snapshot === other.snapshot;
}

View File

@ -1,21 +0,0 @@
'use strict';
// ensure the order which manifest scripts and dynamically registered scripts
// are executed in doesn't matter for initialization, by using a stub.
if (!this.ns) {
let deferredSetup = null;
let nsStub = this.ns = {
config: {},
setup(permissions, MARKER) {
deferredSetup = [permissions, MARKER];
},
merge: ns => {
ns.config = Object.assign(ns.config, nsStub.config);
this.ns = ns;
if (deferredSetup) {
ns.setup(...deferredSetup);
}
}
}
}

View File

@ -57,7 +57,6 @@
"xss/XSS.js",
"bg/ReportingCSP.js",
"bg/deferWebTraffic.js",
"bg/ChildPolicies.js",
"bg/Defaults.js",
"bg/RequestGuard.js",
"bg/Settings.js",