1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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>"]);
}
}
}
|