summaryrefslogtreecommitdiff
path: root/src/bg/ChildPolicies.js
blob: fd790c913973d83c5692e3a574cdc0261d5be219 (plain)
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>"]);
    }
  }
}