morgan pushed to branch base-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser

Commits:

4 changed files:

Changes:

  • browser/components/BrowserComponents.manifest
    ... ... @@ -51,7 +51,7 @@ category browser-first-window-ready resource://gre/modules/SandboxUtils.sys.mjs
    51 51
     #endif
    
    52 52
     #endif
    
    53 53
     category browser-first-window-ready moz-src:///browser/modules/ClipboardPrivacy.sys.mjs ClipboardPrivacy.init
    
    54
    -category browser-first-window-ready moz-src:///browser/modules/SecurityLevelRestartNotification.sys.mjs SecurityLevelRestartNotification.ready
    
    54
    +category browser-first-window-ready moz-src:///browser/modules/SecurityLevelNotification.sys.mjs SecurityLevelNotification.ready
    
    55 55
     
    
    56 56
     category browser-idle-startup resource:///modules/PlacesUIUtils.sys.mjs PlacesUIUtils.unblockToolbars
    
    57 57
     category browser-idle-startup resource:///modules/BuiltInThemes.sys.mjs BuiltInThemes.ensureBuiltInThemes
    

  • browser/modules/SecurityLevelRestartNotification.sys.mjs โ†’ browser/modules/SecurityLevelNotification.sys.mjs
    ... ... @@ -15,7 +15,7 @@ ChromeUtils.defineLazyGetter(lazy, "NotificationStrings", function () {
    15 15
     /**
    
    16 16
      * Interface for showing the security level restart notification on desktop.
    
    17 17
      */
    
    18
    -export const SecurityLevelRestartNotification = {
    
    18
    +export const SecurityLevelNotification = {
    
    19 19
       /**
    
    20 20
        * Whether we have already been initialised.
    
    21 21
        *
    
    ... ... @@ -31,11 +31,13 @@ export const SecurityLevelRestartNotification = {
    31 31
           return;
    
    32 32
         }
    
    33 33
         this._initialized = true;
    
    34
    -    lazy.SecurityLevelPrefs.setRestartNotificationHandler(this);
    
    34
    +    lazy.SecurityLevelPrefs.setNotificationHandler(this);
    
    35 35
       },
    
    36 36
     
    
    37 37
       /**
    
    38 38
        * Show the restart notification, and perform the restart if the user agrees.
    
    39
    +   *
    
    40
    +   * @returns {boolean} - Whether we are restarting the browser.
    
    39 41
        */
    
    40 42
       async tryRestartBrowser() {
    
    41 43
         const [titleText, bodyText, primaryButtonText, secondaryButtonText] =
    
    ... ... @@ -69,6 +71,49 @@ export const SecurityLevelRestartNotification = {
    69 71
           Services.startup.quit(
    
    70 72
             Services.startup.eAttemptQuit | Services.startup.eRestart
    
    71 73
           );
    
    74
    +      return true;
    
    75
    +    }
    
    76
    +    return false;
    
    77
    +  },
    
    78
    +
    
    79
    +  /**
    
    80
    +   * Show or re-show the custom security notification.
    
    81
    +   *
    
    82
    +   * @param {Function} userDismissedCallback - The callback for when the user
    
    83
    +   *   dismisses the notification.
    
    84
    +   */
    
    85
    +  async showCustomWarning(userDismissedCallback) {
    
    86
    +    const win = lazy.BrowserWindowTracker.getTopWindow();
    
    87
    +    if (!win) {
    
    88
    +      return;
    
    89
    +    }
    
    90
    +    const typeName = "security-level-custom";
    
    91
    +    const existing = win.gNotificationBox.getNotificationWithValue(typeName);
    
    92
    +    if (existing) {
    
    93
    +      win.gNotificationBox.removeNotification(existing);
    
    72 94
         }
    
    95
    +
    
    96
    +    const buttons = [
    
    97
    +      {
    
    98
    +        "l10n-id": "security-level-panel-open-settings-button",
    
    99
    +        callback() {
    
    100
    +          win.openPreferences("privacy-securitylevel");
    
    101
    +        },
    
    102
    +      },
    
    103
    +    ];
    
    104
    +
    
    105
    +    win.gNotificationBox.appendNotification(
    
    106
    +      typeName,
    
    107
    +      {
    
    108
    +        label: { "l10n-id": "security-level-summary-custom" },
    
    109
    +        priority: win.gNotificationBox.PRIORITY_WARNING_HIGH,
    
    110
    +        eventCallback: event => {
    
    111
    +          if (event === "dismissed") {
    
    112
    +            userDismissedCallback();
    
    113
    +          }
    
    114
    +        },
    
    115
    +      },
    
    116
    +      buttons
    
    117
    +    );
    
    73 118
       },
    
    74 119
     };

  • browser/modules/moz.build
    ... ... @@ -149,7 +149,7 @@ EXTRA_JS_MODULES += [
    149 149
     MOZ_SRC_FILES += [
    
    150 150
         "ContextId.sys.mjs",
    
    151 151
         "ClipboardPrivacy.sys.mjs",
    
    152
    -    "SecurityLevelRestartNotification.sys.mjs",
    
    152
    +    "SecurityLevelNotification.sys.mjs",
    
    153 153
     ]
    
    154 154
     
    
    155 155
     if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
    

  • toolkit/components/securitylevel/SecurityLevel.sys.mjs
    ... ... @@ -226,7 +226,7 @@ var initializeNoScriptControl = () => {
    226 226
           } catch (e) {
    
    227 227
             logger.error("Could not apply NoScript settings", e);
    
    228 228
             // Treat as a custom security level for the rest of the session.
    
    229
    -        Services.prefs.setBoolPref(kCustomPref, true);
    
    229
    +        SecurityLevelPrefs.setCustomAndWarn();
    
    230 230
           }
    
    231 231
         };
    
    232 232
         waitForExtensionMessage(noscriptID, a => a.__meta.name === "started").then(
    
    ... ... @@ -236,7 +236,7 @@ var initializeNoScriptControl = () => {
    236 236
       } catch (e) {
    
    237 237
         logger.exception(e);
    
    238 238
         // Treat as a custom security level for the rest of the session.
    
    239
    -    Services.prefs.setBoolPref(kCustomPref, true);
    
    239
    +    SecurityLevelPrefs.setCustomAndWarn();
    
    240 240
       }
    
    241 241
     };
    
    242 242
     
    
    ... ... @@ -389,7 +389,12 @@ var initializeSecurityPrefs = function () {
    389 389
         // particular, for the NoScript addon.
    
    390 390
         Services.prefs.setBoolPref(kCustomPref, false);
    
    391 391
         Services.prefs.setIntPref(kSliderPref, effectiveIndex);
    
    392
    -  } else if (!wasCustom && effectiveIndex !== desiredIndex) {
    
    392
    +  }
    
    393
    +  // Warn the user if they have booted the browser in a custom state, and have
    
    394
    +  // not yet acknowledged it in a previous session.
    
    395
    +  SecurityLevelPrefs.maybeWarnCustom();
    
    396
    +
    
    397
    +  if (!wasCustom && effectiveIndex !== desiredIndex) {
    
    393 398
         // NOTE: We assume all our controlled preferences require a restart.
    
    394 399
         // In practice, only a subset of these preferences may actually require a
    
    395 400
         // restart, so we could switch their values. But we treat them all the same
    
    ... ... @@ -436,7 +441,7 @@ var initializeSecurityPrefs = function () {
    436 441
             // properly applied. See tor-browser#43783.
    
    437 442
             // In the case where it does match a pre-set security level, the custom
    
    438 443
             // flag will be cleared at the next startup.
    
    439
    -        Services.prefs.setBoolPref(kCustomPref, true);
    
    444
    +        SecurityLevelPrefs.setCustomAndWarn();
    
    440 445
           }),
    
    441 446
         });
    
    442 447
       }
    
    ... ... @@ -505,12 +510,27 @@ export class SecurityLevel {
    505 510
     }
    
    506 511
     
    
    507 512
     /**
    
    508
    - * @typedef {object} SecurityLevelRestartNotificationHandler
    
    513
    + * @callback SecurityLevelTryRestartBrowserCallback
    
    514
    + *
    
    515
    + * @returns {Promise<boolean>} - A promise that resolves when the user has made
    
    516
    + *   a decision. Should return `true` when the browser is now restarting.
    
    517
    + */
    
    518
    +/**
    
    519
    + * @callback SecurityLevelShowCustomWarningCallback
    
    509 520
      *
    
    510
    - * An object that can serve the user a restart notification.
    
    521
    + * @param {Function} userDismissedCallback - A callback that should be called
    
    522
    + *   if the user has acknowledged and dismissed the notification.
    
    523
    + */
    
    524
    +/**
    
    525
    + * @typedef {object} SecurityLevelNotificationHandler
    
    511 526
      *
    
    512
    - * @property {Function} tryRestartBrowser - The method that should be called to
    
    513
    - *   ask the user to restart the browser.
    
    527
    + * An object that can serve the user notifications.
    
    528
    + *
    
    529
    + * @property {SecurityLevelTryRestartBrowserCallback} tryRestartBrowser - The
    
    530
    + *   method that should be called to ask the user to restart the browser.
    
    531
    + * @property {SecurityLevelShowCustomWarningCallback} showCustomWarning - The
    
    532
    + *   method that should be called to let the user know they have a custom
    
    533
    + *   security level.
    
    514 534
      */
    
    515 535
     
    
    516 536
     /*
    
    ... ... @@ -526,6 +546,8 @@ export const SecurityLevelPrefs = {
    526 546
       }),
    
    527 547
       security_slider_pref: "browser.security_level.security_slider",
    
    528 548
       security_custom_pref: "browser.security_level.security_custom",
    
    549
    +  _customWarningDismissedPref:
    
    550
    +    "browser.security_level.custom_warning_dismissed",
    
    529 551
     
    
    530 552
       /**
    
    531 553
        * The current security level preference.
    
    ... ... @@ -581,18 +603,18 @@ export const SecurityLevelPrefs = {
    581 603
       },
    
    582 604
     
    
    583 605
       /**
    
    584
    -   * Whether the browser should be restarted to apply the security level.
    
    606
    +   * The external handler that can show a notification to the user, if any.
    
    585 607
        *
    
    586
    -   * @type {boolean}
    
    608
    +   * @type {?SecurityLevelNotificationHandler}
    
    587 609
        */
    
    588
    -  _needRestart: false,
    
    610
    +  _notificationHandler: null,
    
    589 611
     
    
    590 612
       /**
    
    591
    -   * The external handler that can show a notification to the user, if any.
    
    613
    +   * The notifications we are waiting for a handler to show.
    
    592 614
        *
    
    593
    -   * @type {?SecurityLevelRestartNotificationHandler}
    
    615
    +   * @type {Set}
    
    594 616
        */
    
    595
    -  _restartNotificationHandler: null,
    
    617
    +  _pendingNotifications: {},
    
    596 618
     
    
    597 619
       /**
    
    598 620
        * Set the external handler for showing notifications to the user.
    
    ... ... @@ -600,49 +622,73 @@ export const SecurityLevelPrefs = {
    600 622
        * This should only be called once per session once the handler is ready to
    
    601 623
        * show a notification, which may occur immediately during this call.
    
    602 624
        *
    
    603
    -   * @param {SecurityLevelRestartNotificationHandler} handler - The new handler
    
    604
    -   *   to use.
    
    625
    +   * @param {SecurityLevelNotificationHandler} handler - The new handler to use.
    
    605 626
        */
    
    606
    -  setRestartNotificationHandler(handler) {
    
    627
    +  setNotificationHandler(handler) {
    
    607 628
         logger.info("Restart notification handler is set");
    
    608
    -    this._restartNotificationHandler = handler;
    
    609
    -    if (this._needRestart) {
    
    610
    -      // Show now using the new handler.
    
    611
    -      this._tryShowRestartNotification();
    
    612
    -    }
    
    629
    +    this._notificationHandler = handler;
    
    630
    +    this._tryShowNotifications(this._pendingNotifications);
    
    613 631
       },
    
    614 632
     
    
    615 633
       /**
    
    616 634
        * A promise for any ongoing notification prompt task.
    
    617 635
        *
    
    618
    -   * @type {Promise}
    
    636
    +   * Resolves with whether the browser is restarting.
    
    637
    +   *
    
    638
    +   * @type {Promise<boolean>}
    
    619 639
        */
    
    620 640
       _restartNotificationPromise: null,
    
    621 641
     
    
    622 642
       /**
    
    623
    -   * Try show a notification to the user.
    
    643
    +   * Try show notifications to the user.
    
    644
    +   *
    
    645
    +   * If no notification handler has been attached yet, this will queue the
    
    646
    +   * notification for when it is added, if ever.
    
    624 647
        *
    
    625
    -   * If no notification handler has been attached yet, this will do nothing.
    
    648
    +   * @param {object} notifications - The notifications to try and show.
    
    649
    +   * @param {boolean} notifications.restart - Whether to show the restart
    
    650
    +   *   notification.
    
    651
    +   * @param {boolean} notifications.custom - Whether to show the custom security
    
    652
    +   *   level notification.
    
    626 653
        */
    
    627
    -  async _tryShowRestartNotification() {
    
    628
    -    if (!this._restartNotificationHandler) {
    
    629
    -      logger.info("Missing a restart notification handler");
    
    654
    +  async _tryShowNotifications(notifications) {
    
    655
    +    if (!this._notificationHandler) {
    
    656
    +      logger.info("Missing a notification handler", notifications);
    
    630 657
           // This may be added later in the session.
    
    658
    +      if (notifications.custom) {
    
    659
    +        this._pendingNotifications.custom = true;
    
    660
    +      }
    
    661
    +      if (notifications.restart) {
    
    662
    +        this._pendingNotifications.restart = true;
    
    663
    +      }
    
    631 664
           return;
    
    632 665
         }
    
    633 666
     
    
    634
    -    const prevPromise = this._restartNotificationPromise;
    
    635
    -    let resolve;
    
    636
    -    ({ promise: this._restartNotificationPromise, resolve } =
    
    637
    -      Promise.withResolvers());
    
    638
    -    await prevPromise;
    
    639
    -
    
    640
    -    try {
    
    641
    -      await this._restartNotificationHandler?.tryRestartBrowser();
    
    642
    -    } finally {
    
    643
    -      // Allow the notification to be shown again.
    
    644
    -      resolve();
    
    667
    +    let isRestarting = false;
    
    668
    +    if (notifications.restart) {
    
    669
    +      const prevPromise = this._restartNotificationPromise;
    
    670
    +      let resolve;
    
    671
    +      ({ promise: this._restartNotificationPromise, resolve } =
    
    672
    +        Promise.withResolvers());
    
    673
    +      await prevPromise;
    
    674
    +
    
    675
    +      try {
    
    676
    +        isRestarting = await this._notificationHandler?.tryRestartBrowser();
    
    677
    +      } finally {
    
    678
    +        // Allow the notification to be shown again.
    
    679
    +        resolve();
    
    680
    +      }
    
    681
    +    }
    
    682
    +    // NOTE: We wait for the restart notification to resolve before showing the
    
    683
    +    // custom warning. We do not show the warning if we are already restarting.
    
    684
    +    if (!isRestarting && notifications.custom) {
    
    685
    +      this._notificationHandler?.showCustomWarning(() => {
    
    686
    +        // User has acknowledged and dismissed the notification.
    
    687
    +        Services.prefs.setBoolPref(this._customWarningDismissedPref, true);
    
    688
    +      });
    
    645 689
         }
    
    690
    +
    
    691
    +    this._pendingNotifications = {};
    
    646 692
       },
    
    647 693
     
    
    648 694
       /**
    
    ... ... @@ -658,7 +704,6 @@ export const SecurityLevelPrefs = {
    658 704
         // At the next startup, the custom flag may be cleared if the settings are
    
    659 705
         // as expected.
    
    660 706
         Services.prefs.setBoolPref(kCustomPref, true);
    
    661
    -    this._needRestart = true;
    
    662 707
     
    
    663 708
         // NOTE: We need to change the controlled security level preferences in
    
    664 709
         // response to the desired change in security level. We could either:
    
    ... ... @@ -684,6 +729,39 @@ export const SecurityLevelPrefs = {
    684 729
         // still be marked as "custom" because:
    
    685 730
         // 1. Some preferences require a browser restart to be applied.
    
    686 731
         // 2. NoScript has not been updated with the new settings.
    
    687
    -    this._tryShowRestartNotification();
    
    732
    +
    
    733
    +    this._tryShowNotifications({ restart: true, custom: true });
    
    734
    +  },
    
    735
    +
    
    736
    +  /**
    
    737
    +   * Put the user in the custom security level state and show them a warning
    
    738
    +   * about this state.
    
    739
    +   */
    
    740
    +  setCustomAndWarn() {
    
    741
    +    Services.prefs.setBoolPref(kCustomPref, true);
    
    742
    +    // NOTE: We clear _customWarningDismissedPref because the entry points
    
    743
    +    // for this method imply we should re-warn the user each time.
    
    744
    +    Services.prefs.clearUserPref(this._customWarningDismissedPref);
    
    745
    +    this._tryShowNotifications({ custom: true });
    
    746
    +  },
    
    747
    +
    
    748
    +  /**
    
    749
    +   * If the user is in a custom state, try and notify them of this state.
    
    750
    +   */
    
    751
    +  maybeWarnCustom() {
    
    752
    +    const isCustom = Services.prefs.getBoolPref(kCustomPref, false);
    
    753
    +    if (!isCustom) {
    
    754
    +      // Clear the dismissed preference so the user will be re-shown the
    
    755
    +      // notification when they re-enter the custom state.
    
    756
    +      Services.prefs.clearUserPref(this._customWarningDismissedPref);
    
    757
    +      return;
    
    758
    +    }
    
    759
    +    if (Services.prefs.getBoolPref(this._customWarningDismissedPref, false)) {
    
    760
    +      // Do not warn the user of the custom state if they have already
    
    761
    +      // acknowledged and dismissed this in a previous session.
    
    762
    +      return;
    
    763
    +    }
    
    764
    +
    
    765
    +    this._tryShowNotifications({ custom: true });
    
    688 766
       },
    
    689 767
     }; /* Security Level Prefs */