Pier Angelo Vendrame pushed to branch tor-browser-128.6.0esr-14.5-1 at The Tor Project / Applications / Tor Browser

Commits:

4 changed files:

Changes:

  • toolkit/components/tor-launcher/TorBootstrapRequest.sys.mjs
    ... ... @@ -90,6 +90,11 @@ export class TorBootstrapRequest {
    90 90
           // Wait for bootstrapping to begin and maybe handle error.
    
    91 91
           // Notice that we do not resolve the promise here in case of success, but
    
    92 92
           // we do it from the BootstrapStatus observer.
    
    93
    +      // NOTE: After TorProviderBuilder.build resolves, TorProvider.init will
    
    94
    +      // have completed. In particular, assuming no errors, the TorSettings will
    
    95
    +      // have been initialised and passed on to the provider via
    
    96
    +      // TorProvider.writeSettings. Therefore we should be safe to immediately
    
    97
    +      // call `connect` using the latest user settings.
    
    93 98
           lazy.TorProviderBuilder.build()
    
    94 99
             .then(provider => provider.connect())
    
    95 100
             .catch(err => {
    

  • toolkit/components/tor-launcher/TorProviderBuilder.sys.mjs
    ... ... @@ -54,14 +54,15 @@ export class TorProviderBuilder {
    54 54
     
    
    55 55
       /**
    
    56 56
        * Initialize the provider of choice.
    
    57
    -   * Even though initialization is asynchronous, we do not expect the caller to
    
    58
    -   * await this method. The reason is that any call to build() will wait the
    
    59
    -   * initialization anyway (and re-throw any initialization error).
    
    60 57
        */
    
    61
    -  static async init() {
    
    58
    +  static init() {
    
    62 59
         switch (this.providerType) {
    
    63 60
           case TorProviders.tor:
    
    64
    -        await this.#initTorProvider();
    
    61
    +        // Even though initialization of the initial TorProvider is
    
    62
    +        // asynchronous, we do not expect the caller to await it. The reason is
    
    63
    +        // that any call to build() will wait the initialization anyway (and
    
    64
    +        // re-throw any initialization error).
    
    65
    +        this.#initTorProvider();
    
    65 66
             break;
    
    66 67
           case TorProviders.none:
    
    67 68
             lazy.TorLauncherUtil.setProxyConfiguration(
    
    ... ... @@ -74,7 +75,12 @@ export class TorProviderBuilder {
    74 75
         }
    
    75 76
       }
    
    76 77
     
    
    77
    -  static async #initTorProvider() {
    
    78
    +  /**
    
    79
    +   * Replace #provider with a new instance.
    
    80
    +   *
    
    81
    +   * @returns {Promise<TorProvider>} The new instance.
    
    82
    +   */
    
    83
    +  static #initTorProvider() {
    
    78 84
         if (!this.#exitObserver) {
    
    79 85
           this.#exitObserver = this.#torExited.bind(this);
    
    80 86
           Services.obs.addObserver(
    
    ... ... @@ -83,18 +89,39 @@ export class TorProviderBuilder {
    83 89
           );
    
    84 90
         }
    
    85 91
     
    
    92
    +    // NOTE: We need to ensure that the #provider is set as soon
    
    93
    +    // TorProviderBuilder.init is called.
    
    94
    +    // I.e. it should be safe to call
    
    95
    +    //   TorProviderBuilder.init();
    
    96
    +    //   TorProviderBuilder.build();
    
    97
    +    // without any await.
    
    98
    +    //
    
    99
    +    // Therefore, we await the oldProvider within the Promise rather than make
    
    100
    +    // #initTorProvider async.
    
    101
    +    //
    
    102
    +    // In particular, this is needed by TorConnect when the user has selected
    
    103
    +    // quickstart, in which case `TorConnect.init` will immediately request the
    
    104
    +    // provider. See tor-browser#41921.
    
    105
    +    this.#provider = this.#replaceTorProvider(this.#provider);
    
    106
    +    return this.#provider;
    
    107
    +  }
    
    108
    +
    
    109
    +  /**
    
    110
    +   * Replace a TorProvider instance. Resolves once the TorProvider is
    
    111
    +   * initialised.
    
    112
    +   *
    
    113
    +   * @param {Promise<TorProvider>?} oldProvider - The previous's provider's
    
    114
    +   *   promise, if any.
    
    115
    +   * @returns {TorProvider} The new TorProvider instance.
    
    116
    +   */
    
    117
    +  static async #replaceTorProvider(oldProvider) {
    
    86 118
         try {
    
    87
    -      const old = await this.#provider;
    
    88
    -      old?.uninit();
    
    119
    +      // Uninitialise the old TorProvider, if there is any.
    
    120
    +      (await oldProvider)?.uninit();
    
    89 121
         } catch {}
    
    90
    -    this.#provider = new Promise((resolve, reject) => {
    
    91
    -      const provider = new lazy.TorProvider();
    
    92
    -      provider
    
    93
    -        .init()
    
    94
    -        .then(() => resolve(provider))
    
    95
    -        .catch(reject);
    
    96
    -    });
    
    97
    -    await this.#provider;
    
    122
    +    const provider = new lazy.TorProvider();
    
    123
    +    await provider.init();
    
    124
    +    return provider;
    
    98 125
       }
    
    99 126
     
    
    100 127
       static uninit() {
    

  • toolkit/modules/TorAndroidIntegration.sys.mjs
    ... ... @@ -68,9 +68,12 @@ class TorAndroidIntegrationImpl {
    68 68
           Services.obs.addObserver(this, lazy.TorSettingsTopics[topic]);
    
    69 69
         }
    
    70 70
     
    
    71
    -    lazy.TorProviderBuilder.init().finally(() => {
    
    72
    -      lazy.TorProviderBuilder.firstWindowLoaded();
    
    73
    -    });
    
    71
    +    lazy.TorProviderBuilder.init();
    
    72
    +    // On Android immediately call firstWindowLoaded. This should be safe to
    
    73
    +    // call since it will await the initialisation of the TorProvider set up
    
    74
    +    // by TorProviderBuilder.init.
    
    75
    +    lazy.TorProviderBuilder.firstWindowLoaded();
    
    76
    +
    
    74 77
         try {
    
    75 78
           await lazy.TorSettings.init();
    
    76 79
           await lazy.TorConnect.init();
    

  • toolkit/modules/TorConnect.sys.mjs
    ... ... @@ -10,7 +10,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
    10 10
       BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.sys.mjs",
    
    11 11
       MoatRPC: "resource://gre/modules/Moat.sys.mjs",
    
    12 12
       TorBootstrapRequest: "resource://gre/modules/TorBootstrapRequest.sys.mjs",
    
    13
    -  TorProviderBuilder: "resource://gre/modules/TorProviderBuilder.sys.mjs",
    
    14 13
       TorProviderTopics: "resource://gre/modules/TorProviderBuilder.sys.mjs",
    
    15 14
       TorLauncherUtil: "resource://gre/modules/TorLauncherUtil.sys.mjs",
    
    16 15
       TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
    
    ... ... @@ -436,15 +435,23 @@ class AutoBootstrapAttempt {
    436 435
             return;
    
    437 436
           }
    
    438 437
           this.#resolved = true;
    
    439
    -      try {
    
    440
    -        // Run cleanup before we resolve the promise to ensure two instances
    
    441
    -        // of AutoBootstrapAttempt are not trying to change the settings at
    
    442
    -        // the same time.
    
    443
    -        if (arg.result !== "complete") {
    
    444
    -          await lazy.TorSettings.clearTemporaryBridges();
    
    438
    +
    
    439
    +      if (lazy.TorSettings.initialized) {
    
    440
    +        // If not initialized, then we won't have applied any settings.
    
    441
    +        try {
    
    442
    +          // Run cleanup before we resolve the promise to ensure two instances
    
    443
    +          // of AutoBootstrapAttempt are not trying to change the settings at
    
    444
    +          // the same time.
    
    445
    +          if (arg.result !== "complete") {
    
    446
    +            // Should do nothing if we never called applyTemporaryBridges.
    
    447
    +            await lazy.TorSettings.clearTemporaryBridges();
    
    448
    +          }
    
    449
    +        } catch (error) {
    
    450
    +          lazy.logger.error(
    
    451
    +            "Unexpected error in auto-bootstrap cleanup",
    
    452
    +            error
    
    453
    +          );
    
    445 454
             }
    
    446
    -      } catch (error) {
    
    447
    -        lazy.logger.error("Unexpected error in auto-bootstrap cleanup", error);
    
    448 455
           }
    
    449 456
           if (arg.error) {
    
    450 457
             reject(arg.error);
    
    ... ... @@ -483,6 +490,16 @@ class AutoBootstrapAttempt {
    483 490
        * @param {BootstrapOptions} options - Options to apply to the bootstrap.
    
    484 491
        */
    
    485 492
       async #runInternal(progressCallback, options) {
    
    493
    +    // Wait for TorSettings to be initialised, which is used for the
    
    494
    +    // AutoBootstrapping set up.
    
    495
    +    await Promise.race([
    
    496
    +      lazy.TorSettings.initializedPromise,
    
    497
    +      this.#cancelledPromise,
    
    498
    +    ]);
    
    499
    +    if (this.#cancelled || this.#resolved) {
    
    500
    +      return;
    
    501
    +    }
    
    502
    +
    
    486 503
         await this.#fetchBridges(options);
    
    487 504
         if (this.#cancelled || this.#resolved) {
    
    488 505
           return;
    
    ... ... @@ -1016,19 +1033,20 @@ export const TorConnect = {
    1016 1033
           lazy.logger.debug(`Observing topic '${addTopic}'`);
    
    1017 1034
         };
    
    1018 1035
     
    
    1019
    -    // Wait for TorSettings, as we will need it.
    
    1020
    -    // We will wait for a TorProvider only after TorSettings is ready,
    
    1021
    -    // because the TorProviderBuilder initialization might not have finished
    
    1022
    -    // at this point, and TorSettings initialization is a prerequisite for
    
    1023
    -    // having a provider.
    
    1024
    -    // So, we prefer initializing TorConnect as soon as possible, so that
    
    1025
    -    // the UI will be able to detect it is in the Initializing state and act
    
    1026
    -    // consequently.
    
    1027
    -    lazy.TorSettings.initializedPromise.then(() => this._settingsInitialized());
    
    1028
    -
    
    1029 1036
         // register the Tor topics we always care about
    
    1030 1037
         observeTopic(lazy.TorProviderTopics.ProcessExited);
    
    1031 1038
         observeTopic(lazy.TorProviderTopics.HasWarnOrErr);
    
    1039
    +
    
    1040
    +    // NOTE: At this point, _requestedStage should still be `null`.
    
    1041
    +    this._setStage(TorConnectStage.Start);
    
    1042
    +    if (
    
    1043
    +      // Quickstart setting is enabled.
    
    1044
    +      this.quickstart &&
    
    1045
    +      // And the previous bootstrap attempt must have succeeded.
    
    1046
    +      !Services.prefs.getBoolPref(TorConnectPrefs.prompt_at_startup, true)
    
    1047
    +    ) {
    
    1048
    +      this.beginBootstrapping();
    
    1049
    +    }
    
    1032 1050
       },
    
    1033 1051
     
    
    1034 1052
       async observe(subject, topic) {
    
    ... ... @@ -1058,26 +1076,6 @@ export const TorConnect = {
    1058 1076
         }
    
    1059 1077
       },
    
    1060 1078
     
    
    1061
    -  async _settingsInitialized() {
    
    1062
    -    // TODO: Handle failures here, instead of the prompt to restart the
    
    1063
    -    // daemon when it exits (tor-browser#21053, tor-browser#41921).
    
    1064
    -    await lazy.TorProviderBuilder.build();
    
    1065
    -
    
    1066
    -    lazy.logger.debug("The TorProvider is ready, changing state.");
    
    1067
    -    // NOTE: If the tor process exits before this point, then
    
    1068
    -    // shouldQuickStart would be `false`.
    
    1069
    -    // NOTE: At this point, _requestedStage should still be `null`.
    
    1070
    -    this._setStage(TorConnectStage.Start);
    
    1071
    -    if (
    
    1072
    -      // Quickstart setting is enabled.
    
    1073
    -      this.quickstart &&
    
    1074
    -      // And the previous bootstrap attempt must have succeeded.
    
    1075
    -      !Services.prefs.getBoolPref(TorConnectPrefs.prompt_at_startup, true)
    
    1076
    -    ) {
    
    1077
    -      this.beginBootstrapping();
    
    1078
    -    }
    
    1079
    -  },
    
    1080
    -
    
    1081 1079
       /**
    
    1082 1080
        * Set the user stage.
    
    1083 1081
        *