tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

about_compat_broker.js (3727B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /* global browser, onMessageFromTab */
      8 
      9 class AboutCompatBroker {
     10  constructor(bindings) {
     11    this._interventions = bindings.interventions;
     12    this._shims = bindings.shims;
     13 
     14    if (!this._interventions && !this._shims) {
     15      throw new Error(
     16        "No interventions or shims; about:compat broker is not needed"
     17      );
     18    }
     19 
     20    this.portsToAboutCompatTabs = this.buildPorts();
     21    this._interventions?.bindAboutCompatBroker(this);
     22    this._shims?.bindAboutCompatBroker(this);
     23  }
     24 
     25  buildPorts() {
     26    const ports = new Set();
     27 
     28    browser.runtime.onConnect.addListener(port => {
     29      ports.add(port);
     30      port.onDisconnect.addListener(function () {
     31        ports.delete(port);
     32      });
     33    });
     34 
     35    async function broadcast(message) {
     36      for (const port of ports) {
     37        port.postMessage(message);
     38      }
     39    }
     40 
     41    return { broadcast };
     42  }
     43 
     44  filterInterventions(interventions) {
     45    return interventions
     46      .filter(intervention => intervention.availableOnPlatform)
     47      .map(intervention => {
     48        const { id, active, bugs, hidden } = intervention;
     49        let domain = intervention.label;
     50        let bug = Object.keys(bugs)[0];
     51        return { id, active, bug, domain, hidden };
     52      });
     53  }
     54 
     55  getInterventionById(id) {
     56    for (const [type, things] of Object.entries({
     57      interventions: this._interventions?.getAvailableInterventions() || [],
     58      shims: this._shims?.getAvailableShims() || [],
     59    })) {
     60      for (const what of things) {
     61        if (what.id === id) {
     62          return { type, what };
     63        }
     64      }
     65    }
     66    return {};
     67  }
     68 
     69  bootup() {
     70    onMessageFromTab(msg => {
     71      switch (msg.command || msg) {
     72        case "toggle": {
     73          const id = msg.id;
     74          const { type, what } = this.getInterventionById(id);
     75          if (!what) {
     76            return Promise.reject(`No such intervention to toggle: ${id}`);
     77          }
     78          const active = type === "shims" ? !what.disabledReason : what.active;
     79          this.portsToAboutCompatTabs
     80            .broadcast({ toggling: id, active })
     81            .then(async () => {
     82              switch (type) {
     83                case "interventions": {
     84                  if (active) {
     85                    await this._interventions?.disableIntervention(what);
     86                  } else {
     87                    await this._interventions?.enableIntervention(what, true);
     88                  }
     89                  break;
     90                }
     91                case "shims": {
     92                  if (active) {
     93                    await this._shims?.disableShimForSession(id);
     94                  } else {
     95                    await this._shims?.enableShimForSession(id);
     96                  }
     97                  // no need to broadcast the "toggled" signal for shims, as
     98                  // they send a shimsUpdated message themselves instead
     99                  return;
    100                }
    101              }
    102              this.portsToAboutCompatTabs.broadcast({
    103                toggled: id,
    104                active: !active,
    105              });
    106            });
    107          break;
    108        }
    109        case "getAllInterventions": {
    110          return Promise.resolve({
    111            interventions:
    112              (this._interventions?.isEnabled() &&
    113                this.filterInterventions(
    114                  this._interventions?.getAvailableInterventions()
    115                )) ||
    116              false,
    117            shims: this._shims?.getAvailableShims() || false,
    118          });
    119        }
    120      }
    121      return undefined;
    122    });
    123  }
    124 }