Verified Commit 504c9c48 authored by ma1's avatar ma1 Committed by Pier Angelo Vendrame
Browse files

Bug 41695: Warn on window maximization without letterboxing in RFPHelper module

parent 23df1a9a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -370,6 +370,8 @@ pref("security.remote_settings.intermediates.enabled", false);
pref("dom.use_components_shim", false);
// Enable letterboxing
pref("privacy.resistFingerprinting.letterboxing", true);
// tor-browser#41695: how many warnings we show if user closes them without restoring the window size
pref("privacy.resistFingerprinting.resizeWarnings", 3);
// tor-browser#33282: new windows start at 1400x900 when there's enough screen space, otherwise down by 200x100 blocks
pref("privacy.window.maxInnerWidth", 1400);
pref("privacy.window.maxInnerHeight", 900);
+95 −1
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ const kPrefLetterboxingTesting =
  "privacy.resistFingerprinting.letterboxing.testing";
const kTopicDOMWindowOpened = "domwindowopened";

const kPrefResizeWarnings = "privacy.resistFingerprinting.resizeWarnings";

const lazy = {};

XPCOMUtils.defineLazyGetter(lazy, "logConsole", () =>
@@ -43,6 +45,84 @@ function forEachWindow(callback) {
  }
}

async function windowResizeHandler(aEvent) {
  if (RFPHelper.letterboxingEnabled || !RFPHelper.rfpEnabled) {
    return;
  }
  if (Services.prefs.getIntPref(kPrefResizeWarnings) <= 0) {
    return;
  }

  const window = aEvent.currentTarget;

  // Wait for end of execution queue to ensure we have correct windowState.
  await new Promise(resolve => window.setTimeout(resolve, 0));
  switch (window.windowState) {
    case window.STATE_MAXIMIZED:
    case window.STATE_FULLSCREEN:
      break;
    default:
      return;
  }

  // Do not add another notification if one is already showing.
  const kNotificationName = "rfp-window-resize-notification";
  let box = window.gNotificationBox;
  if (box.getNotificationWithValue(kNotificationName)) {
    return;
  }

  // Rate-limit showing our notification if needed.
  if (Date.now() - (windowResizeHandler.timestamp || 0) < 1000) {
    return;
  }
  windowResizeHandler.timestamp = Date.now();

  const decreaseWarningsCount = () => {
    const currentCount = Services.prefs.getIntPref(kPrefResizeWarnings);
    if (currentCount > 0) {
      Services.prefs.setIntPref(kPrefResizeWarnings, currentCount - 1);
    }
  };

  const [label, accessKey] = await window.document.l10n.formatValues([
    { id: "basebrowser-rfp-restore-window-size-button-label" },
    { id: "basebrowser-rfp-restore-window-size-button-ak" },
  ]);

  const buttons = [
    {
      label,
      accessKey,
      popup: null,
      callback() {
        // reset notification timer to work-around resize race conditions
        windowResizeHandler.timestamp = Date.now();
        // restore the original (rounded) size we had stored on window startup
        let { _rfpOriginalSize } = window;
        window.setTimeout(() => {
          window.resizeTo(_rfpOriginalSize.width, _rfpOriginalSize.height);
        }, 0);
      },
    },
  ];

  box.appendNotification(
    kNotificationName,
    {
      label: { "l10n-id": "basebrowser-rfp-maximize-warning-message" },
      priority: box.PRIORITY_WARNING_LOW,
      eventCallback(event) {
        if (event === "dismissed") {
          // user manually dismissed the notification
          decreaseWarningsCount();
        }
      },
    },
    buttons
  );
}

class _RFPHelper {
  // ============================================================================
  // Shared Setup
@@ -443,7 +523,12 @@ class _RFPHelper {
      ])
    );

    if (!win._rfpSizeOffset) {
    if (
      !win._rfpSizeOffset ||
      (win._rfpOriginalSize &&
        win.outerWidth === win._rfpOriginalSize.width &&
        win.outerHeight === win._rfpOriginalSize.height)
    ) {
      const BASELINE_ROUNDING = 10;
      const offset = s =>
        s - Math.round(s / BASELINE_ROUNDING) * BASELINE_ROUNDING;
@@ -613,10 +698,18 @@ class _RFPHelper {
    // we need to add this class late because otherwise new windows get maximized
    aWindow.setTimeout(() => {
      tabBrowser.tabpanels?.classList.add("letterboxing-ready");
      if (!aWindow._rfpOriginalSize) {
        aWindow._rfpOriginalSize = {
          width: aWindow.outerWidth,
          height: aWindow.outerHeight,
        };
        log("Recording original window size", aWindow._rfpOriginalSize);
      }
    });
  }

  _attachWindow(aWindow) {
    aWindow.addEventListener("sizemodechange", windowResizeHandler);
    aWindow.gBrowser.addTabsProgressListener(this);
    aWindow.addEventListener("TabOpen", this);
    const resizeObserver = (aWindow._rfpResizeObserver =
@@ -648,6 +741,7 @@ class _RFPHelper {
      let browser = tab.linkedBrowser;
      this._resetContentSize(browser);
    }
    aWindow.removeEventListener("sizemodechange", windowResizeHandler);
  }

  _handleDOMWindowOpened(win) {