summaryrefslogtreecommitdiff
path: root/src/legacy/Legacy.js
blob: aeb076260326950e9f1247b681d3abd4a0882509 (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
'use strict';

var Legacy = {

  async init() {
    let migrated = (await browser.storage.local.get("legacyBackup")).legacyBackup;
    let real = await this.import(migrated);
    this.init = async () => real;
    return real;
  },

  async import(migrated) {
    if (this.migrated) this.undo = this.migrated;
    this.migrated = (migrated && migrated.prefs) ? migrated : {prefs: {}};
    await include("/legacy/defaults.js");
    return 'whitelist' in this.migrated; // "real" migration with custom policy
  },

  async persist() {
    await browser.storage.local.set({legacyBackup: this.migrated});
  },

  getPref(name, def) {
    return name in this.migrated.prefs ? this.migrated.prefs[name] : def;
  },

  getRxPref(name, parseRx = Legacy.RX.multi, flags, def) {
    let source = this.getPref(name, def);
    if (source instanceof RegExp) return source;
    try {
      return parseRx(source, flags);
    } catch (e) {
      error(e, "Parsing RegExp preference %s, falling back to %s", name, def);
      if (def) {
        if (def instanceof RegExp) {
          return def;
        }
        try {
          return parseRx(def, flags);
        } catch(e) {
          error(e);
        }
      }
    }
    return null;
  },

  async createOrMigratePolicy() {
    try {
      if (await this.init()) {
        return this.migratePolicy();
      }
    } catch (e) {
      error(e);
    }
    return new Policy();
  },

  extractLists(lists) {
    return lists.map(listString => listString.split(/\s+/))
    .map(sites => sites.filter(s => !(s.includes(":") &&
                                sites.includes(s.replace(/.*:\/*(?=\w)/g, ""))
                              )));
  },

  migratePolicy() {
    // here we normalize both NS whitelist and blacklist, getting finally rid of
    // the legacy of CAPS mandating protocols for top-level domains
    let [trusted, untrusted] = this.extractLists(
        [this.migrated.whitelist, this.getPref("untrusted", "")]);

    // securify default whitelist domain items
    if (this.getPref("httpsDefWhitelist")) {
      this.getPref("default", "").
        split(/\s+/).
        filter(s => !s.includes(":")).
        forEach(s => {
          let idx = trusted.indexOf(s);
          if (idx !== -1) {
            trusted[idx] = Sites.secureDomainKey(s);
          }
        });
    }

    let DEFAULT = new Permissions(["other"]);
    let {capabilities} = DEFAULT;
    // let's semplify object permissions now that almost everything is
    // either blacklisted or C2P by the browser
    if (!["Java", "Flash", "Silverlight", "Plugins"]
          .find(type => this.getPref(`forbid${type}`))) {
      capabilities.add("object");
    }

    let prefMap = {
      "Fonts": "font",
      "Frames": "frame",
      "IFrames": "frame",
      "Media": "media",
      "WebGL": "webgl",
    };
    for (let [legacy, current] of Object.entries(prefMap)) {
      if (!this.getPref(`forbid${legacy}`, true)) capabilities.add(current);
    }

    let TRUSTED = new Permissions(new Set(this.getPref("contentBlocker") ? capabilities : Permissions.ALL));
    TRUSTED.capabilities.add("script").add("fetch");

    let UNTRUSTED = new Permissions();
    if (this.getPref("global")) {
      if (!this.getPref("alwaysBlockUntrustedContent")) {
        UNTRUSTED.capabilities = new Set(capabilities);
      }
      DEFAULT = new Permissions(TRUSTED.capabilities);
    }

    return new Policy({
      sites: {untrusted, trusted, custom: {}},
      DEFAULT,
      TRUSTED,
      UNTRUSTED,
      enforced: true,
      // TODO: enforce these before ESR 59 gets released
      cascadePermissions: this.getPref("cascadePermissions"),
      restrictSubDocScripting: this.getPref("restrictSubDocScripting"),
      onlySecure: this.getPref("allowHttpsOnly")
    });

  },

  RX: {
    simple: function(s, flags) {
      var anchor = /\^/.test(flags);
      return new RegExp(anchor ? rxParsers.anchor(s) : s,
        anchor ? flags.replace(/\^/g, '') : flags);
    },
    anchor: function(s) {
      return /^\^|\$$/.test(s) ? s : "^" + s + "$";
    },
    multi: function(s, flags) {
      var anchor = /\^/.test(flags);
      var lines = s.split(anchor ? /\s+/ : /[\n\r]+/).filter(l => /\S/.test(l));
      return new RegExp((anchor ? lines.map(rxParsers.anchor) : lines).join('|'),
        anchor ? flags.replace(/\^/g, '') : flags);
    }
  }
}
Legacy.init();