Pier Angelo Vendrame pushed to branch tor-browser-128.7.0esr-14.5-1 at The Tor Project / Applications / Tor Browser
Commits:
-
6c4f2b1c
by Henry Wilkes at 2025-02-10T16:10:58+00:00
-
3e08adbf
by Henry Wilkes at 2025-02-10T16:10:59+00:00
-
f3a86166
by Henry Wilkes at 2025-02-10T16:10:59+00:00
-
b97265e0
by Henry Wilkes at 2025-02-10T16:12:36+00:00
7 changed files:
- browser/components/BrowserGlue.sys.mjs
- browser/components/torpreferences/content/connectionPane.js
- browser/components/torpreferences/content/connectionPane.xhtml
- browser/components/torpreferences/content/torPreferences.css
- toolkit/locales/en-US/toolkit/global/tor-browser.ftl
- toolkit/modules/Moat.sys.mjs
- toolkit/modules/TorConnect.sys.mjs
Changes:
| ... | ... | @@ -4824,6 +4824,7 @@ BrowserGlue.prototype = { |
| 4824 | 4824 | // since we hid the UI (tor-browser#43118).
|
| 4825 | 4825 | // Version 6: Tor Browser 14.5a3: Clear preference for TorSettings that is
|
| 4826 | 4826 | // no longer used (tor-browser#41921).
|
| 4827 | + // Drop unused TorConnect setting (tor-browser#43462).
|
|
| 4827 | 4828 | const TBB_MIGRATION_VERSION = 6;
|
| 4828 | 4829 | const MIGRATION_PREF = "torbrowser.migration.version";
|
| 4829 | 4830 | |
| ... | ... | @@ -4908,6 +4909,7 @@ BrowserGlue.prototype = { |
| 4908 | 4909 | |
| 4909 | 4910 | if (currentVersion < 6) {
|
| 4910 | 4911 | Services.prefs.clearUserPref("torbrowser.settings.enabled");
|
| 4912 | + Services.prefs.clearUserPref("torbrowser.bootstrap.allow_internet_test");
|
|
| 4911 | 4913 | }
|
| 4912 | 4914 | |
| 4913 | 4915 | Services.prefs.setIntPref(MIGRATION_PREF, TBB_MIGRATION_VERSION);
|
| ... | ... | @@ -22,13 +22,9 @@ const { TorProviderBuilder, TorProviderTopics } = ChromeUtils.importESModule( |
| 22 | 22 | "resource://gre/modules/TorProviderBuilder.sys.mjs"
|
| 23 | 23 | );
|
| 24 | 24 | |
| 25 | -const { TorConnect, TorConnectTopics, TorConnectStage, TorCensorshipLevel } =
|
|
| 25 | +const { InternetStatus, TorConnect, TorConnectTopics, TorConnectStage } =
|
|
| 26 | 26 | ChromeUtils.importESModule("resource://gre/modules/TorConnect.sys.mjs");
|
| 27 | 27 | |
| 28 | -const { MoatRPC } = ChromeUtils.importESModule(
|
|
| 29 | - "resource://gre/modules/Moat.sys.mjs"
|
|
| 30 | -);
|
|
| 31 | - |
|
| 32 | 28 | const { QRCode } = ChromeUtils.importESModule(
|
| 33 | 29 | "resource://gre/modules/QRCode.sys.mjs"
|
| 34 | 30 | );
|
| ... | ... | @@ -2371,12 +2367,6 @@ const gNetworkStatus = { |
| 2371 | 2367 | this._internetResultEl = this._internetAreaEl.querySelector(
|
| 2372 | 2368 | ".network-status-result"
|
| 2373 | 2369 | );
|
| 2374 | - this._internetTestButton = document.getElementById(
|
|
| 2375 | - "network-status-internet-test-button"
|
|
| 2376 | - );
|
|
| 2377 | - this._internetTestButton.addEventListener("click", () => {
|
|
| 2378 | - this._startInternetTest();
|
|
| 2379 | - });
|
|
| 2380 | 2370 | |
| 2381 | 2371 | this._torAreaEl = document.getElementById("network-status-tor-area");
|
| 2382 | 2372 | this._torResultEl = this._torAreaEl.querySelector(".network-status-result");
|
| ... | ... | @@ -2387,10 +2377,11 @@ const gNetworkStatus = { |
| 2387 | 2377 | TorConnect.openTorConnect({ beginBootstrapping: "soft" });
|
| 2388 | 2378 | });
|
| 2389 | 2379 | |
| 2390 | - this._updateInternetStatus("unknown");
|
|
| 2380 | + this._updateInternetStatus();
|
|
| 2391 | 2381 | this._updateTorConnectionStatus();
|
| 2392 | 2382 | |
| 2393 | 2383 | Services.obs.addObserver(this, TorConnectTopics.StageChange);
|
| 2384 | + Services.obs.addObserver(this, TorConnectTopics.InternetStatusChange);
|
|
| 2394 | 2385 | },
|
| 2395 | 2386 | |
| 2396 | 2387 | /**
|
| ... | ... | @@ -2398,98 +2389,42 @@ const gNetworkStatus = { |
| 2398 | 2389 | */
|
| 2399 | 2390 | uninit() {
|
| 2400 | 2391 | Services.obs.removeObserver(this, TorConnectTopics.StageChange);
|
| 2392 | + Services.obs.removeObserver(this, TorConnectTopics.InternetStatusChange);
|
|
| 2401 | 2393 | },
|
| 2402 | 2394 | |
| 2403 | 2395 | observe(subject, topic) {
|
| 2404 | 2396 | switch (topic) {
|
| 2405 | 2397 | // triggered when tor connect state changes and we may
|
| 2406 | 2398 | // need to update the messagebox
|
| 2407 | - case TorConnectTopics.StageChange: {
|
|
| 2399 | + case TorConnectTopics.StageChange:
|
|
| 2408 | 2400 | this._updateTorConnectionStatus();
|
| 2409 | 2401 | break;
|
| 2410 | - }
|
|
| 2411 | - }
|
|
| 2412 | - },
|
|
| 2413 | - |
|
| 2414 | - /**
|
|
| 2415 | - * Whether the test should be disabled.
|
|
| 2416 | - *
|
|
| 2417 | - * @type {boolean}
|
|
| 2418 | - */
|
|
| 2419 | - _internetTestDisabled: false,
|
|
| 2420 | - /**
|
|
| 2421 | - * Start the internet test.
|
|
| 2422 | - */
|
|
| 2423 | - async _startInternetTest() {
|
|
| 2424 | - if (this._internetTestDisabled) {
|
|
| 2425 | - return;
|
|
| 2426 | - }
|
|
| 2427 | - this._internetTestDisabled = true;
|
|
| 2428 | - // We use "aria-disabled" rather than the "disabled" attribute so that the
|
|
| 2429 | - // button can remain focusable during the test.
|
|
| 2430 | - // TODO: Replace with moz-button when it handles this for us. See
|
|
| 2431 | - // tor-browser#43275.
|
|
| 2432 | - this._internetTestButton.setAttribute("aria-disabled", "true");
|
|
| 2433 | - this._internetTestButton.classList.add("spoof-button-disabled");
|
|
| 2434 | - this._internetTestButton.tabIndex = -1;
|
|
| 2435 | - try {
|
|
| 2436 | - this._updateInternetStatus("testing");
|
|
| 2437 | - const mrpc = new MoatRPC();
|
|
| 2438 | - let status = null;
|
|
| 2439 | - try {
|
|
| 2440 | - await mrpc.init();
|
|
| 2441 | - status = await mrpc.testInternetConnection();
|
|
| 2442 | - } catch (err) {
|
|
| 2443 | - log.error("Error while checking the Internet connection", err);
|
|
| 2444 | - } finally {
|
|
| 2445 | - mrpc.uninit();
|
|
| 2446 | - }
|
|
| 2447 | - if (status) {
|
|
| 2448 | - this._updateInternetStatus(status.successful ? "online" : "offline");
|
|
| 2449 | - } else {
|
|
| 2450 | - this._updateInternetStatus("unknown");
|
|
| 2451 | - }
|
|
| 2452 | - } finally {
|
|
| 2453 | - this._internetTestButton.removeAttribute("aria-disabled");
|
|
| 2454 | - this._internetTestButton.classList.remove("spoof-button-disabled");
|
|
| 2455 | - this._internetTestButton.tabIndex = 0;
|
|
| 2456 | - this._internetTestDisabled = false;
|
|
| 2402 | + case TorConnectTopics.InternetStatusChange:
|
|
| 2403 | + this._updateInternetStatus();
|
|
| 2404 | + break;
|
|
| 2457 | 2405 | }
|
| 2458 | 2406 | },
|
| 2459 | 2407 | |
| 2460 | 2408 | /**
|
| 2461 | 2409 | * Update the shown internet status.
|
| 2462 | - *
|
|
| 2463 | - * @param {string} stateName - The name of the state to show.
|
|
| 2464 | 2410 | */
|
| 2465 | - _updateInternetStatus(stateName) {
|
|
| 2411 | + _updateInternetStatus() {
|
|
| 2466 | 2412 | let l10nId;
|
| 2467 | - switch (stateName) {
|
|
| 2468 | - case "testing":
|
|
| 2469 | - l10nId = "tor-connection-internet-status-testing";
|
|
| 2470 | - break;
|
|
| 2471 | - case "offline":
|
|
| 2413 | + let isOffline = false;
|
|
| 2414 | + switch (TorConnect.internetStatus) {
|
|
| 2415 | + case InternetStatus.Offline:
|
|
| 2472 | 2416 | l10nId = "tor-connection-internet-status-offline";
|
| 2417 | + isOffline = true;
|
|
| 2473 | 2418 | break;
|
| 2474 | - case "online":
|
|
| 2419 | + case InternetStatus.Online:
|
|
| 2475 | 2420 | l10nId = "tor-connection-internet-status-online";
|
| 2476 | 2421 | break;
|
| 2422 | + default:
|
|
| 2423 | + l10nId = "tor-connection-internet-status-unknown";
|
|
| 2424 | + break;
|
|
| 2477 | 2425 | }
|
| 2478 | - if (l10nId) {
|
|
| 2479 | - this._internetResultEl.setAttribute("data-l10n-id", l10nId);
|
|
| 2480 | - } else {
|
|
| 2481 | - this._internetResultEl.removeAttribute("data-l10n-id");
|
|
| 2482 | - this._internetResultEl.textContent = "";
|
|
| 2483 | - }
|
|
| 2484 | - |
|
| 2485 | - this._internetAreaEl.classList.toggle(
|
|
| 2486 | - "status-loading",
|
|
| 2487 | - stateName === "testing"
|
|
| 2488 | - );
|
|
| 2489 | - this._internetAreaEl.classList.toggle(
|
|
| 2490 | - "status-offline",
|
|
| 2491 | - stateName === "offline"
|
|
| 2492 | - );
|
|
| 2426 | + this._internetResultEl.setAttribute("data-l10n-id", l10nId);
|
|
| 2427 | + this._internetAreaEl.classList.toggle("status-offline", isOffline);
|
|
| 2493 | 2428 | },
|
| 2494 | 2429 | |
| 2495 | 2430 | /**
|
| ... | ... | @@ -31,27 +31,15 @@ |
| 31 | 31 | aria-labelledby="network-status-internet-area-label"
|
| 32 | 32 | >
|
| 33 | 33 | <html:img alt="" class="network-status-icon" />
|
| 34 | - <!-- Use an aria-live area to announce "Internet: Online" or
|
|
| 35 | - - "Internet: Offline". We only expect this to change when triggered by
|
|
| 36 | - - the user clicking the "Test" button, so shouldn't occur unexpectedly.
|
|
| 37 | - -->
|
|
| 38 | - <html:div
|
|
| 39 | - class="network-status-live-area"
|
|
| 40 | - aria-live="polite"
|
|
| 41 | - aria-atomic="true"
|
|
| 42 | - >
|
|
| 43 | - <html:span
|
|
| 44 | - id="network-status-internet-area-label"
|
|
| 45 | - class="network-status-label"
|
|
| 46 | - data-l10n-id="tor-connection-internet-status-label"
|
|
| 47 | - ></html:span>
|
|
| 48 | - <img alt="" class="network-status-loading-icon tor-loading-icon" />
|
|
| 49 | - <html:span class="network-status-result"></html:span>
|
|
| 50 | - </html:div>
|
|
| 51 | - <html:button
|
|
| 52 | - id="network-status-internet-test-button"
|
|
| 53 | - data-l10n-id="tor-connection-internet-status-test-button"
|
|
| 54 | - ></html:button>
|
|
| 34 | + <!-- NOTE: We do not wrap the label and status ("Internet: Offline", etc)
|
|
| 35 | + - in an aria-live area because it may be too noisey and may not be
|
|
| 36 | + - important to the user. -->
|
|
| 37 | + <html:span
|
|
| 38 | + id="network-status-internet-area-label"
|
|
| 39 | + class="network-status-label"
|
|
| 40 | + data-l10n-id="tor-connection-internet-status-label"
|
|
| 41 | + ></html:span>
|
|
| 42 | + <html:span class="network-status-result"></html:span>
|
|
| 55 | 43 | </html:div>
|
| 56 | 44 | <html:div
|
| 57 | 45 | id="network-status-tor-area"
|
| ... | ... | @@ -60,8 +48,8 @@ |
| 60 | 48 | aria-labelledby="network-status-tor-area-label"
|
| 61 | 49 | >
|
| 62 | 50 | <html:img alt="" class="network-status-icon" />
|
| 63 | - <!-- NOTE: Unlike #network-status-internet-area, we do not wrap the label
|
|
| 64 | - - and status ("Tor network: Not connected", etc) in an aria-live area.
|
|
| 51 | + <!-- NOTE: We do not wrap the label and status
|
|
| 52 | + - ("Tor network: Not connected", etc) in an aria-live area.
|
|
| 65 | 53 | - This is not likely to change whilst this page has focus.
|
| 66 | 54 | - Moreover, the status is already present in the torconnect status bar
|
| 67 | 55 | - in the window tab bar. -->
|
| ... | ... | @@ -90,24 +90,12 @@ button.spoof-button-disabled { |
| 90 | 90 | }
|
| 91 | 91 | }
|
| 92 | 92 | |
| 93 | -.network-status-live-area {
|
|
| 94 | - display: contents;
|
|
| 95 | -}
|
|
| 96 | - |
|
| 97 | 93 | .network-status-label {
|
| 98 | 94 | font-weight: bold;
|
| 99 | 95 | margin-inline-end: 0.75em;
|
| 100 | 96 | }
|
| 101 | 97 | |
| 102 | -.network-status-loading-icon {
|
|
| 103 | - margin-inline-end: 0.5em;
|
|
| 104 | -}
|
|
| 105 | - |
|
| 106 | -#network-status-internet-area:not(.status-loading) .network-status-loading-icon {
|
|
| 107 | - display: none;
|
|
| 108 | -}
|
|
| 109 | - |
|
| 110 | -.network-status-result:not(:empty) {
|
|
| 98 | +.network-status-result {
|
|
| 111 | 99 | margin-inline-end: 0.75em;
|
| 112 | 100 | }
|
| 113 | 101 |
| ... | ... | @@ -65,19 +65,15 @@ tor-connection-quickstart-checkbox = |
| 65 | 65 | # Prefix before the internet connection status.
|
| 66 | 66 | # "Internet" is not a proper noun, but is capitalized because it is the start of a sentence.
|
| 67 | 67 | tor-connection-internet-status-label = Internet:
|
| 68 | -# Button to test the internet connection.
|
|
| 69 | -# Here "Test" is a verb, as in "test the internet connection".
|
|
| 70 | -# Uses sentence case in English (US).
|
|
| 71 | -tor-connection-internet-status-test-button = Test
|
|
| 72 | -# Shown when testing the internet status.
|
|
| 73 | -# Uses sentence case in English (US).
|
|
| 74 | -tor-connection-internet-status-testing = Testing…
|
|
| 75 | 68 | # Shown when the user is connected to the internet.
|
| 76 | 69 | # Uses sentence case in English (US).
|
| 77 | 70 | tor-connection-internet-status-online = Online
|
| 78 | 71 | # Shown when the user is not connected to the internet.
|
| 79 | 72 | # Uses sentence case in English (US).
|
| 80 | 73 | tor-connection-internet-status-offline = Offline
|
| 74 | +# Shown when the user has an unknown internet connection status.
|
|
| 75 | +# Uses sentence case in English (US).
|
|
| 76 | +tor-connection-internet-status-unknown = Unknown status
|
|
| 81 | 77 | |
| 82 | 78 | # Prefix before the Tor network connection status.
|
| 83 | 79 | # Uses sentence case in English (US).
|
| ... | ... | @@ -23,57 +23,6 @@ const TorLauncherPrefs = Object.freeze({ |
| 23 | 23 | moat_service: "extensions.torlauncher.moat_service",
|
| 24 | 24 | });
|
| 25 | 25 | |
| 26 | -/**
|
|
| 27 | - * A special response listener that collects the received headers.
|
|
| 28 | - */
|
|
| 29 | -class InternetTestResponseListener {
|
|
| 30 | - #promise;
|
|
| 31 | - #resolve;
|
|
| 32 | - #reject;
|
|
| 33 | - constructor() {
|
|
| 34 | - this.#promise = new Promise((resolve, reject) => {
|
|
| 35 | - this.#resolve = resolve;
|
|
| 36 | - this.#reject = reject;
|
|
| 37 | - });
|
|
| 38 | - }
|
|
| 39 | - |
|
| 40 | - // callers wait on this for final response
|
|
| 41 | - get status() {
|
|
| 42 | - return this.#promise;
|
|
| 43 | - }
|
|
| 44 | - |
|
| 45 | - onStartRequest() {}
|
|
| 46 | - |
|
| 47 | - // resolve or reject our Promise
|
|
| 48 | - onStopRequest(request, status) {
|
|
| 49 | - try {
|
|
| 50 | - const statuses = {
|
|
| 51 | - components: status,
|
|
| 52 | - successful: Components.isSuccessCode(status),
|
|
| 53 | - };
|
|
| 54 | - try {
|
|
| 55 | - if (statuses.successful) {
|
|
| 56 | - statuses.http = request.responseStatus;
|
|
| 57 | - statuses.date = request.getResponseHeader("Date");
|
|
| 58 | - }
|
|
| 59 | - } catch (err) {
|
|
| 60 | - console.warn(
|
|
| 61 | - "Successful request, but could not get the HTTP status or date",
|
|
| 62 | - err
|
|
| 63 | - );
|
|
| 64 | - }
|
|
| 65 | - this.#resolve(statuses);
|
|
| 66 | - } catch (err) {
|
|
| 67 | - this.#reject(err);
|
|
| 68 | - }
|
|
| 69 | - }
|
|
| 70 | - |
|
| 71 | - onDataAvailable() {
|
|
| 72 | - // We do not care of the actual data, as long as we have a successful
|
|
| 73 | - // connection
|
|
| 74 | - }
|
|
| 75 | -}
|
|
| 76 | - |
|
| 77 | 26 | /**
|
| 78 | 27 | * @typedef {Object} MoatBridges
|
| 79 | 28 | *
|
| ... | ... | @@ -184,18 +133,6 @@ export class MoatRPC { |
| 184 | 133 | return { response, cancelled };
|
| 185 | 134 | }
|
| 186 | 135 | |
| 187 | - async testInternetConnection() {
|
|
| 188 | - const uri = `${Services.prefs.getStringPref(
|
|
| 189 | - TorLauncherPrefs.moat_service
|
|
| 190 | - )}/circumvention/countries`;
|
|
| 191 | - const ch = this.#requestBuilder.buildHttpHandler(uri);
|
|
| 192 | - ch.requestMethod = "HEAD";
|
|
| 193 | - |
|
| 194 | - const listener = new InternetTestResponseListener();
|
|
| 195 | - ch.asyncOpen(listener, ch);
|
|
| 196 | - return listener.status;
|
|
| 197 | - }
|
|
| 198 | - |
|
| 199 | 136 | /**
|
| 200 | 137 | * Request a CAPTCHA challenge.
|
| 201 | 138 | *
|
| ... | ... | @@ -16,9 +16,16 @@ ChromeUtils.defineESModuleGetters(lazy, { |
| 16 | 16 | TorSettingsTopics: "resource://gre/modules/TorSettings.sys.mjs",
|
| 17 | 17 | });
|
| 18 | 18 | |
| 19 | +ChromeUtils.defineLazyGetter(lazy, "NetworkLinkService", () => {
|
|
| 20 | + return Cc["@mozilla.org/network/network-link-service;1"].getService(
|
|
| 21 | + Ci.nsINetworkLinkService
|
|
| 22 | + );
|
|
| 23 | +});
|
|
| 24 | + |
|
| 25 | +const NETWORK_LINK_TOPIC = "network:link-status-changed";
|
|
| 26 | + |
|
| 19 | 27 | const TorConnectPrefs = Object.freeze({
|
| 20 | 28 | censorship_level: "torbrowser.debug.censorship_level",
|
| 21 | - allow_internet_test: "torbrowser.bootstrap.allow_internet_test",
|
|
| 22 | 29 | log_level: "torbrowser.bootstrap.log_level",
|
| 23 | 30 | /* prompt_at_startup now controls whether the quickstart can trigger. */
|
| 24 | 31 | prompt_at_startup: "extensions.torlauncher.prompt_at_startup",
|
| ... | ... | @@ -82,6 +89,7 @@ export const TorConnectTopics = Object.freeze({ |
| 82 | 89 | // TODO: Remove torconnect:state-change when pages have switched to stage.
|
| 83 | 90 | StateChange: "torconnect:state-change",
|
| 84 | 91 | QuickstartChange: "torconnect:quickstart-change",
|
| 92 | + InternetStatusChange: "torconnect:internet-status-change",
|
|
| 85 | 93 | BootstrapProgress: "torconnect:bootstrap-progress",
|
| 86 | 94 | BootstrapComplete: "torconnect:bootstrap-complete",
|
| 87 | 95 | // TODO: Remove torconnect:error when pages have switched to stage.
|
| ... | ... | @@ -108,10 +116,6 @@ export const TorConnectTopics = Object.freeze({ |
| 108 | 116 | * should be an Array of MoatBridges objects that match the bridge settings
|
| 109 | 117 | * accepted by TorSettings.bridges, plus you may add a "simulateCensorship"
|
| 110 | 118 | * property to make only their bootstrap attempts fail.
|
| 111 | - * @property {boolean} [options.testInternet] - Whether to also test the
|
|
| 112 | - * internet connection.
|
|
| 113 | - * @property {boolean} [options.simulateOffline] - Whether to simulate an
|
|
| 114 | - * offline test result. This will not cause the bootstrap to fail.
|
|
| 115 | 119 | * @property {string} [options.regionCode] - The region code to use to fetch
|
| 116 | 120 | * auto-bootstrap settings, or "automatic" to automatically choose the region.
|
| 117 | 121 | */
|
| ... | ... | @@ -141,18 +145,6 @@ class BootstrapAttempt { |
| 141 | 145 | * @type {?TorBootstrapRequest}
|
| 142 | 146 | */
|
| 143 | 147 | #bootstrap = null;
|
| 144 | - /**
|
|
| 145 | - * The error returned by the bootstrap request, if any.
|
|
| 146 | - *
|
|
| 147 | - * @type {?Error}
|
|
| 148 | - */
|
|
| 149 | - #bootstrapError = null;
|
|
| 150 | - /**
|
|
| 151 | - * The ongoing internet test, if any.
|
|
| 152 | - *
|
|
| 153 | - * @type {?InternetTest}
|
|
| 154 | - */
|
|
| 155 | - #internetTest = null;
|
|
| 156 | 148 | /**
|
| 157 | 149 | * The method to call to complete the `run` promise.
|
| 158 | 150 | *
|
| ... | ... | @@ -192,13 +184,6 @@ class BootstrapAttempt { |
| 192 | 184 | return;
|
| 193 | 185 | }
|
| 194 | 186 | this.#resolved = true;
|
| 195 | - try {
|
|
| 196 | - // Should be ok to call this twice in the case where we "cancel" the
|
|
| 197 | - // bootstrap.
|
|
| 198 | - this.#internetTest?.cancel();
|
|
| 199 | - } catch (error) {
|
|
| 200 | - lazy.logger.error("Unexpected error in bootstrap cleanup", error);
|
|
| 201 | - }
|
|
| 202 | 187 | if (arg.error) {
|
| 203 | 188 | reject(arg.error);
|
| 204 | 189 | } else {
|
| ... | ... | @@ -259,35 +244,7 @@ class BootstrapAttempt { |
| 259 | 244 | this.#resolveRun({ result: "complete" });
|
| 260 | 245 | };
|
| 261 | 246 | this.#bootstrap.onbootstraperror = error => {
|
| 262 | - if (this.#bootstrapError) {
|
|
| 263 | - lazy.logger.warn("Another bootstrap error", error);
|
|
| 264 | - return;
|
|
| 265 | - }
|
|
| 266 | - // We have to wait for the Internet test to finish before sending the
|
|
| 267 | - // bootstrap error
|
|
| 268 | - this.#bootstrapError = error;
|
|
| 269 | - this.#maybeTransitionToError();
|
|
| 270 | - };
|
|
| 271 | - if (options.testInternet) {
|
|
| 272 | - this.#internetTest = new InternetTest(options.simulateOffline);
|
|
| 273 | - this.#internetTest.onResult = () => {
|
|
| 274 | - this.#maybeTransitionToError();
|
|
| 275 | - };
|
|
| 276 | - this.#internetTest.onError = () => {
|
|
| 277 | - this.#maybeTransitionToError();
|
|
| 278 | - };
|
|
| 279 | - }
|
|
| 280 | - |
|
| 281 | - this.#bootstrap.bootstrap();
|
|
| 282 | - }
|
|
| 283 | - |
|
| 284 | - /**
|
|
| 285 | - * Callback for when we get a new bootstrap error or a change in the internet
|
|
| 286 | - * status.
|
|
| 287 | - */
|
|
| 288 | - #maybeTransitionToError() {
|
|
| 289 | - if (this.#resolved || this.#cancelled) {
|
|
| 290 | - if (this.#bootstrapError) {
|
|
| 247 | + if (this.#resolved || this.#cancelled) {
|
|
| 291 | 248 | // We ignore this error since it occurred after cancelling (by the
|
| 292 | 249 | // user), or we have already resolved. We assume the error is just a
|
| 293 | 250 | // side effect of the cancelling.
|
| ... | ... | @@ -295,45 +252,16 @@ class BootstrapAttempt { |
| 295 | 252 | // "Building circuits: Establishing a Tor circuit failed".
|
| 296 | 253 | // TODO: Maybe move this logic deeper in the process to know when to
|
| 297 | 254 | // filter out such errors triggered by cancelling.
|
| 298 | - lazy.logger.warn("Post-complete error.", this.#bootstrapError);
|
|
| 255 | + lazy.logger.warn("Post-complete bootstrap error.", error);
|
|
| 256 | + return;
|
|
| 299 | 257 | }
|
| 300 | - return;
|
|
| 301 | - }
|
|
| 302 | 258 | |
| 303 | - if (
|
|
| 304 | - this.#internetTest &&
|
|
| 305 | - this.#internetTest.status === InternetStatus.Unknown &&
|
|
| 306 | - this.#internetTest.error === null &&
|
|
| 307 | - this.#internetTest.enabled
|
|
| 308 | - ) {
|
|
| 309 | - // We have been called by a failed bootstrap, but the internet test has
|
|
| 310 | - // not run yet - force it to run immediately!
|
|
| 311 | - this.#internetTest.test();
|
|
| 312 | - // Return from this call, because the Internet test's callback will call
|
|
| 313 | - // us again.
|
|
| 314 | - return;
|
|
| 315 | - }
|
|
| 316 | - // Do not transition to "offline" until we are sure that also the bootstrap
|
|
| 317 | - // failed, in case Moat is down but the bootstrap can proceed anyway.
|
|
| 318 | - if (!this.#bootstrapError) {
|
|
| 319 | - return;
|
|
| 320 | - }
|
|
| 321 | - if (this.#internetTest?.status === InternetStatus.Offline) {
|
|
| 322 | - if (this.#bootstrapError) {
|
|
| 323 | - lazy.logger.info(
|
|
| 324 | - "Ignoring bootstrap error since offline.",
|
|
| 325 | - this.#bootstrapError
|
|
| 326 | - );
|
|
| 327 | - }
|
|
| 328 | - this.#resolveRun({ result: "offline" });
|
|
| 329 | - return;
|
|
| 330 | - }
|
|
| 331 | - this.#resolveRun({
|
|
| 332 | - error: new TorConnectError(
|
|
| 333 | - TorConnectError.BootstrapError,
|
|
| 334 | - this.#bootstrapError
|
|
| 335 | - ),
|
|
| 336 | - });
|
|
| 259 | + this.#resolveRun({
|
|
| 260 | + error: new TorConnectError(TorConnectError.BootstrapError, error),
|
|
| 261 | + });
|
|
| 262 | + };
|
|
| 263 | + |
|
| 264 | + this.#bootstrap.bootstrap();
|
|
| 337 | 265 | }
|
| 338 | 266 | |
| 339 | 267 | /**
|
| ... | ... | @@ -355,7 +283,6 @@ class BootstrapAttempt { |
| 355 | 283 | // cancelled. In particular, there is a small chance that the bootstrap
|
| 356 | 284 | // completes, in which case we want to be able to resolve with a success
|
| 357 | 285 | // instead.
|
| 358 | - this.#internetTest?.cancel();
|
|
| 359 | 286 | await this.#bootstrap?.cancel();
|
| 360 | 287 | this.#resolveRun({ result: "cancelled" });
|
| 361 | 288 | }
|
| ... | ... | @@ -729,117 +656,6 @@ export const InternetStatus = Object.freeze({ |
| 729 | 656 | Online: 1,
|
| 730 | 657 | });
|
| 731 | 658 | |
| 732 | -class InternetTest {
|
|
| 733 | - #enabled;
|
|
| 734 | - #status = InternetStatus.Unknown;
|
|
| 735 | - #error = null;
|
|
| 736 | - #pending = false;
|
|
| 737 | - #canceled = false;
|
|
| 738 | - #timeout = 0;
|
|
| 739 | - #simulateOffline = false;
|
|
| 740 | - |
|
| 741 | - constructor(simulateOffline) {
|
|
| 742 | - this.#simulateOffline = simulateOffline;
|
|
| 743 | - |
|
| 744 | - this.#enabled = Services.prefs.getBoolPref(
|
|
| 745 | - TorConnectPrefs.allow_internet_test,
|
|
| 746 | - true
|
|
| 747 | - );
|
|
| 748 | - if (this.#enabled) {
|
|
| 749 | - this.#timeout = setTimeout(() => {
|
|
| 750 | - this.#timeout = 0;
|
|
| 751 | - this.test();
|
|
| 752 | - }, this.#timeoutRand());
|
|
| 753 | - }
|
|
| 754 | - this.onResult = _online => {};
|
|
| 755 | - this.onError = _error => {};
|
|
| 756 | - }
|
|
| 757 | - |
|
| 758 | - /**
|
|
| 759 | - * Perform the internet test.
|
|
| 760 | - *
|
|
| 761 | - * While this is an async method, the callers are not expected to await it,
|
|
| 762 | - * as we are also using callbacks.
|
|
| 763 | - */
|
|
| 764 | - async test() {
|
|
| 765 | - if (this.#pending || !this.#enabled) {
|
|
| 766 | - return;
|
|
| 767 | - }
|
|
| 768 | - this.cancel();
|
|
| 769 | - this.#pending = true;
|
|
| 770 | - this.#canceled = false;
|
|
| 771 | - |
|
| 772 | - lazy.logger.info("Starting the Internet test");
|
|
| 773 | - |
|
| 774 | - if (this.#simulateOffline) {
|
|
| 775 | - await new Promise(res => setTimeout(res, 500));
|
|
| 776 | - |
|
| 777 | - this.#status = InternetStatus.Offline;
|
|
| 778 | - |
|
| 779 | - if (this.#canceled) {
|
|
| 780 | - return;
|
|
| 781 | - }
|
|
| 782 | - this.onResult(this.#status);
|
|
| 783 | - return;
|
|
| 784 | - }
|
|
| 785 | - |
|
| 786 | - const mrpc = new lazy.MoatRPC();
|
|
| 787 | - try {
|
|
| 788 | - await mrpc.init();
|
|
| 789 | - const status = await mrpc.testInternetConnection();
|
|
| 790 | - this.#status = status.successful
|
|
| 791 | - ? InternetStatus.Online
|
|
| 792 | - : InternetStatus.Offline;
|
|
| 793 | - // TODO: We could consume the date we got from the HTTP request to detect
|
|
| 794 | - // big clock skews that might prevent a successfull bootstrap.
|
|
| 795 | - lazy.logger.info(`Performed Internet test, outcome ${this.#status}`);
|
|
| 796 | - } catch (err) {
|
|
| 797 | - lazy.logger.error("Error while checking the Internet connection", err);
|
|
| 798 | - this.#error = err;
|
|
| 799 | - this.#pending = false;
|
|
| 800 | - } finally {
|
|
| 801 | - mrpc.uninit();
|
|
| 802 | - }
|
|
| 803 | - |
|
| 804 | - if (this.#canceled) {
|
|
| 805 | - return;
|
|
| 806 | - }
|
|
| 807 | - if (this.#error) {
|
|
| 808 | - this.onError(this.#error);
|
|
| 809 | - } else {
|
|
| 810 | - this.onResult(this.#status);
|
|
| 811 | - }
|
|
| 812 | - }
|
|
| 813 | - |
|
| 814 | - cancel() {
|
|
| 815 | - this.#canceled = true;
|
|
| 816 | - if (this.#timeout) {
|
|
| 817 | - clearTimeout(this.#timeout);
|
|
| 818 | - this.#timeout = 0;
|
|
| 819 | - }
|
|
| 820 | - }
|
|
| 821 | - |
|
| 822 | - get status() {
|
|
| 823 | - return this.#status;
|
|
| 824 | - }
|
|
| 825 | - |
|
| 826 | - get error() {
|
|
| 827 | - return this.#error;
|
|
| 828 | - }
|
|
| 829 | - |
|
| 830 | - get enabled() {
|
|
| 831 | - return this.#enabled;
|
|
| 832 | - }
|
|
| 833 | - |
|
| 834 | - // We randomize the Internet test timeout to make fingerprinting it harder, at
|
|
| 835 | - // least a little bit...
|
|
| 836 | - #timeoutRand() {
|
|
| 837 | - const offset = 30000;
|
|
| 838 | - const randRange = 5000;
|
|
| 839 | - return offset + randRange * (Math.random() * 2 - 1);
|
|
| 840 | - }
|
|
| 841 | -}
|
|
| 842 | - |
|
| 843 | 659 | export const TorConnectStage = Object.freeze({
|
| 844 | 660 | Disabled: "Disabled",
|
| 845 | 661 | Loading: "Loading",
|
| ... | ... | @@ -903,6 +719,13 @@ export const TorConnect = { |
| 903 | 719 | */
|
| 904 | 720 | simulateBootstrapOptions: {},
|
| 905 | 721 | |
| 722 | + /**
|
|
| 723 | + * Whether to simulate being offline.
|
|
| 724 | + *
|
|
| 725 | + * @type {boolean}
|
|
| 726 | + */
|
|
| 727 | + simulateOffline: false,
|
|
| 728 | + |
|
| 906 | 729 | /**
|
| 907 | 730 | * The name of the current stage the user is in.
|
| 908 | 731 | *
|
| ... | ... | @@ -1004,10 +827,6 @@ export const TorConnect = { |
| 1004 | 827 | })()
|
| 1005 | 828 | ),
|
| 1006 | 829 | |
| 1007 | - // This is used as a helper to make the state of about:torconnect persistent
|
|
| 1008 | - // during a session, but TorConnect does not use this data at all.
|
|
| 1009 | - _uiState: {},
|
|
| 1010 | - |
|
| 1011 | 830 | /**
|
| 1012 | 831 | * The status of the most recent bootstrap attempt.
|
| 1013 | 832 | *
|
| ... | ... | @@ -1029,6 +848,36 @@ export const TorConnect = { |
| 1029 | 848 | );
|
| 1030 | 849 | },
|
| 1031 | 850 | |
| 851 | + /**
|
|
| 852 | + * The current internet status. One of the InternetStatus values.
|
|
| 853 | + *
|
|
| 854 | + * @type {integer}
|
|
| 855 | + */
|
|
| 856 | + _internetStatus: InternetStatus.Unknown,
|
|
| 857 | + |
|
| 858 | + get internetStatus() {
|
|
| 859 | + return this._internetStatus;
|
|
| 860 | + },
|
|
| 861 | + |
|
| 862 | + /**
|
|
| 863 | + * Update the _internetStatus value.
|
|
| 864 | + */
|
|
| 865 | + _updateInternetStatus() {
|
|
| 866 | + let newStatus;
|
|
| 867 | + if (lazy.NetworkLinkService.linkStatusKnown) {
|
|
| 868 | + newStatus = lazy.NetworkLinkService.isLinkUp
|
|
| 869 | + ? InternetStatus.Online
|
|
| 870 | + : InternetStatus.Offline;
|
|
| 871 | + } else {
|
|
| 872 | + newStatus = InternetStatus.Unknown;
|
|
| 873 | + }
|
|
| 874 | + if (newStatus === this._internetStatus) {
|
|
| 875 | + return;
|
|
| 876 | + }
|
|
| 877 | + this._internetStatus = newStatus;
|
|
| 878 | + Services.obs.notifyObservers(null, TorConnectTopics.InternetStatusChange);
|
|
| 879 | + },
|
|
| 880 | + |
|
| 1032 | 881 | // init should be called by TorStartupService
|
| 1033 | 882 | init() {
|
| 1034 | 883 | lazy.logger.debug("TorConnect.init()");
|
| ... | ... | @@ -1048,6 +897,9 @@ export const TorConnect = { |
| 1048 | 897 | observeTopic(lazy.TorProviderTopics.ProcessExited);
|
| 1049 | 898 | observeTopic(lazy.TorProviderTopics.HasWarnOrErr);
|
| 1050 | 899 | observeTopic(lazy.TorSettingsTopics.SettingsChanged);
|
| 900 | + observeTopic(NETWORK_LINK_TOPIC);
|
|
| 901 | + |
|
| 902 | + this._updateInternetStatus();
|
|
| 1051 | 903 | |
| 1052 | 904 | // NOTE: At this point, _requestedStage should still be `null`.
|
| 1053 | 905 | this._setStage(TorConnectStage.Start);
|
| ... | ... | @@ -1109,6 +961,9 @@ export const TorConnect = { |
| 1109 | 961 | this._makeStageRequest(TorConnectStage.Start);
|
| 1110 | 962 | }
|
| 1111 | 963 | break;
|
| 964 | + case NETWORK_LINK_TOPIC:
|
|
| 965 | + this._updateInternetStatus();
|
|
| 966 | + break;
|
|
| 1112 | 967 | }
|
| 1113 | 968 | },
|
| 1114 | 969 | |
| ... | ... | @@ -1330,9 +1185,6 @@ export const TorConnect = { |
| 1330 | 1185 | bootstrapOptions.simulateDelay =
|
| 1331 | 1186 | this.simulateBootstrapOptions.simulateDelay;
|
| 1332 | 1187 | }
|
| 1333 | - if (this.simulateBootstrapOptions.simulateOffline) {
|
|
| 1334 | - bootstrapOptions.simulateOffline = true;
|
|
| 1335 | - }
|
|
| 1336 | 1188 | if (this.simulateBootstrapOptions.simulateMoatResponse) {
|
| 1337 | 1189 | bootstrapOptions.simulateMoatResponse =
|
| 1338 | 1190 | this.simulateBootstrapOptions.simulateMoatResponse;
|
| ... | ... | @@ -1446,12 +1298,6 @@ export const TorConnect = { |
| 1446 | 1298 | ? new AutoBootstrapAttempt()
|
| 1447 | 1299 | : new BootstrapAttempt();
|
| 1448 | 1300 | |
| 1449 | - if (!regionCode) {
|
|
| 1450 | - // Only test internet for the first bootstrap attempt.
|
|
| 1451 | - // TODO: Remove this since we do not have user consent. tor-browser#42605.
|
|
| 1452 | - bootstrapOptions.testInternet = true;
|
|
| 1453 | - }
|
|
| 1454 | - |
|
| 1455 | 1301 | this._addSimulateOptions(bootstrapOptions, regionCode);
|
| 1456 | 1302 | |
| 1457 | 1303 | // NOTE: The only `await` in this method is for `bootstrapAttempt.run`.
|
| ... | ... | @@ -1523,22 +1369,27 @@ export const TorConnect = { |
| 1523 | 1369 | return;
|
| 1524 | 1370 | }
|
| 1525 | 1371 | |
| 1526 | - if (
|
|
| 1527 | - result === "offline" &&
|
|
| 1528 | - (beginStage === TorConnectStage.Start ||
|
|
| 1529 | - beginStage === TorConnectStage.Offline)
|
|
| 1530 | - ) {
|
|
| 1531 | - this._tryAgain = true;
|
|
| 1532 | - this._signalError(new TorConnectError(TorConnectError.Offline));
|
|
| 1533 | - |
|
| 1534 | - this._setStage(TorConnectStage.Offline);
|
|
| 1535 | - return;
|
|
| 1536 | - }
|
|
| 1537 | - |
|
| 1538 | 1372 | if (error) {
|
| 1539 | 1373 | lazy.logger.info("Bootstrap attempt error", error);
|
| 1540 | - |
|
| 1541 | 1374 | this._tryAgain = true;
|
| 1375 | + |
|
| 1376 | + if (
|
|
| 1377 | + (beginStage === TorConnectStage.Start ||
|
|
| 1378 | + beginStage === TorConnectStage.Offline) &&
|
|
| 1379 | + (this.internetStatus === InternetStatus.Offline || this.simulateOffline)
|
|
| 1380 | + ) {
|
|
| 1381 | + // If we are currently offline, we assume the bootstrap error is caused
|
|
| 1382 | + // by a general internet connection problem, so we show an "Offline"
|
|
| 1383 | + // stage instead.
|
|
| 1384 | + // NOTE: In principle, we may determine that we are offline prior to the
|
|
| 1385 | + // bootstrap being thrown, but we do not want to cancel a bootstrap
|
|
| 1386 | + // attempt prematurely in case the offline state is intermittent or
|
|
| 1387 | + // incorrect.
|
|
| 1388 | + this._signalError(new TorConnectError(TorConnectError.Offline));
|
|
| 1389 | + this._setStage(TorConnectStage.Offline);
|
|
| 1390 | + return;
|
|
| 1391 | + }
|
|
| 1392 | + |
|
| 1542 | 1393 | this._potentiallyBlocked = true;
|
| 1543 | 1394 | // Disable quickstart until we have a successful bootstrap.
|
| 1544 | 1395 | Services.prefs.setBoolPref(TorConnectPrefs.prompt_at_startup, true);
|