[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [Git][tpo/applications/tor-browser][tor-browser-128.6.0esr-14.5-1] 3 commits: fixup! TB 40597: Implement TorSettings module



Title: GitLab

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

Commits:

  • 0b42b720
    by Henry Wilkes at 2025-01-20T17:57:59+00:00
    fixup! TB 40597: Implement TorSettings module
    
    TB 41921: Return only the bridge settings from Moat.
    
    Rather than return { bridges: enabled: true, ... } from MoatRPC API, we
    just return the relevant parts. This should make it clearer that Moat
    can *only* change TorSettings.bridges, and nothing else.
    
  • 7129f408
    by Henry Wilkes at 2025-01-20T17:57:59+00:00
    fixup! TB 40597: Implement TorSettings module
    
    TB 41921: Have Moat bridges pass through TorSettings rather than using
    TorProvider directly.
    
    TorSettings should be the only caller to TorProvider.writeSettings, so
    we can establish more control over which bridges are in use at any given
    moment in one place.
    
    Also add some sanitation to the Moat response.
    
  • 6ea6bd74
    by Henry Wilkes at 2025-01-20T17:57:59+00:00
    fixup! TB 40933: Add tor-launcher functionality
    
    TB 41921: Use temporary bridges for TorProvider initialisation.
    
    It is unlikely that temporary bridges would be present when TorProvider
    is initialised, but it should be using whatever
    TorSettings.applySettings uses.
    

4 changed files:

Changes:

  • toolkit/components/tor-launcher/TorProvider.sys.mjs
    ... ... @@ -227,7 +227,7 @@ export class TorProvider {
    227 227
         if (this.ownsTorDaemon) {
    
    228 228
           try {
    
    229 229
             await lazy.TorSettings.initializedPromise;
    
    230
    -        await this.writeSettings(lazy.TorSettings.getSettings());
    
    230
    +        await this.writeSettings();
    
    231 231
           } catch (e) {
    
    232 232
             logger.warn(
    
    233 233
               "Failed to initialize TorSettings or to write our initial settings. Continuing the initialization anyway.",
    
    ... ... @@ -269,11 +269,13 @@ export class TorProvider {
    269 269
       /**
    
    270 270
        * Send settings to the tor daemon.
    
    271 271
        *
    
    272
    -   * @param {object} settings A settings object, as returned by
    
    273
    -   * TorSettings.getSettings(). This allow to try settings without passing
    
    274
    -   * through TorSettings.
    
    272
    +   * This should only be called internally or by the TorSettings module.
    
    275 273
        */
    
    276
    -  async writeSettings(settings) {
    
    274
    +  async writeSettings() {
    
    275
    +    // Fetch the current settings.
    
    276
    +    // We set the useTemporary parameter since we want to apply temporary
    
    277
    +    // bridges if they are available.
    
    278
    +    const settings = lazy.TorSettings.getSettings(true);
    
    277 279
         logger.debug("TorProvider.writeSettings", settings);
    
    278 280
         const torSettings = new Map();
    
    279 281
     
    

  • toolkit/modules/Moat.sys.mjs
    ... ... @@ -13,7 +13,6 @@ ChromeUtils.defineESModuleGetters(lazy, {
    13 13
       DomainFrontRequestBuilder:
    
    14 14
         "resource://gre/modules/DomainFrontedRequests.sys.mjs",
    
    15 15
       TorBridgeSource: "resource://gre/modules/TorSettings.sys.mjs",
    
    16
    -  TorSettings: "resource://gre/modules/TorSettings.sys.mjs",
    
    17 16
     });
    
    18 17
     
    
    19 18
     const TorLauncherPrefs = Object.freeze({
    
    ... ... @@ -73,6 +72,25 @@ class InternetTestResponseListener {
    73 72
       }
    
    74 73
     }
    
    75 74
     
    
    75
    +/**
    
    76
    + * @typedef {Object} MoatBridges
    
    77
    + *
    
    78
    + * Bridge settings that can be passed to TorSettings.bridges.
    
    79
    + *
    
    80
    + * @property {number} source - The `TorBridgeSource` type.
    
    81
    + * @property {string} [builtin_type] - The built-in bridge type.
    
    82
    + * @property {string[]} [bridge_strings] - The bridge lines.
    
    83
    + */
    
    84
    +
    
    85
    +/**
    
    86
    + * @typedef {Object} MoatSettings
    
    87
    + *
    
    88
    + * The settings returned by Moat.
    
    89
    + *
    
    90
    + * @property {MoatBridges[]} bridgesList - The list of bridges found.
    
    91
    + * @property {string} [country] - The detected country (region).
    
    92
    + */
    
    93
    +
    
    76 94
     /**
    
    77 95
      * Constructs JSON objects and sends requests over Moat.
    
    78 96
      * The documentation about the JSON schemas to use are available at
    
    ... ... @@ -213,37 +231,31 @@ export class MoatRPC {
    213 231
         return { bridges, qrcode: qrcodeImg };
    
    214 232
       }
    
    215 233
     
    
    216
    -  // Convert received settings object to format used by TorSettings module.
    
    217
    -  #fixupSettings(settings) {
    
    234
    +  /**
    
    235
    +   * Extract bridges from the received Moat settings object.
    
    236
    +   *
    
    237
    +   * @param {Object} settings - The received settings.
    
    238
    +   * @return {MoatBridge} The extracted bridges.
    
    239
    +   */
    
    240
    +  #extractBridges(settings) {
    
    218 241
         if (!("bridges" in settings)) {
    
    219 242
           throw new Error("Expected to find `bridges` in the settings object.");
    
    220 243
         }
    
    221
    -    const retval = {
    
    222
    -      bridges: {
    
    223
    -        enabled: true,
    
    224
    -      },
    
    225
    -    };
    
    244
    +    const bridges = {};
    
    226 245
         switch (settings.bridges.source) {
    
    227 246
           case "builtin":
    
    228
    -        retval.bridges.source = lazy.TorBridgeSource.BuiltIn;
    
    229
    -        retval.bridges.builtin_type = settings.bridges.type;
    
    230
    -        // TorSettings will ignore strings for built-in bridges, and use the
    
    231
    -        // ones it already knows, instead. However, when we try these settings
    
    232
    -        // in the connect assist, we skip TorSettings. Therefore, we set the
    
    233
    -        // lines also here (the ones we already know, not the ones we receive
    
    234
    -        // from Moat). This needs TorSettings to be initialized, which by now
    
    235
    -        // should have already happened (this method is used only by TorConnect,
    
    236
    -        // that needs TorSettings to be initialized).
    
    237
    -        // In any case, getBuiltinBridges will throw if the data is not ready,
    
    238
    -        // yet.
    
    239
    -        retval.bridges.bridge_strings = lazy.TorSettings.getBuiltinBridges(
    
    240
    -          settings.bridges.type
    
    241
    -        );
    
    247
    +        bridges.source = lazy.TorBridgeSource.BuiltIn;
    
    248
    +        bridges.builtin_type = String(settings.bridges.type);
    
    249
    +        // Ignore the bridge_strings argument since we will use our built-in
    
    250
    +        // bridge strings instead.
    
    242 251
             break;
    
    243 252
           case "bridgedb":
    
    244
    -        retval.bridges.source = lazy.TorBridgeSource.BridgeDB;
    
    245
    -        if (settings.bridges.bridge_strings) {
    
    246
    -          retval.bridges.bridge_strings = settings.bridges.bridge_strings;
    
    253
    +        bridges.source = lazy.TorBridgeSource.BridgeDB;
    
    254
    +        if (settings.bridges.bridge_strings?.length) {
    
    255
    +          bridges.bridge_strings = Array.from(
    
    256
    +            settings.bridges.bridge_strings,
    
    257
    +            item => String(item)
    
    258
    +          );
    
    247 259
             } else {
    
    248 260
               throw new Error(
    
    249 261
                 "Received no bridge-strings for BridgeDB bridge source"
    
    ... ... @@ -255,37 +267,38 @@ export class MoatRPC {
    255 267
               `Unexpected bridge source '${settings.bridges.source}'`
    
    256 268
             );
    
    257 269
         }
    
    258
    -    return retval;
    
    270
    +    return bridges;
    
    259 271
       }
    
    260 272
     
    
    261
    -  // Converts a list of settings objects received from BridgeDB to a list of
    
    262
    -  // settings objects understood by the TorSettings module.
    
    263
    -  // In the event of error, returns an empty list.
    
    264
    -  #fixupSettingsList(settingsList) {
    
    265
    -    const retval = [];
    
    273
    +  /**
    
    274
    +   * Extract a list of bridges from the received Moat settings object.
    
    275
    +   *
    
    276
    +   * @param {Object} settings - The received settings.
    
    277
    +   * @return {MoatBridge[]} The list of extracted bridges.
    
    278
    +   */
    
    279
    +  #extractBridgesList(settingsList) {
    
    280
    +    const bridgesList = [];
    
    266 281
         for (const settings of settingsList) {
    
    267 282
           try {
    
    268
    -        retval.push(this.#fixupSettings(settings));
    
    283
    +        bridgesList.push(this.#extractBridges(settings));
    
    269 284
           } catch (ex) {
    
    270 285
             log.error(ex);
    
    271 286
           }
    
    272 287
         }
    
    273
    -    return retval;
    
    288
    +    return bridgesList;
    
    274 289
       }
    
    275 290
     
    
    276
    -  // Request tor settings for the user optionally based on their location
    
    277
    -  // (derived from their IP). Takes the following parameters:
    
    278
    -  // - transports: optional, an array of transports available to the client; if
    
    279
    -  //   empty (or not given) returns settings using all working transports known
    
    280
    -  //   to the server
    
    281
    -  // - country: optional, an ISO 3166-1 alpha-2 country code to request settings
    
    282
    -  //   for; if not provided the country is determined by the user's IP address
    
    283
    -  //
    
    284
    -  // Returns an object with the detected country code and an array of settings
    
    285
    -  // in a format that can be passed to the TorSettings module. This array might
    
    286
    -  // be empty if the country has no associated settings.
    
    287
    -  // If the server cannot determine the user's country (and no country code is
    
    288
    -  // provided), then null is returned instead of the object.
    
    291
    +  /**
    
    292
    +   * Request tor settings for the user optionally based on their location
    
    293
    +   * (derived from their IP). Takes the following parameters:
    
    294
    +   *
    
    295
    +   * @param {string[]} transports - A list of transports we support.
    
    296
    +   * @param {?string} country - The region to request bridges for, as an
    
    297
    +   *   ISO 3166-1 alpha-2 region code, or `null` to have the server
    
    298
    +   *   automatically determine the region.
    
    299
    +   * @returns {?MoatSettings} - The returned settings from the server, or `null`
    
    300
    +   *   if the region could not be determined by the server.
    
    301
    +   */
    
    289 302
       async circumvention_settings(transports, country) {
    
    290 303
         const args = {
    
    291 304
           transports: transports ? transports : [],
    
    ... ... @@ -306,7 +319,7 @@ export class MoatRPC {
    306 319
     
    
    307 320
           throw new Error(`MoatRPC: ${detail} (${code})`);
    
    308 321
         } else if ("settings" in response) {
    
    309
    -      settings.settings = this.#fixupSettingsList(response.settings);
    
    322
    +      settings.bridgesList = this.#extractBridgesList(response.settings);
    
    310 323
         }
    
    311 324
         if ("country" in response) {
    
    312 325
           settings.country = response.country;
    
    ... ... @@ -349,14 +362,12 @@ export class MoatRPC {
    349 362
         return map;
    
    350 363
       }
    
    351 364
     
    
    352
    -  // Request a copy of the defaul/fallback bridge settings, takes the following
    
    353
    -  // parameters:
    
    354
    -  // - transports: optional, an array of transports available to the client; if
    
    355
    -  //   empty (or not given) returns settings using all working transports known
    
    356
    -  //   to the server
    
    357
    -  //
    
    358
    -  // returns an array of settings objects in roughly the same format as the
    
    359
    -  // _settings object on the TorSettings module
    
    365
    +  /**
    
    366
    +   * Request a copy of the default/fallback bridge settings.
    
    367
    +   *
    
    368
    +   * @param {string[]} transports - A list of transports we support.
    
    369
    +   * @returns {MoatBridges[]} - The list of bridges found.
    
    370
    +   */
    
    360 371
       async circumvention_defaults(transports) {
    
    361 372
         const args = {
    
    362 373
           transports: transports ? transports : [],
    
    ... ... @@ -367,7 +378,7 @@ export class MoatRPC {
    367 378
           const detail = response.errors[0].detail;
    
    368 379
           throw new Error(`MoatRPC: ${detail} (${code})`);
    
    369 380
         } else if ("settings" in response) {
    
    370
    -      return this.#fixupSettingsList(response.settings);
    
    381
    +      return this.#extractBridgesList(response.settings);
    
    371 382
         }
    
    372 383
         return [];
    
    373 384
       }
    

  • toolkit/modules/TorConnect.sys.mjs
    ... ... @@ -103,11 +103,12 @@ export const TorConnectTopics = Object.freeze({
    103 103
      *   failing bootstrap.
    
    104 104
      * @property {integer} [options.simulateDelay] - The delay in microseconds to
    
    105 105
      *   apply to simulated bootstraps.
    
    106
    - * @property {object} [options.simulateMoatResponse] - Simulate a Moat response
    
    107
    - *   for circumvention settings. Should include a "settings" property, and
    
    108
    - *   optionally a "country" property. You may add a "simulateCensorship"
    
    109
    - *   property to some of the settings to make only their bootstrap attempts
    
    110
    - *   fail.
    
    106
    + * @property {MoatSettings} [options.simulateMoatResponse] - Simulate a Moat
    
    107
    + *   response for circumvention settings. Should include a "bridgesList"
    
    108
    + *   property, and optionally a "country" property. The "bridgesList" property
    
    109
    + *   should be an Array of MoatBridges objects that match the bridge settings
    
    110
    + *   accepted by TorSettings.bridges, plus you may add a "simulateCensorship"
    
    111
    + *   property to make only their bootstrap attempts fail.
    
    111 112
      * @property {boolean} [options.testInternet] - Whether to also test the
    
    112 113
      *   internet connection.
    
    113 114
      * @property {boolean} [options.simulateOffline] - Whether to simulate an
    
    ... ... @@ -214,6 +215,14 @@ class BootstrapAttempt {
    214 215
         return promise;
    
    215 216
       }
    
    216 217
     
    
    218
    +  /**
    
    219
    +   * Method to call just after the Bootstrapped stage is set in response to this
    
    220
    +   * bootstrap attempt.
    
    221
    +   */
    
    222
    +  postBootstrapped() {
    
    223
    +    // Nothing to do.
    
    224
    +  }
    
    225
    +
    
    217 226
       /**
    
    218 227
        * Run the attempt.
    
    219 228
        *
    
    ... ... @@ -395,17 +404,11 @@ class AutoBootstrapAttempt {
    395 404
        */
    
    396 405
       #cancelledPromise = null;
    
    397 406
       /**
    
    398
    -   * The found settings from Moat.
    
    399
    -   *
    
    400
    -   * @type {?object[]}
    
    401
    -   */
    
    402
    -  #settings = null;
    
    403
    -  /**
    
    404
    -   * The last settings that have been applied to the TorProvider, if any.
    
    407
    +   * The list of bridge configurations from Moat.
    
    405 408
        *
    
    406
    -   * @type {?object}
    
    409
    +   * @type {?MoatBridges[]}
    
    407 410
        */
    
    408
    -  #changedSetting = null;
    
    411
    +  #bridgesList = null;
    
    409 412
       /**
    
    410 413
        * The detected region code returned by Moat, if any.
    
    411 414
        *
    
    ... ... @@ -438,13 +441,8 @@ class AutoBootstrapAttempt {
    438 441
             // Run cleanup before we resolve the promise to ensure two instances
    
    439 442
             // of AutoBootstrapAttempt are not trying to change the settings at
    
    440 443
             // the same time.
    
    441
    -        if (this.#changedSetting) {
    
    442
    -          if (arg.result === "complete") {
    
    443
    -            // Persist the current settings to preferences.
    
    444
    -            lazy.TorSettings.setSettings(this.#changedSetting);
    
    445
    -            lazy.TorSettings.saveToPrefs();
    
    446
    -          } // else, applySettings will restore the current settings.
    
    447
    -          await lazy.TorSettings.applySettings();
    
    444
    +        if (arg.result !== "complete") {
    
    445
    +          await lazy.TorSettings.clearTemporaryBridges();
    
    448 446
             }
    
    449 447
           } catch (error) {
    
    450 448
             lazy.logger.error("Unexpected error in auto-bootstrap cleanup", error);
    
    ... ... @@ -466,6 +464,15 @@ class AutoBootstrapAttempt {
    466 464
         return promise;
    
    467 465
       }
    
    468 466
     
    
    467
    +  /**
    
    468
    +   * Method to call just after the Bootstrapped stage is set in response to this
    
    469
    +   * bootstrap attempt.
    
    470
    +   */
    
    471
    +  postBootstrapped() {
    
    472
    +    // Persist the current settings to preferences.
    
    473
    +    lazy.TorSettings.saveTemporaryBridges();
    
    474
    +  }
    
    475
    +
    
    469 476
       /**
    
    470 477
        * Run the attempt.
    
    471 478
        *
    
    ... ... @@ -477,12 +484,12 @@ class AutoBootstrapAttempt {
    477 484
        * @param {BootstrapOptions} options - Options to apply to the bootstrap.
    
    478 485
        */
    
    479 486
       async #runInternal(progressCallback, options) {
    
    480
    -    await this.#fetchSettings(options);
    
    487
    +    await this.#fetchBridges(options);
    
    481 488
         if (this.#cancelled || this.#resolved) {
    
    482 489
           return;
    
    483 490
         }
    
    484 491
     
    
    485
    -    if (!this.#settings?.length) {
    
    492
    +    if (!this.#bridgesList?.length) {
    
    486 493
           this.#resolveRun({
    
    487 494
             error: new TorConnectError(
    
    488 495
               options.regionCode === "automatic" && !this.detectedRegion
    
    ... ... @@ -493,14 +500,14 @@ class AutoBootstrapAttempt {
    493 500
         }
    
    494 501
     
    
    495 502
         // Apply each of our settings and try to bootstrap with each.
    
    496
    -    for (const [index, currentSetting] of this.#settings.entries()) {
    
    503
    +    for (const [index, bridges] of this.#bridgesList.entries()) {
    
    497 504
           lazy.logger.info(
    
    498 505
             `Attempting Bootstrap with configuration ${index + 1}/${
    
    499
    -          this.#settings.length
    
    506
    +          this.#bridgesList.length
    
    500 507
             }`
    
    501 508
           );
    
    502 509
     
    
    503
    -      await this.#trySetting(currentSetting, progressCallback, options);
    
    510
    +      await this.#tryBridges(bridges, progressCallback, options);
    
    504 511
     
    
    505 512
           if (this.#cancelled || this.#resolved) {
    
    506 513
             return;
    
    ... ... @@ -518,7 +525,7 @@ class AutoBootstrapAttempt {
    518 525
        *
    
    519 526
        * @param {BootstrapOptions} options - Options to apply to the bootstrap.
    
    520 527
        */
    
    521
    -  async #fetchSettings(options) {
    
    528
    +  async #fetchBridges(options) {
    
    522 529
         if (options.simulateMoatResponse) {
    
    523 530
           await Promise.race([
    
    524 531
             new Promise(res => setTimeout(res, options.simulateDelay || 0)),
    
    ... ... @@ -530,7 +537,7 @@ class AutoBootstrapAttempt {
    530 537
           }
    
    531 538
     
    
    532 539
           this.detectedRegion = options.simulateMoatResponse.country || null;
    
    533
    -      this.#settings = options.simulateMoatResponse.settings ?? null;
    
    540
    +      this.#bridgesList = options.simulateMoatResponse.bridgesList ?? null;
    
    534 541
     
    
    535 542
           return;
    
    536 543
         }
    
    ... ... @@ -564,16 +571,16 @@ class AutoBootstrapAttempt {
    564 571
     
    
    565 572
           this.detectedRegion = maybeSettings?.country || null;
    
    566 573
     
    
    567
    -      if (maybeSettings?.settings?.length) {
    
    568
    -        this.#settings = maybeSettings.settings;
    
    574
    +      if (maybeSettings?.bridgesList?.length) {
    
    575
    +        this.#bridgesList = maybeSettings.bridgesList;
    
    569 576
           } else {
    
    570 577
             // Keep consistency with the other call.
    
    571
    -        this.#settings = await Promise.race([
    
    578
    +        this.#bridgesList = await Promise.race([
    
    572 579
               moat.circumvention_defaults([
    
    573 580
                 ...lazy.TorSettings.builtinBridgeTypes,
    
    574 581
                 "vanilla",
    
    575 582
               ]),
    
    576
    -          // This might set this.#settings to undefined.
    
    583
    +          // This might set this.#bridgesList to undefined.
    
    577 584
               this.#cancelledPromise,
    
    578 585
             ]);
    
    579 586
           }
    
    ... ... @@ -586,21 +593,21 @@ class AutoBootstrapAttempt {
    586 593
       /**
    
    587 594
        * Try to apply the settings we fetched.
    
    588 595
        *
    
    589
    -   * @param {object} setting - The setting to try.
    
    596
    +   * @param {MoatBridges} bridges - The bridges to try.
    
    590 597
        * @param {ProgressCallback} progressCallback - The callback to invoke with
    
    591 598
        *   the bootstrap progress.
    
    592 599
        * @param {BootstrapOptions} options - Options to apply to the bootstrap.
    
    593 600
        */
    
    594
    -  async #trySetting(setting, progressCallback, options) {
    
    601
    +  async #tryBridges(bridges, progressCallback, options) {
    
    595 602
         if (this.#cancelled || this.#resolved) {
    
    596 603
           return;
    
    597 604
         }
    
    598 605
     
    
    599
    -    if (options.simulateMoatResponse && setting.simulateCensorship) {
    
    606
    +    if (options.simulateMoatResponse && bridges.simulateCensorship) {
    
    600 607
           // Move the simulateCensorship option to the options for the next
    
    601 608
           // BootstrapAttempt.
    
    602
    -      setting = structuredClone(setting);
    
    603
    -      delete setting.simulateCensorship;
    
    609
    +      bridges = structuredClone(bridges);
    
    610
    +      delete bridges.simulateCensorship;
    
    604 611
           options = { ...options, simulateCensorship: true };
    
    605 612
         }
    
    606 613
     
    
    ... ... @@ -616,14 +623,7 @@ class AutoBootstrapAttempt {
    616 623
         // Another idea (maybe easier to implement) is to disable the settings
    
    617 624
         // UI while *any* bootstrap is going on.
    
    618 625
         // This is also documented in tor-browser#41921.
    
    619
    -    const provider = await lazy.TorProviderBuilder.build();
    
    620
    -    this.#changedSetting = setting;
    
    621
    -    // We need to merge with old settings, in case the user is using a proxy
    
    622
    -    // or is behind a firewall.
    
    623
    -    await provider.writeSettings({
    
    624
    -      ...lazy.TorSettings.getSettings(),
    
    625
    -      ...setting,
    
    626
    -    });
    
    626
    +    await lazy.TorSettings.applyTemporaryBridges(bridges);
    
    627 627
     
    
    628 628
         if (this.#cancelled || this.#resolved) {
    
    629 629
           return;
    
    ... ... @@ -642,7 +642,7 @@ class AutoBootstrapAttempt {
    642 642
             error instanceof TorConnectError &&
    
    643 643
             error.code === TorConnectError.BootstrapError
    
    644 644
           ) {
    
    645
    -        lazy.logger.info("TorConnect setting failed", setting, error);
    
    645
    +        lazy.logger.info("TorConnect setting failed", bridges, error);
    
    646 646
             // Try with the next settings.
    
    647 647
             // NOTE: We do not restore the user settings in between these runs.
    
    648 648
             // Instead we wait for #resolveRun callback to do so.
    
    ... ... @@ -1459,6 +1459,12 @@ export const TorConnect = {
    1459 1459
           }
    
    1460 1460
           this._setStage(TorConnectStage.Bootstrapped);
    
    1461 1461
           Services.obs.notifyObservers(null, TorConnectTopics.BootstrapComplete);
    
    1462
    +
    
    1463
    +      // Now call the postBootstrapped method. We do this after changing the
    
    1464
    +      // stage to ensure that AutoBootstrapAttempt.postBootstrapped call to
    
    1465
    +      // saveTemporaryBridges does not trigger SettingsChanged too early and
    
    1466
    +      // cancel itself.
    
    1467
    +      bootstrapAttempt.postBootstrapped();
    
    1462 1468
           return;
    
    1463 1469
         }
    
    1464 1470
     
    

  • toolkit/modules/TorSettings.sys.mjs
    ... ... @@ -198,6 +198,14 @@ class TorSettingsImpl {
    198 198
           allowed_ports: [],
    
    199 199
         },
    
    200 200
       };
    
    201
    +
    
    202
    +  /**
    
    203
    +   * Temporary bridge settings to apply instead of #settings.bridges.
    
    204
    +   *
    
    205
    +   * @type {?Object}
    
    206
    +   */
    
    207
    +  #temporaryBridgeSettings = null;
    
    208
    +
    
    201 209
       /**
    
    202 210
        * Accumulated errors from trying to set settings.
    
    203 211
        *
    
    ... ... @@ -713,6 +721,8 @@ class TorSettingsImpl {
    713 721
           try {
    
    714 722
             this.#allowUninitialized = true;
    
    715 723
             this.#loadFromPrefs();
    
    724
    +        // We do not pass on the loaded settings to the TorProvider yet. Instead
    
    725
    +        // TorProvider will ask for these once it has initialised.
    
    716 726
           } finally {
    
    717 727
             this.#allowUninitialized = false;
    
    718 728
             this.#notificationQueue.clear();
    
    ... ... @@ -971,7 +981,7 @@ class TorSettingsImpl {
    971 981
       async applySettings() {
    
    972 982
         this.#checkIfInitialized();
    
    973 983
         const provider = await lazy.TorProviderBuilder.build();
    
    974
    -    await provider.writeSettings(this.getSettings());
    
    984
    +    await provider.writeSettings();
    
    975 985
       }
    
    976 986
     
    
    977 987
       /**
    
    ... ... @@ -1073,12 +1083,20 @@ class TorSettingsImpl {
    1073 1083
       /**
    
    1074 1084
        * Get a copy of all our settings.
    
    1075 1085
        *
    
    1086
    +   * @param {boolean} [useTemporary=false] - Whether the returned settings
    
    1087
    +   *   should use the temporary bridge settings, if any, instead.
    
    1088
    +   *
    
    1076 1089
        * @returns {object} A copy of the settings object
    
    1077 1090
        */
    
    1078
    -  getSettings() {
    
    1091
    +  getSettings(useTemporary = false) {
    
    1079 1092
         lazy.logger.debug("getSettings()");
    
    1080 1093
         this.#checkIfInitialized();
    
    1081
    -    return structuredClone(this.#settings);
    
    1094
    +    const settings = structuredClone(this.#settings);
    
    1095
    +    if (useTemporary && this.#temporaryBridgeSettings) {
    
    1096
    +      // Override the bridge settings with our temporary ones.
    
    1097
    +      settings.bridges = structuredClone(this.#temporaryBridgeSettings);
    
    1098
    +    }
    
    1099
    +    return settings;
    
    1082 1100
       }
    
    1083 1101
     
    
    1084 1102
       /**
    
    ... ... @@ -1097,6 +1115,83 @@ class TorSettingsImpl {
    1097 1115
         }
    
    1098 1116
         return types;
    
    1099 1117
       }
    
    1118
    +
    
    1119
    +  /**
    
    1120
    +   * Apply some Moat bridges temporarily.
    
    1121
    +   *
    
    1122
    +   * These bridges will not yet be saved to settings.
    
    1123
    +   *
    
    1124
    +   * @param {MoatBridges} bridges - The bridges to apply.
    
    1125
    +   */
    
    1126
    +  async applyTemporaryBridges(bridges) {
    
    1127
    +    this.#checkIfInitialized();
    
    1128
    +
    
    1129
    +    if (
    
    1130
    +      bridges.source !== TorBridgeSource.BuiltIn &&
    
    1131
    +      bridges.source !== TorBridgeSource.BridgeDB
    
    1132
    +    ) {
    
    1133
    +      throw new Error(`Invalid bridge source ${bridges.source}`);
    
    1134
    +    }
    
    1135
    +
    
    1136
    +    const bridgeSettings = {
    
    1137
    +      enabled: true,
    
    1138
    +      source: bridges.source,
    
    1139
    +    };
    
    1140
    +
    
    1141
    +    if (bridges.source === TorBridgeSource.BuiltIn) {
    
    1142
    +      if (!bridges.builtin_type) {
    
    1143
    +        throw Error("Missing a built-in type");
    
    1144
    +      }
    
    1145
    +      bridgeSettings.builtin_type = String(bridges.builtin_type);
    
    1146
    +      const bridgeStrings = this.getBuiltinBridges(bridgeSettings.builtin_type);
    
    1147
    +      if (!bridgeStrings.length) {
    
    1148
    +        throw new Error(`No builtin bridges for type ${bridges.builtin_type}`);
    
    1149
    +      }
    
    1150
    +      bridgeSettings.bridge_strings = bridgeStrings;
    
    1151
    +    } else {
    
    1152
    +      // BridgeDB.
    
    1153
    +      if (!bridges.bridge_strings?.length) {
    
    1154
    +        throw new Error("Missing bridges strings");
    
    1155
    +      }
    
    1156
    +      // TODO: Can we safely verify the format of the bridge addresses sent from
    
    1157
    +      // Moat?
    
    1158
    +      bridgeSettings.bridge_strings = Array.from(bridges.bridge_strings, item =>
    
    1159
    +        String(item)
    
    1160
    +      );
    
    1161
    +    }
    
    1162
    +
    
    1163
    +    // After checks are complete, we commit them.
    
    1164
    +    this.#temporaryBridgeSettings = bridgeSettings;
    
    1165
    +    await this.applySettings();
    
    1166
    +  }
    
    1167
    +
    
    1168
    +  /**
    
    1169
    +   * Save to current temporary bridges to be permanent instead.
    
    1170
    +   */
    
    1171
    +  async saveTemporaryBridges() {
    
    1172
    +    this.#checkIfInitialized();
    
    1173
    +    if (!this.#temporaryBridgeSettings) {
    
    1174
    +      lazy.logger.warn("No temporary bridges to save");
    
    1175
    +      return;
    
    1176
    +    }
    
    1177
    +    this.setSettings({ bridges: this.#temporaryBridgeSettings });
    
    1178
    +    this.#temporaryBridgeSettings = null;
    
    1179
    +    this.saveToPrefs();
    
    1180
    +    await this.applySettings();
    
    1181
    +  }
    
    1182
    +
    
    1183
    +  /**
    
    1184
    +   * Clear the current temporary bridges.
    
    1185
    +   */
    
    1186
    +  async clearTemporaryBridges() {
    
    1187
    +    this.#checkIfInitialized();
    
    1188
    +    if (!this.#temporaryBridgeSettings) {
    
    1189
    +      lazy.logger.debug("No temporary bridges to clear");
    
    1190
    +      return;
    
    1191
    +    }
    
    1192
    +    this.#temporaryBridgeSettings = null;
    
    1193
    +    await this.applySettings();
    
    1194
    +  }
    
    1100 1195
     }
    
    1101 1196
     
    
    1102 1197
     export const TorSettings = new TorSettingsImpl();

  • _______________________________________________
    tor-commits mailing list -- tor-commits@xxxxxxxxxxxxxxxxxxxx
    To unsubscribe send an email to tor-commits-leave@xxxxxxxxxxxxxxxxxxxx