Pier Angelo Vendrame pushed to branch tor-browser-115.1.0esr-13.0-1 at The Tor Project / Applications / Tor Browser
Commits:
- 
c3d2496b
by Pier Angelo Vendrame at 2023-07-27T21:07:52+02:00
- 
642df684
by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
- 
9e825b61
by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
- 
8061f810
by Pier Angelo Vendrame at 2023-07-27T21:07:53+02:00
- 
f5a3f4af
by Pier Angelo Vendrame at 2023-07-27T21:07:54+02:00
- 
71b08c4e
by Pier Angelo Vendrame at 2023-07-27T21:07:54+02:00
- 
e1a69b4e
by Pier Angelo Vendrame at 2023-07-27T21:07:55+02:00
- 
d457b6f8
by Pier Angelo Vendrame at 2023-07-31T20:42:54+02:00
- 
c4e8cd0f
by Pier Angelo Vendrame at 2023-07-31T20:42:57+02:00
13 changed files:
- browser/components/torpreferences/content/connectionPane.js
- browser/installer/package-manifest.in
- browser/modules/TorStrings.jsm
- toolkit/components/tor-launcher/TorLauncherUtil.sys.mjs
- toolkit/components/tor-launcher/TorMonitorService.sys.mjs
- toolkit/components/tor-launcher/TorParsers.sys.mjs
- toolkit/components/tor-launcher/TorProcess.sys.mjs
- toolkit/components/tor-launcher/TorProtocolService.sys.mjs
- toolkit/torbutton/chrome/content/torbutton.js
- toolkit/torbutton/components.conf
- − toolkit/torbutton/modules/TorbuttonStartupObserver.jsm
- toolkit/torbutton/moz.build
- − toolkit/torbutton/torbutton.manifest
Changes:
| ... | ... | @@ -14,8 +14,11 @@ const { setTimeout, clearTimeout } = ChromeUtils.import( | 
| 14 | 14 |  const { TorSettings, TorSettingsTopics, TorSettingsData, TorBridgeSource } =
 | 
| 15 | 15 |    ChromeUtils.import("resource:///modules/TorSettings.jsm");
 | 
| 16 | 16 | |
| 17 | -const { TorProtocolService } = ChromeUtils.import(
 | |
| 18 | -  "resource://gre/modules/TorProtocolService.jsm"
 | |
| 17 | +const { TorParsers } = ChromeUtils.importESModule(
 | |
| 18 | +  "resource://gre/modules/TorParsers.sys.mjs"
 | |
| 19 | +);
 | |
| 20 | +const { TorProtocolService } = ChromeUtils.importESModule(
 | |
| 21 | +  "resource://gre/modules/TorProtocolService.sys.mjs"
 | |
| 19 | 22 |  );
 | 
| 20 | 23 |  const { TorMonitorService, TorMonitorTopics } = ChromeUtils.import(
 | 
| 21 | 24 |    "resource://gre/modules/TorMonitorService.jsm"
 | 
| ... | ... | @@ -495,7 +498,7 @@ const gConnectionPane = (function () { | 
| 495 | 498 |          });
 | 
| 496 | 499 |          const idString = TorStrings.settings.bridgeId;
 | 
| 497 | 500 |          const id = card.querySelector(selectors.bridges.cardId);
 | 
| 498 | -        const details = parseBridgeLine(bridgeString);
 | |
| 501 | +        const details = TorParsers.parseBridgeLine(bridgeString);
 | |
| 499 | 502 |          if (details && details.id !== undefined) {
 | 
| 500 | 503 |            card.setAttribute("data-bridge-id", details.id);
 | 
| 501 | 504 |          }
 | 
| ... | ... | @@ -1111,23 +1114,3 @@ function makeBridgeId(bridgeString) { | 
| 1111 | 1114 |      hash & 0x000000ff,
 | 
| 1112 | 1115 |    ];
 | 
| 1113 | 1116 |  } | 
| 1114 | - | |
| 1115 | -function parseBridgeLine(line) {
 | |
| 1116 | -  const re =
 | |
| 1117 | -    /^\s*(\S+\s+)?([0-9a-fA-F\.\[\]\:]+:\d{1,5})(\s+[0-9a-fA-F]{40})?(\s+.+)?/;
 | |
| 1118 | -  const matches = line.match(re);
 | |
| 1119 | -  if (!matches) {
 | |
| 1120 | -    return null;
 | |
| 1121 | -  }
 | |
| 1122 | -  let bridge = { addr: matches[2] };
 | |
| 1123 | -  if (matches[1] !== undefined) {
 | |
| 1124 | -    bridge.transport = matches[1].trim();
 | |
| 1125 | -  }
 | |
| 1126 | -  if (matches[3] !== undefined) {
 | |
| 1127 | -    bridge.id = matches[3].trim().toUpperCase();
 | |
| 1128 | -  }
 | |
| 1129 | -  if (matches[4] !== undefined) {
 | |
| 1130 | -    bridge.args = matches[4].trim();
 | |
| 1131 | -  }
 | |
| 1132 | -  return bridge;
 | |
| 1133 | -} | 
| ... | ... | @@ -228,7 +228,6 @@ | 
| 228 | 228 |  @RESPATH@/components/tor-launcher.manifest
 | 
| 229 | 229 |  @RESPATH@/chrome/torbutton.manifest
 | 
| 230 | 230 |  @RESPATH@/chrome/torbutton/*
 | 
| 231 | -@RESPATH@/components/torbutton.manifest
 | |
| 232 | 231 |  @RESPATH@/chrome/toolkit@JAREXT@
 | 
| 233 | 232 |  @RESPATH@/chrome/toolkit.manifest
 | 
| 234 | 233 |  #ifdef MOZ_GTK
 | 
| ... | ... | @@ -11,9 +11,11 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); | 
| 11 | 11 |  const { AppConstants } = ChromeUtils.import(
 | 
| 12 | 12 |    "resource://gre/modules/AppConstants.jsm"
 | 
| 13 | 13 |  );
 | 
| 14 | -const { getLocale } = ChromeUtils.import(
 | |
| 15 | -  "resource://torbutton/modules/utils.js"
 | |
| 16 | -);
 | |
| 14 | + | |
| 15 | +function getLocale() {
 | |
| 16 | +  const locale = Services.locale.appLocaleAsBCP47;
 | |
| 17 | +  return locale === "ja-JP-macos" ? "ja" : locale;
 | |
| 18 | +}
 | |
| 17 | 19 | |
| 18 | 20 |  /*
 | 
| 19 | 21 |    Tor Property String Bundle
 | 
| ... | ... | @@ -5,6 +5,12 @@ | 
| 5 | 5 |   * Tor Launcher Util JS Module
 | 
| 6 | 6 |   *************************************************************************/
 | 
| 7 | 7 | |
| 8 | +const lazy = {};
 | |
| 9 | + | |
| 10 | +ChromeUtils.defineESModuleGetters(lazy, {
 | |
| 11 | +  FileUtils: "resource://gre/modules/FileUtils.sys.jsm",
 | |
| 12 | +});
 | |
| 13 | + | |
| 8 | 14 |  const kPropBundleURI = "chrome://torbutton/locale/torlauncher.properties";
 | 
| 9 | 15 |  const kPropNamePrefix = "torlauncher.";
 | 
| 10 | 16 |  const kIPCDirPrefName = "extensions.torlauncher.tmp_ipc_dir";
 | 
| ... | ... | @@ -209,14 +215,15 @@ class TorFile { | 
| 209 | 215 |    // and return a file object. The control and SOCKS IPC objects will be
 | 
| 210 | 216 |    // created by tor.
 | 
| 211 | 217 |    normalize() {
 | 
| 212 | -    if (!this.file.exists() && !this.isIPC) {
 | |
| 218 | +    if (this.file.exists()) {
 | |
| 219 | +      try {
 | |
| 220 | +        this.file.normalize();
 | |
| 221 | +      } catch (e) {
 | |
| 222 | +        console.warn("Normalization of the path failed", e);
 | |
| 223 | +      }
 | |
| 224 | +    } else if (!this.isIPC) {
 | |
| 213 | 225 |        throw new Error(`${this.fileType} file not found: ${this.file.path}`);
 | 
| 214 | 226 |      }
 | 
| 215 | -    try {
 | |
| 216 | -      this.file.normalize();
 | |
| 217 | -    } catch (e) {
 | |
| 218 | -      console.warn("Normalization of the path failed", e);
 | |
| 219 | -    }
 | |
| 220 | 227 | |
| 221 | 228 |      // Ensure that the IPC path length is short enough for use by the
 | 
| 222 | 229 |      // operating system. If not, create and use a unique directory under
 | 
| ... | ... | @@ -452,6 +459,154 @@ export const TorLauncherUtil = Object.freeze({ | 
| 452 | 459 |      return result ? result : "";
 | 
| 453 | 460 |    },
 | 
| 454 | 461 | |
| 462 | +  /**
 | |
| 463 | +   * Determine what kind of SOCKS port has been requested for this session or
 | |
| 464 | +   * the browser has been configured for.
 | |
| 465 | +   * On Windows (where Unix domain sockets are not supported), TCP is always
 | |
| 466 | +   * used.
 | |
| 467 | +   *
 | |
| 468 | +   * The following environment variables are supported and take precedence over
 | |
| 469 | +   * preferences:
 | |
| 470 | +   *    TOR_TRANSPROXY (do not use a proxy)
 | |
| 471 | +   *    TOR_SOCKS_IPC_PATH (file system path; ignored on Windows)
 | |
| 472 | +   *    TOR_SOCKS_HOST
 | |
| 473 | +   *    TOR_SOCKS_PORT
 | |
| 474 | +   *
 | |
| 475 | +   * The following preferences are consulted:
 | |
| 476 | +   *    network.proxy.socks
 | |
| 477 | +   *    network.proxy.socks_port
 | |
| 478 | +   *    extensions.torlauncher.socks_port_use_ipc (Boolean)
 | |
| 479 | +   *    extensions.torlauncher.socks_ipc_path (file system path)
 | |
| 480 | +   * If extensions.torlauncher.socks_ipc_path is empty, a default path is used.
 | |
| 481 | +   *
 | |
| 482 | +   * When using TCP, if a value is not defined via an env variable it is
 | |
| 483 | +   * taken from the corresponding browser preference if possible. The
 | |
| 484 | +   * exceptions are:
 | |
| 485 | +   *   If network.proxy.socks contains a file: URL, a default value of
 | |
| 486 | +   *     "127.0.0.1" is used instead.
 | |
| 487 | +   *   If the network.proxy.socks_port value is not valid (outside the
 | |
| 488 | +   *     (0; 65535] range), a default value of 9150 is used instead.
 | |
| 489 | +   *
 | |
| 490 | +   * The SOCKS configuration will not influence the launch of a tor daemon and
 | |
| 491 | +   * the configuration of the control port in any way.
 | |
| 492 | +   * When a SOCKS configuration is required without TOR_SKIP_LAUNCH, the browser
 | |
| 493 | +   * will try to configure the tor instance to use the required configuration.
 | |
| 494 | +   * This also applies to TOR_TRANSPROXY (at least for now): tor will be
 | |
| 495 | +   * launched with its defaults.
 | |
| 496 | +   *
 | |
| 497 | +   * TODO: add a preference to ignore the current configuration, and let tor
 | |
| 498 | +   * listen on any free port. Then, the browser will prompt the daemon the port
 | |
| 499 | +   * to use through the control port (even though this is quite dangerous at the
 | |
| 500 | +   * moment, because with network disabled tor will disable also the SOCKS
 | |
| 501 | +   * listeners, so it means that we will have to check it every time we change
 | |
| 502 | +   * the network status).
 | |
| 503 | +   */
 | |
| 504 | +  getPreferredSocksConfiguration() {
 | |
| 505 | +    if (Services.env.exists("TOR_TRANSPROXY")) {
 | |
| 506 | +      Services.prefs.setBoolPref("network.proxy.socks_remote_dns", false);
 | |
| 507 | +      Services.prefs.setIntPref("network.proxy.type", 0);
 | |
| 508 | +      Services.prefs.setIntPref("network.proxy.socks_port", 0);
 | |
| 509 | +      Services.prefs.setCharPref("network.proxy.socks", "");
 | |
| 510 | +      return { transproxy: true };
 | |
| 511 | +    }
 | |
| 512 | + | |
| 513 | +    let useIPC;
 | |
| 514 | +    const socksPortInfo = {
 | |
| 515 | +      transproxy: false,
 | |
| 516 | +    };
 | |
| 517 | + | |
| 518 | +    if (!this.isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
 | |
| 519 | +      useIPC = true;
 | |
| 520 | +      const ipcPath = Services.env.get("TOR_SOCKS_IPC_PATH");
 | |
| 521 | +      if (ipcPath) {
 | |
| 522 | +        socksPortInfo.ipcFile = new lazy.FileUtils.File(ipcPath);
 | |
| 523 | +      }
 | |
| 524 | +    } else {
 | |
| 525 | +      // Check for TCP host and port environment variables.
 | |
| 526 | +      if (Services.env.exists("TOR_SOCKS_HOST")) {
 | |
| 527 | +        socksPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
 | |
| 528 | +        useIPC = false;
 | |
| 529 | +      }
 | |
| 530 | +      if (Services.env.exists("TOR_SOCKS_PORT")) {
 | |
| 531 | +        const port = parseInt(Services.env.get("TOR_SOCKS_PORT"), 10);
 | |
| 532 | +        if (Number.isInteger(port) && port > 0 && port <= 65535) {
 | |
| 533 | +          socksPortInfo.port = port;
 | |
| 534 | +          useIPC = false;
 | |
| 535 | +        }
 | |
| 536 | +      }
 | |
| 537 | +    }
 | |
| 538 | + | |
| 539 | +    if (useIPC === undefined) {
 | |
| 540 | +      socksPortInfo.useIPC =
 | |
| 541 | +        !this.isWindows &&
 | |
| 542 | +        Services.prefs.getBoolPref(
 | |
| 543 | +          "extensions.torlauncher.socks_port_use_ipc",
 | |
| 544 | +          false
 | |
| 545 | +        );
 | |
| 546 | +    }
 | |
| 547 | + | |
| 548 | +    // Fill in missing SOCKS info from prefs.
 | |
| 549 | +    if (socksPortInfo.useIPC) {
 | |
| 550 | +      if (!socksPortInfo.ipcFile) {
 | |
| 551 | +        socksPortInfo.ipcFile = TorLauncherUtil.getTorFile("socks_ipc", false);
 | |
| 552 | +      }
 | |
| 553 | +    } else {
 | |
| 554 | +      if (!socksPortInfo.host) {
 | |
| 555 | +        let socksAddr = Services.prefs.getCharPref(
 | |
| 556 | +          "network.proxy.socks",
 | |
| 557 | +          "127.0.0.1"
 | |
| 558 | +        );
 | |
| 559 | +        let socksAddrHasHost = socksAddr && !socksAddr.startsWith("file:");
 | |
| 560 | +        socksPortInfo.host = socksAddrHasHost ? socksAddr : "127.0.0.1";
 | |
| 561 | +      }
 | |
| 562 | + | |
| 563 | +      if (!socksPortInfo.port) {
 | |
| 564 | +        let socksPort = Services.prefs.getIntPref(
 | |
| 565 | +          "network.proxy.socks_port",
 | |
| 566 | +          0
 | |
| 567 | +        );
 | |
| 568 | +        // This pref is set as 0 by default in Firefox, use 9150 if we get 0.
 | |
| 569 | +        socksPortInfo.port =
 | |
| 570 | +          socksPort > 0 && socksPort <= 65535 ? socksPort : 9150;
 | |
| 571 | +      }
 | |
| 572 | +    }
 | |
| 573 | + | |
| 574 | +    return socksPortInfo;
 | |
| 575 | +  },
 | |
| 576 | + | |
| 577 | +  setProxyConfiguration(socksPortInfo) {
 | |
| 578 | +    if (socksPortInfo.transproxy) {
 | |
| 579 | +      return;
 | |
| 580 | +    }
 | |
| 581 | + | |
| 582 | +    if (socksPortInfo.useIPC) {
 | |
| 583 | +      const fph = Services.io
 | |
| 584 | +        .getProtocolHandler("file")
 | |
| 585 | +        .QueryInterface(Ci.nsIFileProtocolHandler);
 | |
| 586 | +      const fileURI = fph.newFileURI(socksPortInfo.ipcFile);
 | |
| 587 | +      Services.prefs.setCharPref("network.proxy.socks", fileURI.spec);
 | |
| 588 | +      Services.prefs.setIntPref("network.proxy.socks_port", 0);
 | |
| 589 | +    } else {
 | |
| 590 | +      if (socksPortInfo.host) {
 | |
| 591 | +        Services.prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
 | |
| 592 | +      }
 | |
| 593 | +      if (socksPortInfo.port) {
 | |
| 594 | +        Services.prefs.setIntPref(
 | |
| 595 | +          "network.proxy.socks_port",
 | |
| 596 | +          socksPortInfo.port
 | |
| 597 | +        );
 | |
| 598 | +      }
 | |
| 599 | +    }
 | |
| 600 | + | |
| 601 | +    if (socksPortInfo.ipcFile || socksPortInfo.host || socksPortInfo.port) {
 | |
| 602 | +      Services.prefs.setBoolPref("network.proxy.socks_remote_dns", true);
 | |
| 603 | +      Services.prefs.setIntPref("network.proxy.type", 1);
 | |
| 604 | +    }
 | |
| 605 | + | |
| 606 | +    // Force prefs to be synced to disk
 | |
| 607 | +    Services.prefs.savePrefFile(null);
 | |
| 608 | +  },
 | |
| 609 | + | |
| 455 | 610 |    get shouldStartAndOwnTor() {
 | 
| 456 | 611 |      const kPrefStartTor = "extensions.torlauncher.start_tor";
 | 
| 457 | 612 |      try {
 | 
| ... | ... | @@ -13,6 +13,10 @@ import { TorLauncherUtil } from "resource://gre/modules/TorLauncherUtil.sys.mjs" | 
| 13 | 13 | |
| 14 | 14 |  const lazy = {};
 | 
| 15 | 15 | |
| 16 | +ChromeUtils.defineESModuleGetters(lazy, {
 | |
| 17 | +  TorProtocolService: "resource://gre/modules/TorProtocolService.sys.mjs",
 | |
| 18 | +});
 | |
| 19 | + | |
| 16 | 20 |  ChromeUtils.defineModuleGetter(
 | 
| 17 | 21 |    lazy,
 | 
| 18 | 22 |    "controller",
 | 
| ... | ... | @@ -233,7 +237,10 @@ export const TorMonitorService = { | 
| 233 | 237 |      // TorProcess should be instanced once, then always reused and restarted
 | 
| 234 | 238 |      // only through the prompt it exposes when the controlled process dies.
 | 
| 235 | 239 |      if (!this._torProcess) {
 | 
| 236 | -      this._torProcess = new TorProcess();
 | |
| 240 | +      this._torProcess = new TorProcess(
 | |
| 241 | +        lazy.TorProtocolService.torControlPortInfo,
 | |
| 242 | +        lazy.TorProtocolService.torSOCKSPortInfo
 | |
| 243 | +      );
 | |
| 237 | 244 |        this._torProcess.onExit = () => {
 | 
| 238 | 245 |          this._shutDownEventMonitor();
 | 
| 239 | 246 |          Services.obs.notifyObservers(null, TorTopics.ProcessExited);
 | 
| ... | ... | @@ -254,6 +261,7 @@ export const TorMonitorService = { | 
| 254 | 261 |        await this._torProcess.start();
 | 
| 255 | 262 |        if (this._torProcess.isRunning) {
 | 
| 256 | 263 |          logger.info("tor started");
 | 
| 264 | +        this._torProcessStartTime = Date.now();
 | |
| 257 | 265 |        }
 | 
| 258 | 266 |      } catch (e) {
 | 
| 259 | 267 |        // TorProcess already logs the error.
 | 
| ... | ... | @@ -267,4 +267,18 @@ export const TorParsers = Object.freeze({ | 
| 267 | 267 |      rv += aStr.substring(lastAdded, aStr.length - 1);
 | 
| 268 | 268 |      return rv;
 | 
| 269 | 269 |    },
 | 
| 270 | + | |
| 271 | +  parseBridgeLine(line) {
 | |
| 272 | +    const re =
 | |
| 273 | +      /\s*(?:(?<transport>\S+)\s+)?(?<addr>[0-9a-fA-F\.\[\]\:]+:\d{1,5})(?:\s+(?<id>[0-9a-fA-F]{40}))?(?:\s+(?<args>.+))?/;
 | |
| 274 | +    const match = re.exec(line);
 | |
| 275 | +    if (!match) {
 | |
| 276 | +      throw new Error("Invalid bridge line.");
 | |
| 277 | +    }
 | |
| 278 | +    const bridge = match.groups;
 | |
| 279 | +    if (!bridge.transport) {
 | |
| 280 | +      bridge.transport = "vanilla";
 | |
| 281 | +    }
 | |
| 282 | +    return bridge;
 | |
| 283 | +  },
 | |
| 270 | 284 |  }); | 
| 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 | + | |
| 1 | 5 |  import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";
 | 
| 2 | 6 |  import { ConsoleAPI } from "resource://gre/modules/Console.sys.mjs";
 | 
| 3 | 7 |  import { Subprocess } from "resource://gre/modules/Subprocess.sys.mjs";
 | 
| 4 | 8 | |
| 5 | 9 |  const lazy = {};
 | 
| 6 | 10 | |
| 7 | -ChromeUtils.defineModuleGetter(
 | |
| 8 | -  lazy,
 | |
| 9 | -  "TorProtocolService",
 | |
| 10 | -  "resource://gre/modules/TorProtocolService.jsm"
 | |
| 11 | -);
 | |
| 12 | -const { TorLauncherUtil } = ChromeUtils.import(
 | |
| 13 | -  "resource://gre/modules/TorLauncherUtil.jsm"
 | |
| 14 | -);
 | |
| 15 | - | |
| 16 | -const { TorParsers } = ChromeUtils.import(
 | |
| 17 | -  "resource://gre/modules/TorParsers.jsm"
 | |
| 18 | -);
 | |
| 11 | +ChromeUtils.defineESModuleGetters(lazy, {
 | |
| 12 | +  TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
 | |
| 13 | +  TorParsers: "resource://gre/modules/TorParsers.sys.mjs",
 | |
| 14 | +});
 | |
| 19 | 15 | |
| 20 | 16 |  const TorProcessStatus = Object.freeze({
 | 
| 21 | 17 |    Unknown: 0,
 | 
| ... | ... | @@ -30,53 +26,86 @@ const logger = new ConsoleAPI({ | 
| 30 | 26 |  });
 | 
| 31 | 27 | |
| 32 | 28 |  export class TorProcess {
 | 
| 33 | -  _exeFile = null;
 | |
| 34 | -  _dataDir = null;
 | |
| 35 | -  _args = [];
 | |
| 36 | -  _subprocess = null;
 | |
| 37 | -  _status = TorProcessStatus.Unknown;
 | |
| 38 | -  _torProcessStartTime = null; // JS Date.now()
 | |
| 39 | -  _didConnectToTorControlPort = false; // Have we ever made a connection?
 | |
| 29 | +  #controlSettings;
 | |
| 30 | +  #socksSettings;
 | |
| 31 | +  #exeFile = null;
 | |
| 32 | +  #dataDir = null;
 | |
| 33 | +  #args = [];
 | |
| 34 | +  #subprocess = null;
 | |
| 35 | +  #status = TorProcessStatus.Unknown;
 | |
| 36 | +  // Have we ever made a connection on the control port?
 | |
| 37 | +  #didConnectToTorControlPort = false;
 | |
| 38 | + | |
| 39 | +  onExit = exitCode => {};
 | |
| 40 | +  onRestart = () => {};
 | |
| 41 | + | |
| 42 | +  constructor(controlSettings, socksSettings) {
 | |
| 43 | +    if (
 | |
| 44 | +      controlSettings &&
 | |
| 45 | +      !controlSettings.password &&
 | |
| 46 | +      !controlSettings.cookieFilePath
 | |
| 47 | +    ) {
 | |
| 48 | +      throw new Error("Unauthenticated control port is not supported");
 | |
| 49 | +    }
 | |
| 40 | 50 | |
| 41 | -  onExit = null;
 | |
| 42 | -  onRestart = null;
 | |
| 51 | +    const checkPort = port =>
 | |
| 52 | +      port === undefined ||
 | |
| 53 | +      (Number.isInteger(controlSettings.port) &&
 | |
| 54 | +        controlSettings.port > 0 &&
 | |
| 55 | +        controlSettings.port < 65535);
 | |
| 56 | +    if (!checkPort(controlSettings?.port)) {
 | |
| 57 | +      throw new Error("Invalid control port");
 | |
| 58 | +    }
 | |
| 59 | +    if (!checkPort(socksSettings.port)) {
 | |
| 60 | +      throw new Error("Invalid port specified for the SOCKS port");
 | |
| 61 | +    }
 | |
| 62 | + | |
| 63 | +    this.#controlSettings = { ...controlSettings };
 | |
| 64 | +    const ipcFileToString = file =>
 | |
| 65 | +      "unix:" + lazy.TorParsers.escapeString(file.path);
 | |
| 66 | +    if (controlSettings.ipcFile) {
 | |
| 67 | +      this.#controlSettings.ipcFile = ipcFileToString(controlSettings.ipcFile);
 | |
| 68 | +    }
 | |
| 69 | +    this.#socksSettings = { ...socksSettings };
 | |
| 70 | +    if (socksSettings.ipcFile) {
 | |
| 71 | +      this.#socksSettings.ipcFile = ipcFileToString(socksSettings.ipcFile);
 | |
| 72 | +    }
 | |
| 73 | +  }
 | |
| 43 | 74 | |
| 44 | 75 |    get status() {
 | 
| 45 | -    return this._status;
 | |
| 76 | +    return this.#status;
 | |
| 46 | 77 |    }
 | 
| 47 | 78 | |
| 48 | 79 |    get isRunning() {
 | 
| 49 | 80 |      return (
 | 
| 50 | -      this._status === TorProcessStatus.Starting ||
 | |
| 51 | -      this._status === TorProcessStatus.Running
 | |
| 81 | +      this.#status === TorProcessStatus.Starting ||
 | |
| 82 | +      this.#status === TorProcessStatus.Running
 | |
| 52 | 83 |      );
 | 
| 53 | 84 |    }
 | 
| 54 | 85 | |
| 55 | 86 |    async start() {
 | 
| 56 | -    if (this._subprocess) {
 | |
| 87 | +    if (this.#subprocess) {
 | |
| 57 | 88 |        return;
 | 
| 58 | 89 |      }
 | 
| 59 | 90 | |
| 60 | -    this._status = TorProcessStatus.Unknown;
 | |
| 91 | +    this.#status = TorProcessStatus.Unknown;
 | |
| 61 | 92 | |
| 62 | 93 |      try {
 | 
| 63 | -      this._makeArgs();
 | |
| 64 | -      this._addControlPortArg();
 | |
| 65 | -      this._addSocksPortArg();
 | |
| 94 | +      this.#makeArgs();
 | |
| 95 | +      this.#addControlPortArgs();
 | |
| 96 | +      this.#addSocksPortArg();
 | |
| 66 | 97 | |
| 67 | 98 |        const pid = Services.appinfo.processID;
 | 
| 68 | 99 |        if (pid !== 0) {
 | 
| 69 | -        this._args.push("__OwningControllerProcess");
 | |
| 70 | -        this._args.push("" + pid);
 | |
| 100 | +        this.#args.push("__OwningControllerProcess", pid.toString());
 | |
| 71 | 101 |        }
 | 
| 72 | 102 | |
| 73 | -      if (TorLauncherUtil.shouldShowNetworkSettings) {
 | |
| 74 | -        this._args.push("DisableNetwork");
 | |
| 75 | -        this._args.push("1");
 | |
| 103 | +      if (lazy.TorLauncherUtil.shouldShowNetworkSettings) {
 | |
| 104 | +        this.#args.push("DisableNetwork", "1");
 | |
| 76 | 105 |        }
 | 
| 77 | 106 | |
| 78 | -      this._status = TorProcessStatus.Starting;
 | |
| 79 | -      this._didConnectToTorControlPort = false;
 | |
| 107 | +      this.#status = TorProcessStatus.Starting;
 | |
| 108 | +      this.#didConnectToTorControlPort = false;
 | |
| 80 | 109 | |
| 81 | 110 |        // useful for simulating slow tor daemon launch
 | 
| 82 | 111 |        const kPrefTorDaemonLaunchDelay = "extensions.torlauncher.launch_delay";
 | 
| ... | ... | @@ -88,29 +117,31 @@ export class TorProcess { | 
| 88 | 117 |          await new Promise(resolve => setTimeout(() => resolve(), launchDelay));
 | 
| 89 | 118 |        }
 | 
| 90 | 119 | |
| 91 | -      logger.debug(`Starting ${this._exeFile.path}`, this._args);
 | |
| 120 | +      logger.debug(`Starting ${this.#exeFile.path}`, this.#args);
 | |
| 92 | 121 |        const options = {
 | 
| 93 | -        command: this._exeFile.path,
 | |
| 94 | -        arguments: this._args,
 | |
| 122 | +        command: this.#exeFile.path,
 | |
| 123 | +        arguments: this.#args,
 | |
| 95 | 124 |          stderr: "stdout",
 | 
| 96 | -        workdir: TorLauncherUtil.getTorFile("pt-startup-dir", false).path,
 | |
| 125 | +        workdir: lazy.TorLauncherUtil.getTorFile("pt-startup-dir", false).path,
 | |
| 97 | 126 |        };
 | 
| 98 | -      this._subprocess = await Subprocess.call(options);
 | |
| 99 | -      this._dumpStdout();
 | |
| 100 | -      this._watchProcess();
 | |
| 101 | -      this._status = TorProcessStatus.Running;
 | |
| 102 | -      this._torProcessStartTime = Date.now();
 | |
| 127 | +      this.#subprocess = await Subprocess.call(options);
 | |
| 128 | +      this.#status = TorProcessStatus.Running;
 | |
| 103 | 129 |      } catch (e) {
 | 
| 104 | -      this._status = TorProcessStatus.Exited;
 | |
| 105 | -      this._subprocess = null;
 | |
| 130 | +      this.#status = TorProcessStatus.Exited;
 | |
| 131 | +      this.#subprocess = null;
 | |
| 106 | 132 |        logger.error("startTor error:", e);
 | 
| 107 | 133 |        throw e;
 | 
| 108 | 134 |      }
 | 
| 135 | + | |
| 136 | +    // Do not await the following functions, as they will return only when the
 | |
| 137 | +    // process exits.
 | |
| 138 | +    this.#dumpStdout();
 | |
| 139 | +    this.#watchProcess();
 | |
| 109 | 140 |    }
 | 
| 110 | 141 | |
| 111 | 142 |    // Forget about a process.
 | 
| 112 | 143 |    //
 | 
| 113 | -  // Instead of killing the tor process, we  rely on the TAKEOWNERSHIP feature
 | |
| 144 | +  // Instead of killing the tor process, we rely on the TAKEOWNERSHIP feature
 | |
| 114 | 145 |    // to shut down tor when we close the control port connection.
 | 
| 115 | 146 |    //
 | 
| 116 | 147 |    // Previously, we sent a SIGNAL HALT command to the tor control port,
 | 
| ... | ... | @@ -123,36 +154,38 @@ export class TorProcess { | 
| 123 | 154 |    // Still, before closing the owning connection, this class should forget about
 | 
| 124 | 155 |    // the process, so that future notifications will be ignored.
 | 
| 125 | 156 |    forget() {
 | 
| 126 | -    this._subprocess = null;
 | |
| 127 | -    this._status = TorProcessStatus.Exited;
 | |
| 157 | +    this.#subprocess = null;
 | |
| 158 | +    this.#status = TorProcessStatus.Exited;
 | |
| 128 | 159 |    }
 | 
| 129 | 160 | |
| 130 | 161 |    // The owner of the process can use this function to tell us that they
 | 
| 131 | 162 |    // successfully connected to the control port. This information will be used
 | 
| 132 | 163 |    // only to decide which text to show in the confirmation dialog if tor exits.
 | 
| 133 | 164 |    connectionWorked() {
 | 
| 134 | -    this._didConnectToTorControlPort = true;
 | |
| 165 | +    this.#didConnectToTorControlPort = true;
 | |
| 135 | 166 |    }
 | 
| 136 | 167 | |
| 137 | -  async _dumpStdout() {
 | |
| 168 | +  async #dumpStdout() {
 | |
| 138 | 169 |      let string;
 | 
| 139 | 170 |      while (
 | 
| 140 | -      this._subprocess &&
 | |
| 141 | -      (string = await this._subprocess.stdout.readString())
 | |
| 171 | +      this.#subprocess &&
 | |
| 172 | +      (string = await this.#subprocess.stdout.readString())
 | |
| 142 | 173 |      ) {
 | 
| 143 | 174 |        dump(string);
 | 
| 144 | 175 |      }
 | 
| 145 | 176 |    }
 | 
| 146 | 177 | |
| 147 | -  async _watchProcess() {
 | |
| 148 | -    const watched = this._subprocess;
 | |
| 178 | +  async #watchProcess() {
 | |
| 179 | +    const watched = this.#subprocess;
 | |
| 149 | 180 |      if (!watched) {
 | 
| 150 | 181 |        return;
 | 
| 151 | 182 |      }
 | 
| 183 | +    let processExitCode;
 | |
| 152 | 184 |      try {
 | 
| 153 | 185 |        const { exitCode } = await watched.wait();
 | 
| 186 | +      processExitCode = exitCode;
 | |
| 154 | 187 | |
| 155 | -      if (watched !== this._subprocess) {
 | |
| 188 | +      if (watched !== this.#subprocess) {
 | |
| 156 | 189 |          logger.debug(`A Tor process exited with code ${exitCode}.`);
 | 
| 157 | 190 |        } else if (exitCode) {
 | 
| 158 | 191 |          logger.warn(`The watched Tor process exited with code ${exitCode}.`);
 | 
| ... | ... | @@ -163,30 +196,31 @@ export class TorProcess { | 
| 163 | 196 |        logger.error("Failed to watch the tor process", e);
 | 
| 164 | 197 |      }
 | 
| 165 | 198 | |
| 166 | -    if (watched === this._subprocess) {
 | |
| 167 | -      this._processExitedUnexpectedly();
 | |
| 199 | +    if (watched === this.#subprocess) {
 | |
| 200 | +      this.#processExitedUnexpectedly(processExitCode);
 | |
| 168 | 201 |      }
 | 
| 169 | 202 |    }
 | 
| 170 | 203 | |
| 171 | -  _processExitedUnexpectedly() {
 | |
| 172 | -    this._subprocess = null;
 | |
| 173 | -    this._status = TorProcessStatus.Exited;
 | |
| 204 | +  #processExitedUnexpectedly(exitCode) {
 | |
| 205 | +    this.#subprocess = null;
 | |
| 206 | +    this.#status = TorProcessStatus.Exited;
 | |
| 174 | 207 | |
| 175 | 208 |      // TODO: Move this logic somewhere else?
 | 
| 176 | 209 |      let s;
 | 
| 177 | -    if (!this._didConnectToTorControlPort) {
 | |
| 210 | +    if (!this.#didConnectToTorControlPort) {
 | |
| 178 | 211 |        // tor might be misconfigured, becauser we could never connect to it
 | 
| 179 | 212 |        const key = "tor_exited_during_startup";
 | 
| 180 | -      s = TorLauncherUtil.getLocalizedString(key);
 | |
| 213 | +      s = lazy.TorLauncherUtil.getLocalizedString(key);
 | |
| 181 | 214 |      } else {
 | 
| 182 | 215 |        // tor exited suddenly, so configuration should be okay
 | 
| 183 | 216 |        s =
 | 
| 184 | -        TorLauncherUtil.getLocalizedString("tor_exited") +
 | |
| 217 | +        lazy.TorLauncherUtil.getLocalizedString("tor_exited") +
 | |
| 185 | 218 |          "\n\n" +
 | 
| 186 | -        TorLauncherUtil.getLocalizedString("tor_exited2");
 | |
| 219 | +        lazy.TorLauncherUtil.getLocalizedString("tor_exited2");
 | |
| 187 | 220 |      }
 | 
| 188 | 221 |      logger.info(s);
 | 
| 189 | -    const defaultBtnLabel = TorLauncherUtil.getLocalizedString("restart_tor");
 | |
| 222 | +    const defaultBtnLabel =
 | |
| 223 | +      lazy.TorLauncherUtil.getLocalizedString("restart_tor");
 | |
| 190 | 224 |      let cancelBtnLabel = "OK";
 | 
| 191 | 225 |      try {
 | 
| 192 | 226 |        const kSysBundleURI = "chrome://global/locale/commonDialogs.properties";
 | 
| ... | ... | @@ -196,51 +230,43 @@ export class TorProcess { | 
| 196 | 230 |        logger.warn("Could not localize the cancel button", e);
 | 
| 197 | 231 |      }
 | 
| 198 | 232 | |
| 199 | -    const restart = TorLauncherUtil.showConfirm(
 | |
| 233 | +    const restart = lazy.TorLauncherUtil.showConfirm(
 | |
| 200 | 234 |        null,
 | 
| 201 | 235 |        s,
 | 
| 202 | 236 |        defaultBtnLabel,
 | 
| 203 | 237 |        cancelBtnLabel
 | 
| 204 | 238 |      );
 | 
| 205 | 239 |      if (restart) {
 | 
| 206 | -      this.start().then(() => {
 | |
| 207 | -        if (this.onRestart) {
 | |
| 208 | -          this.onRestart();
 | |
| 209 | -        }
 | |
| 210 | -      });
 | |
| 211 | -    } else if (this.onExit) {
 | |
| 212 | -      this.onExit();
 | |
| 240 | +      this.start().then(this.onRestart);
 | |
| 241 | +    } else {
 | |
| 242 | +      this.onExit(exitCode);
 | |
| 213 | 243 |      }
 | 
| 214 | 244 |    }
 | 
| 215 | 245 | |
| 216 | -  _makeArgs() {
 | |
| 217 | -    // Ideally, we would cd to the Firefox application directory before
 | |
| 218 | -    // starting tor (but we don't know how to do that). Instead, we
 | |
| 219 | -    // rely on the TBB launcher to start Firefox from the right place.
 | |
| 220 | - | |
| 246 | +  #makeArgs() {
 | |
| 247 | +    this.#exeFile = lazy.TorLauncherUtil.getTorFile("tor", false);
 | |
| 248 | +    const torrcFile = lazy.TorLauncherUtil.getTorFile("torrc", true);
 | |
| 221 | 249 |      // Get the Tor data directory first so it is created before we try to
 | 
| 222 | 250 |      // construct paths to files that will be inside it.
 | 
| 223 | -    this._exeFile = TorLauncherUtil.getTorFile("tor", false);
 | |
| 224 | -    const torrcFile = TorLauncherUtil.getTorFile("torrc", true);
 | |
| 225 | -    this._dataDir = TorLauncherUtil.getTorFile("tordatadir", true);
 | |
| 226 | -    const onionAuthDir = TorLauncherUtil.getTorFile("toronionauthdir", true);
 | |
| 227 | -    const hashedPassword = lazy.TorProtocolService.torGetPassword(true);
 | |
| 251 | +    this.#dataDir = lazy.TorLauncherUtil.getTorFile("tordatadir", true);
 | |
| 252 | +    const onionAuthDir = lazy.TorLauncherUtil.getTorFile(
 | |
| 253 | +      "toronionauthdir",
 | |
| 254 | +      true
 | |
| 255 | +    );
 | |
| 228 | 256 |      let detailsKey;
 | 
| 229 | -    if (!this._exeFile) {
 | |
| 257 | +    if (!this.#exeFile) {
 | |
| 230 | 258 |        detailsKey = "tor_missing";
 | 
| 231 | 259 |      } else if (!torrcFile) {
 | 
| 232 | 260 |        detailsKey = "torrc_missing";
 | 
| 233 | -    } else if (!this._dataDir) {
 | |
| 261 | +    } else if (!this.#dataDir) {
 | |
| 234 | 262 |        detailsKey = "datadir_missing";
 | 
| 235 | 263 |      } else if (!onionAuthDir) {
 | 
| 236 | 264 |        detailsKey = "onionauthdir_missing";
 | 
| 237 | -    } else if (!hashedPassword) {
 | |
| 238 | -      detailsKey = "password_hash_missing";
 | |
| 239 | 265 |      }
 | 
| 240 | 266 |      if (detailsKey) {
 | 
| 241 | -      const details = TorLauncherUtil.getLocalizedString(detailsKey);
 | |
| 267 | +      const details = lazy.TorLauncherUtil.getLocalizedString(detailsKey);
 | |
| 242 | 268 |        const key = "unable_to_start_tor";
 | 
| 243 | -      const err = TorLauncherUtil.getFormattedLocalizedString(
 | |
| 269 | +      const err = lazy.TorLauncherUtil.getFormattedLocalizedString(
 | |
| 244 | 270 |          key,
 | 
| 245 | 271 |          [details],
 | 
| 246 | 272 |          1
 | 
| ... | ... | @@ -248,7 +274,7 @@ export class TorProcess { | 
| 248 | 274 |        throw new Error(err);
 | 
| 249 | 275 |      }
 | 
| 250 | 276 | |
| 251 | -    const torrcDefaultsFile = TorLauncherUtil.getTorFile(
 | |
| 277 | +    const torrcDefaultsFile = lazy.TorLauncherUtil.getTorFile(
 | |
| 252 | 278 |        "torrc-defaults",
 | 
| 253 | 279 |        false
 | 
| 254 | 280 |      );
 | 
| ... | ... | @@ -258,77 +284,131 @@ export class TorProcess { | 
| 258 | 284 |      const geoip6File = torrcDefaultsFile.clone();
 | 
| 259 | 285 |      geoip6File.leafName = "geoip6";
 | 
| 260 | 286 | |
| 261 | -    this._args = [];
 | |
| 287 | +    this.#args = [];
 | |
| 262 | 288 |      if (torrcDefaultsFile) {
 | 
| 263 | -      this._args.push("--defaults-torrc");
 | |
| 264 | -      this._args.push(torrcDefaultsFile.path);
 | |
| 289 | +      this.#args.push("--defaults-torrc", torrcDefaultsFile.path);
 | |
| 265 | 290 |      }
 | 
| 266 | -    this._args.push("-f");
 | |
| 267 | -    this._args.push(torrcFile.path);
 | |
| 268 | -    this._args.push("DataDirectory");
 | |
| 269 | -    this._args.push(this._dataDir.path);
 | |
| 270 | -    this._args.push("ClientOnionAuthDir");
 | |
| 271 | -    this._args.push(onionAuthDir.path);
 | |
| 272 | -    this._args.push("GeoIPFile");
 | |
| 273 | -    this._args.push(geoipFile.path);
 | |
| 274 | -    this._args.push("GeoIPv6File");
 | |
| 275 | -    this._args.push(geoip6File.path);
 | |
| 276 | -    this._args.push("HashedControlPassword");
 | |
| 277 | -    this._args.push(hashedPassword);
 | |
| 291 | +    this.#args.push("-f", torrcFile.path);
 | |
| 292 | +    this.#args.push("DataDirectory", this.#dataDir.path);
 | |
| 293 | +    this.#args.push("ClientOnionAuthDir", onionAuthDir.path);
 | |
| 294 | +    this.#args.push("GeoIPFile", geoipFile.path);
 | |
| 295 | +    this.#args.push("GeoIPv6File", geoip6File.path);
 | |
| 278 | 296 |    }
 | 
| 279 | 297 | |
| 280 | -  _addControlPortArg() {
 | |
| 281 | -    // Include a ControlPort argument to support switching between
 | |
| 282 | -    // a TCP port and an IPC port (e.g., a Unix domain socket). We
 | |
| 283 | -    // include a "+__" prefix so that (1) this control port is added
 | |
| 284 | -    // to any control ports that the user has defined in their torrc
 | |
| 285 | -    // file and (2) it is never written to torrc.
 | |
| 298 | +  /**
 | |
| 299 | +   * Add all the arguments related to the control port.
 | |
| 300 | +   * We use the + prefix so that the the port is added to any other port already
 | |
| 301 | +   * defined in the torrc, and the __ prefix so that it is never written to
 | |
| 302 | +   * torrc.
 | |
| 303 | +   */
 | |
| 304 | +  #addControlPortArgs() {
 | |
| 305 | +    if (!this.#controlSettings) {
 | |
| 306 | +      return;
 | |
| 307 | +    }
 | |
| 308 | + | |
| 286 | 309 |      let controlPortArg;
 | 
| 287 | -    const controlIPCFile = lazy.TorProtocolService.torGetControlIPCFile();
 | |
| 288 | -    const controlPort = lazy.TorProtocolService.torGetControlPort();
 | |
| 289 | -    if (controlIPCFile) {
 | |
| 290 | -      controlPortArg = this._ipcPortArg(controlIPCFile);
 | |
| 291 | -    } else if (controlPort) {
 | |
| 292 | -      controlPortArg = "" + controlPort;
 | |
| 310 | +    if (this.#controlSettings.ipcFile) {
 | |
| 311 | +      controlPortArg = this.#controlSettings.ipcFile;
 | |
| 312 | +    } else if (this.#controlSettings.port) {
 | |
| 313 | +      controlPortArg = this.#controlSettings.host
 | |
| 314 | +        ? `${this.#controlSettings.host}:${this.#controlSettings.port}`
 | |
| 315 | +        : this.#controlSettings.port.toString();
 | |
| 293 | 316 |      }
 | 
| 294 | 317 |      if (controlPortArg) {
 | 
| 295 | -      this._args.push("+__ControlPort");
 | |
| 296 | -      this._args.push(controlPortArg);
 | |
| 318 | +      this.#args.push("+__ControlPort", controlPortArg);
 | |
| 319 | +    }
 | |
| 320 | + | |
| 321 | +    if (this.#controlSettings.password) {
 | |
| 322 | +      this.#args.push(
 | |
| 323 | +        "HashedControlPassword",
 | |
| 324 | +        this.#hashPassword(this.#controlSettings.password)
 | |
| 325 | +      );
 | |
| 326 | +    }
 | |
| 327 | +    if (this.#controlSettings.cookieFilePath) {
 | |
| 328 | +      this.#args.push("CookieAuthentication", "1");
 | |
| 329 | +      this.#args.push("CookieAuthFile", this.#controlSettings.cookieFilePath);
 | |
| 297 | 330 |      }
 | 
| 298 | 331 |    }
 | 
| 299 | 332 | |
| 300 | -  _addSocksPortArg() {
 | |
| 301 | -    // Include a SocksPort argument to support switching between
 | |
| 302 | -    // a TCP port and an IPC port (e.g., a Unix domain socket). We
 | |
| 303 | -    // include a "+__" prefix so that (1) this SOCKS port is added
 | |
| 304 | -    // to any SOCKS ports that the user has defined in their torrc
 | |
| 305 | -    // file and (2) it is never written to torrc.
 | |
| 306 | -    const socksPortInfo = lazy.TorProtocolService.torGetSOCKSPortInfo();
 | |
| 307 | -    if (socksPortInfo) {
 | |
| 308 | -      let socksPortArg;
 | |
| 309 | -      if (socksPortInfo.ipcFile) {
 | |
| 310 | -        socksPortArg = this._ipcPortArg(socksPortInfo.ipcFile);
 | |
| 311 | -      } else if (socksPortInfo.host && socksPortInfo.port != 0) {
 | |
| 312 | -        socksPortArg = socksPortInfo.host + ":" + socksPortInfo.port;
 | |
| 313 | -      }
 | |
| 314 | -      if (socksPortArg) {
 | |
| 315 | -        let socksPortFlags = Services.prefs.getCharPref(
 | |
| 316 | -          "extensions.torlauncher.socks_port_flags",
 | |
| 317 | -          "IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth"
 | |
| 318 | -        );
 | |
| 319 | -        if (socksPortFlags) {
 | |
| 320 | -          socksPortArg += " " + socksPortFlags;
 | |
| 321 | -        }
 | |
| 322 | -        this._args.push("+__SocksPort");
 | |
| 323 | -        this._args.push(socksPortArg);
 | |
| 333 | +  /**
 | |
| 334 | +   * Add the argument related to the control port.
 | |
| 335 | +   * We use the + prefix so that the the port is added to any other port already
 | |
| 336 | +   * defined in the torrc, and the __ prefix so that it is never written to
 | |
| 337 | +   * torrc.
 | |
| 338 | +   */
 | |
| 339 | +  #addSocksPortArg() {
 | |
| 340 | +    let socksPortArg;
 | |
| 341 | +    if (this.#socksSettings.ipcFile) {
 | |
| 342 | +      socksPortArg = this.#socksSettings.ipcFile;
 | |
| 343 | +    } else if (this.#socksSettings.port != 0) {
 | |
| 344 | +      socksPortArg = this.#socksSettings.host
 | |
| 345 | +        ? `${this.#socksSettings.host}:${this.#socksSettings.port}`
 | |
| 346 | +        : this.#socksSettings.port.toString();
 | |
| 347 | +    }
 | |
| 348 | +    if (socksPortArg) {
 | |
| 349 | +      const socksPortFlags = Services.prefs.getCharPref(
 | |
| 350 | +        "extensions.torlauncher.socks_port_flags",
 | |
| 351 | +        "IPv6Traffic PreferIPv6 KeepAliveIsolateSOCKSAuth"
 | |
| 352 | +      );
 | |
| 353 | +      if (socksPortFlags) {
 | |
| 354 | +        socksPortArg += " " + socksPortFlags;
 | |
| 324 | 355 |        }
 | 
| 356 | +      this.#args.push("+__SocksPort", socksPortArg);
 | |
| 357 | +    }
 | |
| 358 | +  }
 | |
| 359 | + | |
| 360 | +  // Based on Vidalia's TorSettings::hashPassword().
 | |
| 361 | +  #hashPassword(aHexPassword) {
 | |
| 362 | +    if (!aHexPassword) {
 | |
| 363 | +      return null;
 | |
| 325 | 364 |      }
 | 
| 365 | + | |
| 366 | +    // Generate a random, 8 byte salt value.
 | |
| 367 | +    const salt = Array.from(crypto.getRandomValues(new Uint8Array(8)));
 | |
| 368 | + | |
| 369 | +    // Convert hex-encoded password to an array of bytes.
 | |
| 370 | +    const password = [];
 | |
| 371 | +    for (let i = 0; i < aHexPassword.length; i += 2) {
 | |
| 372 | +      password.push(parseInt(aHexPassword.substring(i, i + 2), 16));
 | |
| 373 | +    }
 | |
| 374 | + | |
| 375 | +    // Run through the S2K algorithm and convert to a string.
 | |
| 376 | +    const toHex = v => v.toString(16).padStart(2, "0");
 | |
| 377 | +    const arrayToHex = aArray => aArray.map(toHex).join("");
 | |
| 378 | +    const kCodedCount = 96;
 | |
| 379 | +    const hashVal = this.#cryptoSecretToKey(password, salt, kCodedCount);
 | |
| 380 | +    return "16:" + arrayToHex(salt) + toHex(kCodedCount) + arrayToHex(hashVal);
 | |
| 326 | 381 |    }
 | 
| 327 | 382 | |
| 328 | -  // Return a ControlPort or SocksPort argument for aIPCFile (an nsIFile).
 | |
| 329 | -  // The result is unix:/path or unix:"/path with spaces" with appropriate
 | |
| 330 | -  // C-style escaping within the path portion.
 | |
| 331 | -  _ipcPortArg(aIPCFile) {
 | |
| 332 | -    return "unix:" + TorParsers.escapeString(aIPCFile.path);
 | |
| 383 | +  // #cryptoSecretToKey() is similar to Vidalia's crypto_secret_to_key().
 | |
| 384 | +  // It generates and returns a hash of aPassword by following the iterated
 | |
| 385 | +  // and salted S2K algorithm (see RFC 2440 section 3.6.1.3).
 | |
| 386 | +  // See also https://gitlab.torproject.org/tpo/core/torspec/-/blob/main/control-spec.txt#L3824.
 | |
| 387 | +  // Returns an array of bytes.
 | |
| 388 | +  #cryptoSecretToKey(aPassword, aSalt, aCodedCount) {
 | |
| 389 | +    const inputArray = aSalt.concat(aPassword);
 | |
| 390 | + | |
| 391 | +    // Subtle crypto only has the final digest, and does not allow incremental
 | |
| 392 | +    // updates.
 | |
| 393 | +    const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
 | |
| 394 | +      Ci.nsICryptoHash
 | |
| 395 | +    );
 | |
| 396 | +    hasher.init(hasher.SHA1);
 | |
| 397 | +    const kEXPBIAS = 6;
 | |
| 398 | +    let count = (16 + (aCodedCount & 15)) << ((aCodedCount >> 4) + kEXPBIAS);
 | |
| 399 | +    while (count > 0) {
 | |
| 400 | +      if (count > inputArray.length) {
 | |
| 401 | +        hasher.update(inputArray, inputArray.length);
 | |
| 402 | +        count -= inputArray.length;
 | |
| 403 | +      } else {
 | |
| 404 | +        const finalArray = inputArray.slice(0, count);
 | |
| 405 | +        hasher.update(finalArray, finalArray.length);
 | |
| 406 | +        count = 0;
 | |
| 407 | +      }
 | |
| 408 | +    }
 | |
| 409 | +    return hasher
 | |
| 410 | +      .finish(false)
 | |
| 411 | +      .split("")
 | |
| 412 | +      .map(b => b.charCodeAt(0));
 | |
| 333 | 413 |    }
 | 
| 334 | 414 |  } | 
| ... | ... | @@ -289,9 +289,8 @@ export const TorProtocolService = { | 
| 289 | 289 |    // are also used in torbutton.
 | 
| 290 | 290 | |
| 291 | 291 |    // Returns Tor password string or null if an error occurs.
 | 
| 292 | -  torGetPassword(aPleaseHash) {
 | |
| 293 | -    const pw = this._controlPassword;
 | |
| 294 | -    return aPleaseHash ? this._hashPassword(pw) : pw;
 | |
| 292 | +  torGetPassword() {
 | |
| 293 | +    return this._controlPassword;
 | |
| 295 | 294 |    },
 | 
| 296 | 295 | |
| 297 | 296 |    torGetControlIPCFile() {
 | 
| ... | ... | @@ -306,6 +305,24 @@ export const TorProtocolService = { | 
| 306 | 305 |      return this._SOCKSPortInfo;
 | 
| 307 | 306 |    },
 | 
| 308 | 307 | |
| 308 | +  get torControlPortInfo() {
 | |
| 309 | +    const info = {
 | |
| 310 | +      password: this._controlPassword,
 | |
| 311 | +    };
 | |
| 312 | +    if (this._controlIPCFile) {
 | |
| 313 | +      info.ipcFile = this._controlIPCFile?.clone();
 | |
| 314 | +    }
 | |
| 315 | +    if (this._controlPort) {
 | |
| 316 | +      info.host = this._controlHost;
 | |
| 317 | +      info.port = this._controlPort;
 | |
| 318 | +    }
 | |
| 319 | +    return info;
 | |
| 320 | +  },
 | |
| 321 | + | |
| 322 | +  get torSOCKSPortInfo() {
 | |
| 323 | +    return this._SOCKSPortInfo;
 | |
| 324 | +  },
 | |
| 325 | + | |
| 309 | 326 |    // Public, but called only internally
 | 
| 310 | 327 | |
| 311 | 328 |    // Executes a command on the control port.
 | 
| ... | ... | @@ -469,115 +486,8 @@ export const TorProtocolService = { | 
| 469 | 486 |          this._controlPassword = this._generateRandomPassword();
 | 
| 470 | 487 |        }
 | 
| 471 | 488 | |
| 472 | -      // Determine what kind of SOCKS port Tor and the browser will use.
 | |
| 473 | -      // On Windows (where Unix domain sockets are not supported), TCP is
 | |
| 474 | -      // always used.
 | |
| 475 | -      //
 | |
| 476 | -      // The following environment variables are supported and take
 | |
| 477 | -      // precedence over preferences:
 | |
| 478 | -      //    TOR_SOCKS_IPC_PATH  (file system path; ignored on Windows)
 | |
| 479 | -      //    TOR_SOCKS_HOST
 | |
| 480 | -      //    TOR_SOCKS_PORT
 | |
| 481 | -      //
 | |
| 482 | -      // The following preferences are consulted:
 | |
| 483 | -      //    network.proxy.socks
 | |
| 484 | -      //    network.proxy.socks_port
 | |
| 485 | -      //    extensions.torlauncher.socks_port_use_ipc (Boolean)
 | |
| 486 | -      //    extensions.torlauncher.socks_ipc_path (file system path)
 | |
| 487 | -      // If extensions.torlauncher.socks_ipc_path is empty, a default
 | |
| 488 | -      // path is used (<tor-data-directory>/socks.socket).
 | |
| 489 | -      //
 | |
| 490 | -      // When using TCP, if a value is not defined via an env variable it is
 | |
| 491 | -      // taken from the corresponding browser preference if possible. The
 | |
| 492 | -      // exceptions are:
 | |
| 493 | -      //   If network.proxy.socks contains a file: URL, a default value of
 | |
| 494 | -      //     "127.0.0.1" is used instead.
 | |
| 495 | -      //   If the network.proxy.socks_port value is 0, a default value of
 | |
| 496 | -      //     9150 is used instead.
 | |
| 497 | -      //
 | |
| 498 | -      // Supported scenarios:
 | |
| 499 | -      // 1. By default, an IPC object at a default path is used.
 | |
| 500 | -      // 2. If extensions.torlauncher.socks_port_use_ipc is set to false,
 | |
| 501 | -      //    a TCP socket at 127.0.0.1:9150 is used, unless different values
 | |
| 502 | -      //    are set in network.proxy.socks and network.proxy.socks_port.
 | |
| 503 | -      // 3. If the TOR_SOCKS_IPC_PATH env var is set, an IPC object at that
 | |
| 504 | -      //    path is used (e.g., a Unix domain socket).
 | |
| 505 | -      // 4. If the TOR_SOCKS_HOST and/or TOR_SOCKS_PORT env vars are set, TCP
 | |
| 506 | -      //    is used. Values not set via env vars will be taken from the
 | |
| 507 | -      //    network.proxy.socks and network.proxy.socks_port prefs as described
 | |
| 508 | -      //    above.
 | |
| 509 | -      // 5. If extensions.torlauncher.socks_port_use_ipc is true and
 | |
| 510 | -      //    extensions.torlauncher.socks_ipc_path is set, an IPC object at
 | |
| 511 | -      //    the specified path is used.
 | |
| 512 | -      // 6. Tor Launcher is disabled. Torbutton will respect the env vars if
 | |
| 513 | -      //    present; if not, the values in network.proxy.socks and
 | |
| 514 | -      //    network.proxy.socks_port are used without modification.
 | |
| 515 | - | |
| 516 | -      let useIPC;
 | |
| 517 | -      this._SOCKSPortInfo = { ipcFile: undefined, host: undefined, port: 0 };
 | |
| 518 | -      if (!isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
 | |
| 519 | -        let ipcPath = Services.env.get("TOR_SOCKS_IPC_PATH");
 | |
| 520 | -        this._SOCKSPortInfo.ipcFile = new lazy.FileUtils.File(ipcPath);
 | |
| 521 | -        useIPC = true;
 | |
| 522 | -      } else {
 | |
| 523 | -        // Check for TCP host and port environment variables.
 | |
| 524 | -        if (Services.env.exists("TOR_SOCKS_HOST")) {
 | |
| 525 | -          this._SOCKSPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
 | |
| 526 | -          useIPC = false;
 | |
| 527 | -        }
 | |
| 528 | -        if (Services.env.exists("TOR_SOCKS_PORT")) {
 | |
| 529 | -          this._SOCKSPortInfo.port = parseInt(
 | |
| 530 | -            Services.env.get("TOR_SOCKS_PORT"),
 | |
| 531 | -            10
 | |
| 532 | -          );
 | |
| 533 | -          useIPC = false;
 | |
| 534 | -        }
 | |
| 535 | -      }
 | |
| 536 | - | |
| 537 | -      if (useIPC === undefined) {
 | |
| 538 | -        useIPC =
 | |
| 539 | -          !isWindows &&
 | |
| 540 | -          Services.prefs.getBoolPref(
 | |
| 541 | -            "extensions.torlauncher.socks_port_use_ipc",
 | |
| 542 | -            false
 | |
| 543 | -          );
 | |
| 544 | -      }
 | |
| 545 | - | |
| 546 | -      // Fill in missing SOCKS info from prefs.
 | |
| 547 | -      if (useIPC) {
 | |
| 548 | -        if (!this._SOCKSPortInfo.ipcFile) {
 | |
| 549 | -          this._SOCKSPortInfo.ipcFile = TorLauncherUtil.getTorFile(
 | |
| 550 | -            "socks_ipc",
 | |
| 551 | -            false
 | |
| 552 | -          );
 | |
| 553 | -        }
 | |
| 554 | -      } else {
 | |
| 555 | -        if (!this._SOCKSPortInfo.host) {
 | |
| 556 | -          let socksAddr = Services.prefs.getCharPref(
 | |
| 557 | -            "network.proxy.socks",
 | |
| 558 | -            "127.0.0.1"
 | |
| 559 | -          );
 | |
| 560 | -          let socksAddrHasHost = socksAddr && !socksAddr.startsWith("file:");
 | |
| 561 | -          this._SOCKSPortInfo.host = socksAddrHasHost ? socksAddr : "127.0.0.1";
 | |
| 562 | -        }
 | |
| 563 | - | |
| 564 | -        if (!this._SOCKSPortInfo.port) {
 | |
| 565 | -          let socksPort = Services.prefs.getIntPref(
 | |
| 566 | -            "network.proxy.socks_port",
 | |
| 567 | -            0
 | |
| 568 | -          );
 | |
| 569 | -          // This pref is set as 0 by default in Firefox, use 9150 if we get 0.
 | |
| 570 | -          this._SOCKSPortInfo.port = socksPort != 0 ? socksPort : 9150;
 | |
| 571 | -        }
 | |
| 572 | -      }
 | |
| 573 | - | |
| 574 | -      logger.info("SOCKS port type: " + (useIPC ? "IPC" : "TCP"));
 | |
| 575 | -      if (useIPC) {
 | |
| 576 | -        logger.info(`ipcFile: ${this._SOCKSPortInfo.ipcFile.path}`);
 | |
| 577 | -      } else {
 | |
| 578 | -        logger.info(`SOCKS host: ${this._SOCKSPortInfo.host}`);
 | |
| 579 | -        logger.info(`SOCKS port: ${this._SOCKSPortInfo.port}`);
 | |
| 580 | -      }
 | |
| 489 | +      this._SOCKSPortInfo = TorLauncherUtil.getPreferredSocksConfiguration();
 | |
| 490 | +      TorLauncherUtil.setProxyConfiguration(this._SOCKSPortInfo);
 | |
| 581 | 491 | |
| 582 | 492 |        // Set the global control port info parameters.
 | 
| 583 | 493 |        // These values may be overwritten by torbutton when it initializes, but
 | 
| ... | ... | @@ -781,38 +691,6 @@ export const TorProtocolService = { | 
| 781 | 691 |      return pwd;
 | 
| 782 | 692 |    },
 | 
| 783 | 693 | |
| 784 | -  // Based on Vidalia's TorSettings::hashPassword().
 | |
| 785 | -  _hashPassword(aHexPassword) {
 | |
| 786 | -    if (!aHexPassword) {
 | |
| 787 | -      return null;
 | |
| 788 | -    }
 | |
| 789 | - | |
| 790 | -    // Generate a random, 8 byte salt value.
 | |
| 791 | -    const salt = Array.from(crypto.getRandomValues(new Uint8Array(8)));
 | |
| 792 | - | |
| 793 | -    // Convert hex-encoded password to an array of bytes.
 | |
| 794 | -    const password = [];
 | |
| 795 | -    for (let i = 0; i < aHexPassword.length; i += 2) {
 | |
| 796 | -      password.push(parseInt(aHexPassword.substring(i, i + 2), 16));
 | |
| 797 | -    }
 | |
| 798 | - | |
| 799 | -    // Run through the S2K algorithm and convert to a string.
 | |
| 800 | -    const kCodedCount = 96;
 | |
| 801 | -    const hashVal = this._cryptoSecretToKey(password, salt, kCodedCount);
 | |
| 802 | -    if (!hashVal) {
 | |
| 803 | -      logger.error("_cryptoSecretToKey() failed");
 | |
| 804 | -      return null;
 | |
| 805 | -    }
 | |
| 806 | - | |
| 807 | -    const arrayToHex = aArray =>
 | |
| 808 | -      aArray.map(item => this._toHex(item, 2)).join("");
 | |
| 809 | -    let rv = "16:";
 | |
| 810 | -    rv += arrayToHex(salt);
 | |
| 811 | -    rv += this._toHex(kCodedCount, 2);
 | |
| 812 | -    rv += arrayToHex(hashVal);
 | |
| 813 | -    return rv;
 | |
| 814 | -  },
 | |
| 815 | - | |
| 816 | 694 |    // Returns -1 upon failure.
 | 
| 817 | 695 |    _cryptoRandInt(aMax) {
 | 
| 818 | 696 |      // Based on tor's crypto_rand_int().
 | 
| ... | ... | @@ -831,43 +709,6 @@ export const TorProtocolService = { | 
| 831 | 709 |      return val % aMax;
 | 
| 832 | 710 |    },
 | 
| 833 | 711 | |
| 834 | -  // _cryptoSecretToKey() is similar to Vidalia's crypto_secret_to_key().
 | |
| 835 | -  // It generates and returns a hash of aPassword by following the iterated
 | |
| 836 | -  // and salted S2K algorithm (see RFC 2440 section 3.6.1.3).
 | |
| 837 | -  // Returns an array of bytes.
 | |
| 838 | -  _cryptoSecretToKey(aPassword, aSalt, aCodedCount) {
 | |
| 839 | -    if (!aPassword || !aSalt) {
 | |
| 840 | -      return null;
 | |
| 841 | -    }
 | |
| 842 | - | |
| 843 | -    const inputArray = aSalt.concat(aPassword);
 | |
| 844 | - | |
| 845 | -    // Subtle crypto only has the final digest, and does not allow incremental
 | |
| 846 | -    // updates. Also, it is async, so we should hash and keep the hash in a
 | |
| 847 | -    // variable if we wanted to switch to getters.
 | |
| 848 | -    // So, keeping this implementation should be okay for now.
 | |
| 849 | -    const hasher = Cc["@mozilla.org/security/hash;1"].createInstance(
 | |
| 850 | -      Ci.nsICryptoHash
 | |
| 851 | -    );
 | |
| 852 | -    hasher.init(hasher.SHA1);
 | |
| 853 | -    const kEXPBIAS = 6;
 | |
| 854 | -    let count = (16 + (aCodedCount & 15)) << ((aCodedCount >> 4) + kEXPBIAS);
 | |
| 855 | -    while (count > 0) {
 | |
| 856 | -      if (count > inputArray.length) {
 | |
| 857 | -        hasher.update(inputArray, inputArray.length);
 | |
| 858 | -        count -= inputArray.length;
 | |
| 859 | -      } else {
 | |
| 860 | -        const finalArray = inputArray.slice(0, count);
 | |
| 861 | -        hasher.update(finalArray, finalArray.length);
 | |
| 862 | -        count = 0;
 | |
| 863 | -      }
 | |
| 864 | -    }
 | |
| 865 | -    return hasher
 | |
| 866 | -      .finish(false)
 | |
| 867 | -      .split("")
 | |
| 868 | -      .map(b => b.charCodeAt(0));
 | |
| 869 | -  },
 | |
| 870 | - | |
| 871 | 712 |    _toHex(aValue, aMinLen) {
 | 
| 872 | 713 |      return aValue.toString(16).padStart(aMinLen, "0");
 | 
| 873 | 714 |    },
 | 
| ... | ... | @@ -60,7 +60,7 @@ var torbutton_init; | 
| 60 | 60 |      } else {
 | 
| 61 | 61 |        try {
 | 
| 62 | 62 |          // Try to get password from Tor Launcher.
 | 
| 63 | -        m_tb_control_pass = TorProtocolService.torGetPassword(false);
 | |
| 63 | +        m_tb_control_pass = TorProtocolService.torGetPassword();
 | |
| 64 | 64 |        } catch (e) {}
 | 
| 65 | 65 |      }
 | 
| 66 | 66 | 
| 1 | 1 |  Classes = [
 | 
| 2 | -    {
 | |
| 3 | -        "cid": "{06322def-6fde-4c06-aef6-47ae8e799629}",
 | |
| 4 | -        "contract_ids": [
 | |
| 5 | -            "@torproject.org/startup-observer;1"
 | |
| 6 | -        ],
 | |
| 7 | -        "jsm": "resource://torbutton/modules/TorbuttonStartupObserver.jsm",
 | |
| 8 | -        "constructor": "StartupObserver",
 | |
| 9 | -    },
 | |
| 10 | 2 |      {
 | 
| 11 | 3 |          "cid": "{f36d72c9-9718-4134-b550-e109638331d7}",
 | 
| 12 | 4 |          "contract_ids": [
 | 
| 1 | -// Bug 1506 P1-3: This code is mostly hackish remnants of session store
 | |
| 2 | -// support. There are a couple of observer events that *might* be worth
 | |
| 3 | -// listening to. Search for 1506 in the code.
 | |
| 4 | - | |
| 5 | -/*************************************************************************
 | |
| 6 | - * Startup observer (_javascript_ XPCOM component)
 | |
| 7 | - *
 | |
| 8 | - * Cases tested (each during Tor and Non-Tor, FF4 and FF3.6)
 | |
| 9 | - *    1. Crash
 | |
| 10 | - *    2. Upgrade
 | |
| 11 | - *    3. Fresh install
 | |
| 12 | - *
 | |
| 13 | - *************************************************************************/
 | |
| 14 | - | |
| 15 | -var EXPORTED_SYMBOLS = ["StartupObserver"];
 | |
| 16 | - | |
| 17 | -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 | |
| 18 | -const { XPCOMUtils } = ChromeUtils.import(
 | |
| 19 | -  "resource://gre/modules/XPCOMUtils.jsm"
 | |
| 20 | -);
 | |
| 21 | - | |
| 22 | -const { TorProtocolService } = ChromeUtils.import(
 | |
| 23 | -  "resource://gre/modules/TorProtocolService.jsm"
 | |
| 24 | -);
 | |
| 25 | - | |
| 26 | -const lazy = {};
 | |
| 27 | - | |
| 28 | -XPCOMUtils.defineLazyModuleGetters(lazy, {
 | |
| 29 | -  FileUtils: "resource://gre/modules/FileUtils.jsm",
 | |
| 30 | -});
 | |
| 31 | - | |
| 32 | -function StartupObserver() {
 | |
| 33 | -  this.logger = Cc["@torproject.org/torbutton-logger;1"].getService(
 | |
| 34 | -    Ci.nsISupports
 | |
| 35 | -  ).wrappedJSObject;
 | |
| 36 | -  this._prefs = Services.prefs;
 | |
| 37 | -  this.logger.log(3, "Startup Observer created");
 | |
| 38 | - | |
| 39 | -  try {
 | |
| 40 | -    // XXX: We're in a race with HTTPS-Everywhere to update our proxy settings
 | |
| 41 | -    // before the initial SSL-Observatory test... If we lose the race, Firefox
 | |
| 42 | -    // caches the old proxy settings for check.tp.o somehwere, and it never loads :(
 | |
| 43 | -    this.setProxySettings();
 | |
| 44 | -  } catch (e) {
 | |
| 45 | -    this.logger.log(
 | |
| 46 | -      4,
 | |
| 47 | -      "Early proxy change failed. Will try again at profile load. Error: " + e
 | |
| 48 | -    );
 | |
| 49 | -  }
 | |
| 50 | -}
 | |
| 51 | - | |
| 52 | -StartupObserver.prototype = {
 | |
| 53 | -  // Bug 6803: We need to get the env vars early due to
 | |
| 54 | -  // some weird proxy caching code that showed up in FF15.
 | |
| 55 | -  // Otherwise, homepage domain loads fail forever.
 | |
| 56 | -  setProxySettings() {
 | |
| 57 | -    // Bug 1506: Still want to get these env vars
 | |
| 58 | -    if (Services.env.exists("TOR_TRANSPROXY")) {
 | |
| 59 | -      this.logger.log(3, "Resetting Tor settings to transproxy");
 | |
| 60 | -      this._prefs.setBoolPref("network.proxy.socks_remote_dns", false);
 | |
| 61 | -      this._prefs.setIntPref("network.proxy.type", 0);
 | |
| 62 | -      this._prefs.setIntPref("network.proxy.socks_port", 0);
 | |
| 63 | -      this._prefs.setCharPref("network.proxy.socks", "");
 | |
| 64 | -    } else {
 | |
| 65 | -      // Try to retrieve SOCKS proxy settings from Tor Launcher.
 | |
| 66 | -      let socksPortInfo;
 | |
| 67 | -      try {
 | |
| 68 | -        socksPortInfo = TorProtocolService.torGetSOCKSPortInfo();
 | |
| 69 | -      } catch (e) {
 | |
| 70 | -        this.logger.log(3, "tor launcher failed " + e);
 | |
| 71 | -      }
 | |
| 72 | - | |
| 73 | -      // If Tor Launcher is not available, check environment variables.
 | |
| 74 | -      if (!socksPortInfo) {
 | |
| 75 | -        socksPortInfo = { ipcFile: undefined, host: undefined, port: 0 };
 | |
| 76 | - | |
| 77 | -        let isWindows = Services.appinfo.OS === "WINNT";
 | |
| 78 | -        if (!isWindows && Services.env.exists("TOR_SOCKS_IPC_PATH")) {
 | |
| 79 | -          socksPortInfo.ipcFile = new lazy.FileUtils.File(
 | |
| 80 | -            Services.env.get("TOR_SOCKS_IPC_PATH")
 | |
| 81 | -          );
 | |
| 82 | -        } else {
 | |
| 83 | -          if (Services.env.exists("TOR_SOCKS_HOST")) {
 | |
| 84 | -            socksPortInfo.host = Services.env.get("TOR_SOCKS_HOST");
 | |
| 85 | -          }
 | |
| 86 | -          if (Services.env.exists("TOR_SOCKS_PORT")) {
 | |
| 87 | -            socksPortInfo.port = parseInt(Services.env.get("TOR_SOCKS_PORT"));
 | |
| 88 | -          }
 | |
| 89 | -        }
 | |
| 90 | -      }
 | |
| 91 | - | |
| 92 | -      // Adjust network.proxy prefs.
 | |
| 93 | -      if (socksPortInfo.ipcFile) {
 | |
| 94 | -        let fph = Services.io
 | |
| 95 | -          .getProtocolHandler("file")
 | |
| 96 | -          .QueryInterface(Ci.nsIFileProtocolHandler);
 | |
| 97 | -        let fileURI = fph.newFileURI(socksPortInfo.ipcFile);
 | |
| 98 | -        this.logger.log(3, "Reset socks to " + fileURI.spec);
 | |
| 99 | -        this._prefs.setCharPref("network.proxy.socks", fileURI.spec);
 | |
| 100 | -        this._prefs.setIntPref("network.proxy.socks_port", 0);
 | |
| 101 | -      } else {
 | |
| 102 | -        if (socksPortInfo.host) {
 | |
| 103 | -          this._prefs.setCharPref("network.proxy.socks", socksPortInfo.host);
 | |
| 104 | -          this.logger.log(3, "Reset socks host to " + socksPortInfo.host);
 | |
| 105 | -        }
 | |
| 106 | -        if (socksPortInfo.port) {
 | |
| 107 | -          this._prefs.setIntPref(
 | |
| 108 | -            "network.proxy.socks_port",
 | |
| 109 | -            socksPortInfo.port
 | |
| 110 | -          );
 | |
| 111 | -          this.logger.log(3, "Reset socks port to " + socksPortInfo.port);
 | |
| 112 | -        }
 | |
| 113 | -      }
 | |
| 114 | - | |
| 115 | -      if (socksPortInfo.ipcFile || socksPortInfo.host || socksPortInfo.port) {
 | |
| 116 | -        this._prefs.setBoolPref("network.proxy.socks_remote_dns", true);
 | |
| 117 | -        this._prefs.setIntPref("network.proxy.type", 1);
 | |
| 118 | -      }
 | |
| 119 | -    }
 | |
| 120 | - | |
| 121 | -    // Force prefs to be synced to disk
 | |
| 122 | -    Services.prefs.savePrefFile(null);
 | |
| 123 | - | |
| 124 | -    this.logger.log(3, "Synced network settings to environment.");
 | |
| 125 | -  },
 | |
| 126 | - | |
| 127 | -  observe(subject, topic, data) {
 | |
| 128 | -    if (topic == "profile-after-change") {
 | |
| 129 | -      this.setProxySettings();
 | |
| 130 | -    }
 | |
| 131 | - | |
| 132 | -    // In all cases, force prefs to be synced to disk
 | |
| 133 | -    Services.prefs.savePrefFile(null);
 | |
| 134 | -  },
 | |
| 135 | - | |
| 136 | -  // Hack to get us registered early to observe recovery
 | |
| 137 | -  _xpcom_categories: [{ category: "profile-after-change" }],
 | |
| 138 | -}; | 
| ... | ... | @@ -8,7 +8,3 @@ JAR_MANIFESTS += ['jar.mn'] | 
| 8 | 8 |  XPCOM_MANIFESTS += [
 | 
| 9 | 9 |      "components.conf",
 | 
| 10 | 10 |  ] | 
| 11 | - | |
| 12 | -EXTRA_COMPONENTS += [
 | |
| 13 | -    "torbutton.manifest",
 | |
| 14 | -] | 
| 1 | -category profile-after-change StartupObserver @torproject.org/startup-observer;1 |