summaryrefslogtreecommitdiff
path: root/src/bg
diff options
context:
space:
mode:
Diffstat (limited to 'src/bg')
-rw-r--r--src/bg/ChildPolicies.js200
-rw-r--r--src/bg/RequestGuard.js21
-rw-r--r--src/bg/main.js35
3 files changed, 33 insertions, 223 deletions
diff --git a/src/bg/ChildPolicies.js b/src/bg/ChildPolicies.js
deleted file mode 100644
index 58b18ca..0000000
--- a/src/bg/ChildPolicies.js
+++ /dev/null
@@ -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 = () => {};
- }
-
-}
diff --git a/src/bg/RequestGuard.js b/src/bg/RequestGuard.js
index f636f23..0de52f4 100644
--- a/src/bg/RequestGuard.js
+++ b/src/bg/RequestGuard.js
@@ -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",
diff --git a/src/bg/main.js b/src/bg/main.js
index 5d4f79f..ed53603 100644
--- a/src/bg/main.js
+++ b/src/bg/main.js
@@ -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()
});