tor-browser

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

connection.js (15276B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 /* import-globals-from /browser/base/content/utilityOverlay.js */
      7 /* import-globals-from /toolkit/content/preferencesBindings.js */
      8 /* import-globals-from ../extensionControlled.js */
      9 
     10 const proxyService = Ci.nsIProtocolProxyService;
     11 
     12 const PROXY_TYPES_MAP_REVERSE = new Map([
     13  [proxyService.PROXYCONFIG_DIRECT, "DIRECT"],
     14  [proxyService.PROXYCONFIG_MANUAL, "MANUAL"],
     15  [proxyService.PROXYCONFIG_PAC, "PAC"],
     16  [proxyService.PROXYCONFIG_WPAD, "WPAD"],
     17  [proxyService.PROXYCONFIG_SYSTEM, "SYSTEM"],
     18 ]);
     19 
     20 Preferences.addAll([
     21  // Add network.proxy.autoconfig_url before network.proxy.type so they're
     22  // both initialized when network.proxy.type initialization triggers a call to
     23  // gConnectionsDialog.updateReloadButton().
     24  { id: "network.proxy.autoconfig_url", type: "string" },
     25  { id: "network.proxy.system_wpad", type: "bool" },
     26  { id: "network.proxy.type", type: "int" },
     27  { id: "network.proxy.http", type: "string" },
     28  { id: "network.proxy.http_port", type: "int" },
     29  { id: "network.proxy.ssl", type: "string" },
     30  { id: "network.proxy.ssl_port", type: "int" },
     31  { id: "network.proxy.socks", type: "string" },
     32  { id: "network.proxy.socks_port", type: "int" },
     33  { id: "network.proxy.socks_version", type: "int" },
     34  { id: "network.proxy.socks_remote_dns", type: "bool" },
     35  { id: "network.proxy.socks5_remote_dns", type: "bool" },
     36  { id: "network.proxy.no_proxies_on", type: "string" },
     37  { id: "network.proxy.share_proxy_settings", type: "bool" },
     38  { id: "signon.autologin.proxy", type: "bool" },
     39  { id: "pref.advanced.proxies.disable_button.reload", type: "bool" },
     40  { id: "network.proxy.backup.ssl", type: "string" },
     41  { id: "network.proxy.backup.ssl_port", type: "int" },
     42 ]);
     43 
     44 window.addEventListener(
     45  "DOMContentLoaded",
     46  () => {
     47    Preferences.get("network.proxy.type").on(
     48      "change",
     49      gConnectionsDialog.proxyTypeChanged.bind(gConnectionsDialog)
     50    );
     51    Preferences.get("network.proxy.socks_version").on(
     52      "change",
     53      gConnectionsDialog.updateDNSPref.bind(gConnectionsDialog)
     54    );
     55 
     56    document
     57      .getElementById("key_close")
     58      .addEventListener("command", event => Preferences.close(event));
     59 
     60    document
     61      .getElementById("disableProxyExtension")
     62      .addEventListener(
     63        "command",
     64        makeDisableControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).bind(
     65          gConnectionsDialog
     66        )
     67      );
     68    document
     69      .getElementById("networkProxyAutoconfigURL")
     70      .addEventListener("input", () => gConnectionsDialog.updateReloadButton());
     71    document
     72      .getElementById("autoReload")
     73      .addEventListener("command", () => gConnectionsDialog.reloadPAC());
     74 
     75    gConnectionsDialog.checkForSystemProxy();
     76    gConnectionsDialog.updateProxySettingsUI();
     77    initializeProxyUI(gConnectionsDialog);
     78    gConnectionsDialog.registerSyncPrefListeners();
     79    document
     80      .getElementById("ConnectionsDialog")
     81      .addEventListener("beforeaccept", e =>
     82        gConnectionsDialog.beforeAccept(e)
     83      );
     84  },
     85  { once: true, capture: true }
     86 );
     87 
     88 var gConnectionsDialog = {
     89  beforeAccept(event) {
     90    var proxyTypePref = Preferences.get("network.proxy.type");
     91 
     92    // collect "network.proxy.type" to glean metrics
     93    let proxyTypePrefStr =
     94      PROXY_TYPES_MAP_REVERSE.get(proxyTypePref.value) || "OTHER";
     95    Glean.networkProxySettings.proxyTypePreference.record({
     96      value: proxyTypePrefStr,
     97    });
     98 
     99    if (proxyTypePref.value == 2) {
    100      this.doAutoconfigURLFixup();
    101      return;
    102    }
    103 
    104    if (proxyTypePref.value != 1) {
    105      return;
    106    }
    107 
    108    var httpProxyURLPref = Preferences.get("network.proxy.http");
    109    var httpProxyPortPref = Preferences.get("network.proxy.http_port");
    110    var shareProxiesPref = Preferences.get(
    111      "network.proxy.share_proxy_settings"
    112    );
    113 
    114    // If the proxy server (when specified) is invalid or the port is set to 0 then cancel submission.
    115    for (let prefName of ["http", "ssl", "socks"]) {
    116      let proxyPortPref = Preferences.get(
    117        "network.proxy." + prefName + "_port"
    118      );
    119      let proxyPref = Preferences.get("network.proxy." + prefName);
    120      // Only worry about ports which are currently active. If the share option is on, then ignore
    121      // all ports except the HTTP and SOCKS port
    122      if (
    123        proxyPref.value != "" &&
    124        (prefName == "http" || prefName == "socks" || !shareProxiesPref.value)
    125      ) {
    126        if (proxyPortPref.value == 0) {
    127          document
    128            .getElementById("networkProxy" + prefName.toUpperCase() + "_Port")
    129            .focus();
    130          event.preventDefault();
    131          return;
    132        } else if (!Services.io.isValidHostname(proxyPref.value)) {
    133          document
    134            .getElementById("networkProxy" + prefName.toUpperCase())
    135            .focus();
    136          event.preventDefault();
    137          return;
    138        }
    139      }
    140    }
    141 
    142    // In the case of a shared proxy preference, backup the current values and update with the HTTP value
    143    if (shareProxiesPref.value) {
    144      var proxyServerURLPref = Preferences.get("network.proxy.ssl");
    145      var proxyPortPref = Preferences.get("network.proxy.ssl_port");
    146      var backupServerURLPref = Preferences.get("network.proxy.backup.ssl");
    147      var backupPortPref = Preferences.get("network.proxy.backup.ssl_port");
    148      backupServerURLPref.value =
    149        backupServerURLPref.value || proxyServerURLPref.value;
    150      backupPortPref.value = backupPortPref.value || proxyPortPref.value;
    151      proxyServerURLPref.value = httpProxyURLPref.value;
    152      proxyPortPref.value = httpProxyPortPref.value;
    153    }
    154 
    155    this.sanitizeNoProxiesPref();
    156  },
    157 
    158  checkForSystemProxy() {
    159    if ("@mozilla.org/system-proxy-settings;1" in Cc) {
    160      document.getElementById("systemPref").removeAttribute("hidden");
    161 
    162      var systemWpadAllowed = Services.prefs.getBoolPref(
    163        "network.proxy.system_wpad.allowed",
    164        false
    165      );
    166      if (systemWpadAllowed && AppConstants.platform == "win") {
    167        document.getElementById("systemWpad").removeAttribute("hidden");
    168      }
    169    }
    170  },
    171 
    172  proxyTypeChanged() {
    173    var proxyTypePref = Preferences.get("network.proxy.type");
    174    var systemWpadPref = Preferences.get("network.proxy.system_wpad");
    175    systemWpadPref.updateControlDisabledState(proxyTypePref.value != 5);
    176 
    177    // Update http
    178    var httpProxyURLPref = Preferences.get("network.proxy.http");
    179    httpProxyURLPref.updateControlDisabledState(proxyTypePref.value != 1);
    180    var httpProxyPortPref = Preferences.get("network.proxy.http_port");
    181    httpProxyPortPref.updateControlDisabledState(proxyTypePref.value != 1);
    182 
    183    // Now update the other protocols
    184    this.updateProtocolPrefs();
    185 
    186    var shareProxiesPref = Preferences.get(
    187      "network.proxy.share_proxy_settings"
    188    );
    189    shareProxiesPref.updateControlDisabledState(proxyTypePref.value != 1);
    190    var autologinProxyPref = Preferences.get("signon.autologin.proxy");
    191    autologinProxyPref.updateControlDisabledState(proxyTypePref.value == 0);
    192    var noProxiesPref = Preferences.get("network.proxy.no_proxies_on");
    193    noProxiesPref.updateControlDisabledState(proxyTypePref.value == 0);
    194 
    195    var autoconfigURLPref = Preferences.get("network.proxy.autoconfig_url");
    196    autoconfigURLPref.updateControlDisabledState(proxyTypePref.value != 2);
    197 
    198    this.updateReloadButton();
    199 
    200    document.getElementById("networkProxyNoneLocalhost").hidden =
    201      Services.prefs.getBoolPref(
    202        "network.proxy.allow_hijacking_localhost",
    203        false
    204      );
    205  },
    206 
    207  updateDNSPref() {
    208    var socksVersionPref = Preferences.get("network.proxy.socks_version");
    209    var socks4DNSPref = Preferences.get("network.proxy.socks_remote_dns");
    210    var socks5DNSPref = Preferences.get("network.proxy.socks5_remote_dns");
    211    var proxyTypePref = Preferences.get("network.proxy.type");
    212    var isDefinitelySocks4 =
    213      proxyTypePref.value == 1 && socksVersionPref.value == 4;
    214    socks5DNSPref.updateControlDisabledState(
    215      isDefinitelySocks4 || proxyTypePref.value == 0
    216    );
    217    var isDefinitelySocks5 =
    218      proxyTypePref.value == 1 && socksVersionPref.value == 5;
    219    socks4DNSPref.updateControlDisabledState(
    220      isDefinitelySocks5 || proxyTypePref.value == 0
    221    );
    222    return undefined;
    223  },
    224 
    225  updateReloadButton() {
    226    // Disable the "Reload PAC" button if the selected proxy type is not PAC or
    227    // if the current value of the PAC input does not match the value stored
    228    // in prefs.  Likewise, disable the reload button if PAC is not configured
    229    // in prefs.
    230 
    231    var typedURL = document.getElementById("networkProxyAutoconfigURL").value;
    232    var proxyTypeCur = Preferences.get("network.proxy.type").value;
    233 
    234    var pacURL = Services.prefs.getCharPref("network.proxy.autoconfig_url");
    235    var proxyType = Services.prefs.getIntPref("network.proxy.type");
    236 
    237    var disableReloadPref = Preferences.get(
    238      "pref.advanced.proxies.disable_button.reload"
    239    );
    240    disableReloadPref.updateControlDisabledState(
    241      proxyTypeCur != 2 || proxyType != 2 || typedURL != pacURL
    242    );
    243  },
    244 
    245  readProxyType() {
    246    this.proxyTypeChanged();
    247    return undefined;
    248  },
    249 
    250  updateProtocolPrefs() {
    251    var proxyTypePref = Preferences.get("network.proxy.type");
    252    var shareProxiesPref = Preferences.get(
    253      "network.proxy.share_proxy_settings"
    254    );
    255    var proxyPrefs = ["ssl", "socks"];
    256    for (var i = 0; i < proxyPrefs.length; ++i) {
    257      var proxyServerURLPref = Preferences.get(
    258        "network.proxy." + proxyPrefs[i]
    259      );
    260      var proxyPortPref = Preferences.get(
    261        "network.proxy." + proxyPrefs[i] + "_port"
    262      );
    263 
    264      // Restore previous per-proxy custom settings, if present.
    265      if (proxyPrefs[i] != "socks" && !shareProxiesPref.value) {
    266        var backupServerURLPref = Preferences.get(
    267          "network.proxy.backup." + proxyPrefs[i]
    268        );
    269        var backupPortPref = Preferences.get(
    270          "network.proxy.backup." + proxyPrefs[i] + "_port"
    271        );
    272        if (backupServerURLPref.hasUserValue) {
    273          proxyServerURLPref.value = backupServerURLPref.value;
    274          backupServerURLPref.reset();
    275        }
    276        if (backupPortPref.hasUserValue) {
    277          proxyPortPref.value = backupPortPref.value;
    278          backupPortPref.reset();
    279        }
    280      }
    281 
    282      proxyServerURLPref.updateElements();
    283      proxyPortPref.updateElements();
    284      let prefIsShared = proxyPrefs[i] != "socks" && shareProxiesPref.value;
    285      proxyServerURLPref.updateControlDisabledState(
    286        proxyTypePref.value != 1 || prefIsShared
    287      );
    288      proxyPortPref.updateControlDisabledState(
    289        proxyTypePref.value != 1 || prefIsShared
    290      );
    291    }
    292    var socksVersionPref = Preferences.get("network.proxy.socks_version");
    293    socksVersionPref.updateControlDisabledState(proxyTypePref.value != 1);
    294    this.updateDNSPref();
    295    return undefined;
    296  },
    297 
    298  readProxyProtocolPref(aProtocol, aIsPort) {
    299    if (aProtocol != "socks") {
    300      var shareProxiesPref = Preferences.get(
    301        "network.proxy.share_proxy_settings"
    302      );
    303      if (shareProxiesPref.value) {
    304        var pref = Preferences.get(
    305          "network.proxy.http" + (aIsPort ? "_port" : "")
    306        );
    307        return pref.value;
    308      }
    309 
    310      var backupPref = Preferences.get(
    311        "network.proxy.backup." + aProtocol + (aIsPort ? "_port" : "")
    312      );
    313      return backupPref.hasUserValue ? backupPref.value : undefined;
    314    }
    315    return undefined;
    316  },
    317 
    318  reloadPAC() {
    319    Cc["@mozilla.org/network/protocol-proxy-service;1"]
    320      .getService()
    321      .reloadPAC();
    322  },
    323 
    324  doAutoconfigURLFixup() {
    325    var autoURL = document.getElementById("networkProxyAutoconfigURL");
    326    var autoURLPref = Preferences.get("network.proxy.autoconfig_url");
    327    try {
    328      autoURLPref.value = autoURL.value = Services.uriFixup.getFixupURIInfo(
    329        autoURL.value
    330      ).preferredURI.spec;
    331    } catch (ex) {}
    332  },
    333 
    334  sanitizeNoProxiesPref() {
    335    var noProxiesPref = Preferences.get("network.proxy.no_proxies_on");
    336    // replace substrings of ; and \n with commas if they're neither immediately
    337    // preceded nor followed by a valid separator character
    338    noProxiesPref.value = noProxiesPref.value.replace(
    339      /([^, \n;])[;\n]+(?![,\n;])/g,
    340      "$1,"
    341    );
    342    // replace any remaining ; and \n since some may follow commas, etc.
    343    noProxiesPref.value = noProxiesPref.value.replace(/[;\n]/g, "");
    344  },
    345 
    346  readHTTPProxyServer() {
    347    var shareProxiesPref = Preferences.get(
    348      "network.proxy.share_proxy_settings"
    349    );
    350    if (shareProxiesPref.value) {
    351      this.updateProtocolPrefs();
    352    }
    353    return undefined;
    354  },
    355 
    356  readHTTPProxyPort() {
    357    var shareProxiesPref = Preferences.get(
    358      "network.proxy.share_proxy_settings"
    359    );
    360    if (shareProxiesPref.value) {
    361      this.updateProtocolPrefs();
    362    }
    363    return undefined;
    364  },
    365 
    366  getProxyControls() {
    367    let controlGroup = document.getElementById("networkProxyType");
    368    return [
    369      ...controlGroup.querySelectorAll(":scope > radio"),
    370      ...controlGroup.querySelectorAll("label"),
    371      ...controlGroup.querySelectorAll("input"),
    372      ...controlGroup.querySelectorAll("checkbox"),
    373      ...document.querySelectorAll("#networkProxySOCKSVersion > radio"),
    374      ...document.querySelectorAll("#ConnectionsDialogPane > checkbox"),
    375    ];
    376  },
    377 
    378  // Update the UI to show/hide the extension controlled message for
    379  // proxy settings.
    380  async updateProxySettingsUI() {
    381    let isLocked = API_PROXY_PREFS.some(pref =>
    382      Services.prefs.prefIsLocked(pref)
    383    );
    384 
    385    function setInputsDisabledState(isControlled) {
    386      for (let element of gConnectionsDialog.getProxyControls()) {
    387        element.disabled = isControlled;
    388      }
    389      gConnectionsDialog.proxyTypeChanged();
    390    }
    391 
    392    if (isLocked) {
    393      // An extension can't control this setting if any pref is locked.
    394      hideControllingExtension(PROXY_KEY);
    395    } else {
    396      handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY).then(
    397        setInputsDisabledState
    398      );
    399    }
    400  },
    401 
    402  registerSyncPrefListeners() {
    403    function setSyncFromPrefListener(element_id, callback) {
    404      Preferences.addSyncFromPrefListener(
    405        document.getElementById(element_id),
    406        callback
    407      );
    408    }
    409    setSyncFromPrefListener("networkProxyType", () => this.readProxyType());
    410    setSyncFromPrefListener("networkProxyHTTP", () =>
    411      this.readHTTPProxyServer()
    412    );
    413    setSyncFromPrefListener("networkProxyHTTP_Port", () =>
    414      this.readHTTPProxyPort()
    415    );
    416    setSyncFromPrefListener("shareAllProxies", () =>
    417      this.updateProtocolPrefs()
    418    );
    419    setSyncFromPrefListener("networkProxySSL", () =>
    420      this.readProxyProtocolPref("ssl", false)
    421    );
    422    setSyncFromPrefListener("networkProxySSL_Port", () =>
    423      this.readProxyProtocolPref("ssl", true)
    424    );
    425    setSyncFromPrefListener("networkProxySOCKS", () =>
    426      this.readProxyProtocolPref("socks", false)
    427    );
    428    setSyncFromPrefListener("networkProxySOCKS_Port", () =>
    429      this.readProxyProtocolPref("socks", true)
    430    );
    431  },
    432 };