Pier Angelo Vendrame pushed to branch base-browser-102.9.0esr-12.5-1 at The Tor Project / Applications / Tor Browser

Commits:

2 changed files:

Changes:

  • browser/locales/en-US/browser/languageNotification.ftl
    ... ... @@ -8,3 +8,7 @@ language-notification-label-system = { -brand-short-name } has set your display
    8 8
     # $language is the language Tor Browser is displayed in (already translated).
    
    9 9
     language-notification-label = { -brand-short-name } has set your display language to { $language }.
    
    10 10
     language-notification-button = Change Language…
    
    11
    +
    
    12
    +basebrowser-rfp-maximize-warning-message = Maximizing the browser window can allow websites to determine your monitor size, which can be used to track you. We recommend that you leave browser windows in their original default size.
    
    13
    +basebrowser-rfp-restore-window-size-button-label = Restore
    
    14
    +basebrowser-rfp-restore-window-size-button-ak = R

  • toolkit/components/resistfingerprinting/RFPHelper.jsm
    ... ... @@ -22,16 +22,110 @@ const kPrefLetterboxingTesting =
    22 22
       "privacy.resistFingerprinting.letterboxing.testing";
    
    23 23
     const kTopicDOMWindowOpened = "domwindowopened";
    
    24 24
     
    
    25
    -var logConsole;
    
    26
    -function log(msg) {
    
    27
    -  if (!logConsole) {
    
    28
    -    logConsole = console.createInstance({
    
    29
    -      prefix: "RFPHelper.jsm",
    
    30
    -      maxLogLevelPref: "privacy.resistFingerprinting.jsmloglevel",
    
    31
    -    });
    
    25
    +const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";
    
    26
    +
    
    27
    +XPCOMUtils.defineLazyGetter(this, "logConsole", () =>
    
    28
    +  console.createInstance({
    
    29
    +    prefix: "RFPHelper.jsm",
    
    30
    +    maxLogLevelPref: "privacy.resistFingerprinting.jsmloglevel",
    
    31
    +  })
    
    32
    +);
    
    33
    +
    
    34
    +function log(...args) {
    
    35
    +  logConsole.log(...args);
    
    36
    +}
    
    37
    +
    
    38
    +function forEachWindow(callback) {
    
    39
    +  const windowList = Services.wm.getEnumerator("navigator:browser");
    
    40
    +  while (windowList.hasMoreElements()) {
    
    41
    +    const win = windowList.getNext();
    
    42
    +    if (win.gBrowser && !win.closed) {
    
    43
    +      try {
    
    44
    +        callback(win);
    
    45
    +      } catch (e) {
    
    46
    +        logConsole.error(e);
    
    47
    +      }
    
    48
    +    }
    
    49
    +  }
    
    50
    +}
    
    51
    +
    
    52
    +
    
    53
    +async function windowResizeHandler(aEvent) {
    
    54
    +  if (RFPHelper.letterboxingEnabled) {
    
    55
    +    return;
    
    56
    +  }
    
    57
    +  if (Services.prefs.getIntPref(kPrefResizeWarnings, 3) <= 0) {
    
    58
    +    return;
    
    59
    +  }
    
    60
    +
    
    61
    +  const window = aEvent.currentTarget;
    
    62
    +
    
    63
    +  // Wait for end of execution queue to ensure we have correct windowState.
    
    64
    +  await new Promise(resolve => window.setTimeout(resolve, 0));
    
    65
    +  switch (window.windowState) {
    
    66
    +    case window.STATE_MAXIMIZED:
    
    67
    +    case window.STATE_FULLSCREEN:
    
    68
    +      break;
    
    69
    +    default:
    
    70
    +      return;
    
    71
    +  }
    
    72
    +
    
    73
    +  // Do not add another notification if one is already showing.
    
    74
    +  const kNotificationName = "rfp-window-resize-notification";
    
    75
    +  let box = window.gNotificationBox;
    
    76
    +  if (box.getNotificationWithValue(kNotificationName)) {
    
    77
    +    return;
    
    32 78
       }
    
    33 79
     
    
    34
    -  logConsole.log(msg);
    
    80
    +  // Rate-limit showing our notification if needed.
    
    81
    +  if (Date.now() - (windowResizeHandler.timestamp || 0) < 1000) {
    
    82
    +    return;
    
    83
    +  }
    
    84
    +  windowResizeHandler.timestamp = Date.now();
    
    85
    +
    
    86
    +  const decreaseWarningsCount = () => {
    
    87
    +    const currentCount = Services.prefs.getIntPref(kPrefResizeWarnings);
    
    88
    +    if (currentCount > 0) {
    
    89
    +      Services.prefs.setIntPref(kPrefResizeWarnings, currentCount - 1);
    
    90
    +    }
    
    91
    +  };
    
    92
    +
    
    93
    +  const [label, accessKey] = await window.document.l10n.formatValues([
    
    94
    +    { id: "basebrowser-rfp-restore-window-size-button-label" },
    
    95
    +    { id: "basebrowser-rfp-restore-window-size-button-ak" },
    
    96
    +  ]);
    
    97
    +
    
    98
    +  const buttons = [
    
    99
    +    {
    
    100
    +      label,
    
    101
    +      accessKey,
    
    102
    +      popup: null,
    
    103
    +      callback() {
    
    104
    +        // reset notification timer to work-around resize race conditions
    
    105
    +        windowResizeHandler.timestamp = Date.now();
    
    106
    +        // restore the original (rounded) size we had stored on window startup
    
    107
    +        let { _rfpOriginalSize } = window;
    
    108
    +        window.setTimeout(() => {
    
    109
    +          window.resizeTo(_rfpOriginalSize.width, _rfpOriginalSize.height);
    
    110
    +        }, 0);
    
    111
    +      },
    
    112
    +    },
    
    113
    +  ];
    
    114
    +
    
    115
    +  box.appendNotification(
    
    116
    +    kNotificationName,
    
    117
    +    {
    
    118
    +      label: { "l10n-id": "basebrowser-rfp-maximize-warning-message" },
    
    119
    +      priority: box.PRIORITY_WARNING_LOW,
    
    120
    +      eventCallback(event) {
    
    121
    +        if (event === "dismissed") {
    
    122
    +          // user manually dismissed the notification
    
    123
    +          decreaseWarningsCount();
    
    124
    +        }
    
    125
    +      },
    
    126
    +    },
    
    127
    +    buttons
    
    128
    +  );
    
    35 129
     }
    
    36 130
     
    
    37 131
     class _RFPHelper {
    
    ... ... @@ -158,7 +252,11 @@ class _RFPHelper {
    158 252
       _handleResistFingerprintingChanged() {
    
    159 253
         if (Services.prefs.getBoolPref(kPrefResistFingerprinting)) {
    
    160 254
           this._addRFPObservers();
    
    255
    +      Services.ww.registerNotification(this);
    
    256
    +      forEachWindow(win => this._attachWindow(win));
    
    161 257
         } else {
    
    258
    +      forEachWindow(win => this._detachWindow(win));
    
    259
    +      Services.ww.unregisterNotification(this);
    
    162 260
           this._removeRFPObservers();
    
    163 261
         }
    
    164 262
       }
    
    ... ... @@ -295,13 +393,11 @@ class _RFPHelper {
    295 393
       }
    
    296 394
     
    
    297 395
       _handleLetterboxingPrefChanged() {
    
    298
    -    if (Services.prefs.getBoolPref(kPrefLetterboxing, false)) {
    
    299
    -      Services.ww.registerNotification(this);
    
    300
    -      this._attachAllWindows();
    
    301
    -    } else {
    
    302
    -      this._detachAllWindows();
    
    303
    -      Services.ww.unregisterNotification(this);
    
    304
    -    }
    
    396
    +    this.letterboxingEnabled = Services.prefs.getBoolPref(
    
    397
    +      kPrefLetterboxing,
    
    398
    +      false
    
    399
    +    );
    
    400
    +    forEachWindow(win => this._updateSizeForTabsInWindow(win));
    
    305 401
       }
    
    306 402
     
    
    307 403
       // The function to parse the dimension set from the pref value. The pref value
    
    ... ... @@ -402,11 +498,13 @@ class _RFPHelper {
    402 498
         let logPrefix = `_roundContentSize[${Math.random()}]`;
    
    403 499
         log(logPrefix);
    
    404 500
         let win = aBrowser.ownerGlobal;
    
    501
    +
    
    405 502
         let browserContainer = aBrowser
    
    406 503
           .getTabBrowser()
    
    407 504
           .getBrowserContainer(aBrowser);
    
    408 505
         let browserParent = aBrowser.parentElement;
    
    409 506
         browserParent.classList.remove("exclude-letterboxing");
    
    507
    +
    
    410 508
         let [
    
    411 509
           [contentWidth, contentHeight],
    
    412 510
           [parentWidth, parentHeight],
    
    ... ... @@ -419,6 +517,27 @@ class _RFPHelper {
    419 517
           ])
    
    420 518
         );
    
    421 519
     
    
    520
    +    if (
    
    521
    +      !win._rfpSizeOffset ||
    
    522
    +      (win._rfpOriginalSize &&
    
    523
    +        win.outerWidth === win._rfpOriginalSize.width &&
    
    524
    +        win.outerHeight === win._rfpOriginalSize.height)
    
    525
    +    ) {
    
    526
    +      const BASELINE_ROUNDING = 10;
    
    527
    +      const offset = s =>
    
    528
    +        s - Math.round(s / BASELINE_ROUNDING) * BASELINE_ROUNDING;
    
    529
    +
    
    530
    +      win._rfpSizeOffset = {
    
    531
    +        width: offset(parentWidth),
    
    532
    +        height: offset(parentHeight),
    
    533
    +      };
    
    534
    +      log(
    
    535
    +        `${logPrefix} Window size offsets %o (from %s, %s)`,
    
    536
    +        win._rfpSizeOffset,
    
    537
    +        parentWidth,
    
    538
    +        parentHeight
    
    539
    +      );
    
    540
    +    }
    
    422 541
         log(
    
    423 542
           `${logPrefix} contentWidth=${contentWidth} contentHeight=${contentHeight} parentWidth=${parentWidth} parentHeight=${parentHeight} containerWidth=${containerWidth} containerHeight=${containerHeight}${
    
    424 543
             isNewTab ? " (new tab)." : "."
    
    ... ... @@ -437,6 +556,16 @@ class _RFPHelper {
    437 556
           });
    
    438 557
     
    
    439 558
           let result;
    
    559
    +
    
    560
    +      if (!this.letterboxingEnabled) {
    
    561
    +        const offset = win._rfpSizeOffset;
    
    562
    +        result = r(aWidth - offset.width, aHeight - offset.height);
    
    563
    +        log(
    
    564
    +          `${logPrefix} Letterboxing disabled, applying baseline rounding offsets: (${aWidth}, ${aHeight}) => ${result.width} x ${result.height})`
    
    565
    +        );
    
    566
    +        return result;
    
    567
    +      }
    
    568
    +
    
    440 569
           log(`${logPrefix} roundDimensions(${aWidth}, ${aHeight})`);
    
    441 570
           // If the set is empty, we will round the content with the default
    
    442 571
           // stepping size.
    
    ... ... @@ -554,7 +683,6 @@ class _RFPHelper {
    554 683
     
    
    555 684
       _updateSizeForTabsInWindow(aWindow) {
    
    556 685
         let tabBrowser = aWindow.gBrowser;
    
    557
    -
    
    558 686
         tabBrowser.tabpanels?.classList.add("letterboxing");
    
    559 687
     
    
    560 688
         for (let tab of tabBrowser.tabs) {
    
    ... ... @@ -564,10 +692,18 @@ class _RFPHelper {
    564 692
         // we need to add this class late because otherwise new windows get maximized
    
    565 693
         aWindow.setTimeout(() => {
    
    566 694
           tabBrowser.tabpanels?.classList.add("letterboxing-ready");
    
    695
    +      if (!aWindow._rfpOriginalSize) {
    
    696
    +        aWindow._rfpOriginalSize = {
    
    697
    +          width: aWindow.outerWidth,
    
    698
    +          height: aWindow.outerHeight,
    
    699
    +        };
    
    700
    +        log("Recording original window size", aWindow._rfpOriginalSize);
    
    701
    +      }
    
    567 702
         });
    
    568 703
       }
    
    569 704
     
    
    570 705
       _attachWindow(aWindow) {
    
    706
    +    aWindow.addEventListener("sizemodechange", windowResizeHandler);
    
    571 707
         aWindow.gBrowser.addTabsProgressListener(this);
    
    572 708
         aWindow.addEventListener("TabOpen", this);
    
    573 709
         const resizeObserver = (aWindow._rfpResizeObserver = new aWindow.ResizeObserver(
    
    ... ... @@ -585,19 +721,7 @@ class _RFPHelper {
    585 721
         this._updateSizeForTabsInWindow(aWindow);
    
    586 722
       }
    
    587 723
     
    
    588
    -  _attachAllWindows() {
    
    589
    -    let windowList = Services.wm.getEnumerator("navigator:browser");
    
    590 724
     
    
    591
    -    while (windowList.hasMoreElements()) {
    
    592
    -      let win = windowList.getNext();
    
    593
    -
    
    594
    -      if (win.closed || !win.gBrowser) {
    
    595
    -        continue;
    
    596
    -      }
    
    597
    -
    
    598
    -      this._attachWindow(win);
    
    599
    -    }
    
    600
    -  }
    
    601 725
     
    
    602 726
       _detachWindow(aWindow) {
    
    603 727
         let tabBrowser = aWindow.gBrowser;
    
    ... ... @@ -614,20 +738,7 @@ class _RFPHelper {
    614 738
           let browser = tab.linkedBrowser;
    
    615 739
           this._resetContentSize(browser);
    
    616 740
         }
    
    617
    -  }
    
    618
    -
    
    619
    -  _detachAllWindows() {
    
    620
    -    let windowList = Services.wm.getEnumerator("navigator:browser");
    
    621
    -
    
    622
    -    while (windowList.hasMoreElements()) {
    
    623
    -      let win = windowList.getNext();
    
    624
    -
    
    625
    -      if (win.closed || !win.gBrowser) {
    
    626
    -        continue;
    
    627
    -      }
    
    628
    -
    
    629
    -      this._detachWindow(win);
    
    630
    -    }
    
    741
    +    aWindow.removeEventListener("sizemodechange", windowResizeHandler);
    
    631 742
       }
    
    632 743
     
    
    633 744
       _handleDOMWindowOpened(win) {