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);
|