tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

browser_protectionsUI_suspicious_fingerprinters_subview.js (11851B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 requestLongerTimeout(2);
      7 
      8 /**
      9 * Bug 1863280 - Testing the fingerprinting category of the protection panel
     10 *               shows the suspicious fingerpinter domain if the fingerprinting
     11 *               protection is enabled
     12 */
     13 
     14 const TEST_PATH = getRootDirectory(gTestPath).replace(
     15  "chrome://mochitests/content",
     16  ""
     17 );
     18 
     19 const TEST_DOMAIN = "https://www.example.com";
     20 const TEST_3RD_DOMAIN = "https://example.org";
     21 
     22 const TEST_PAGE = TEST_DOMAIN + TEST_PATH + "benignPage.html";
     23 const TEST_3RD_CANVAS_FP_PAGE =
     24  TEST_3RD_DOMAIN + TEST_PATH + "canvas-fingerprinter.html";
     25 const TEST_3RD_FONT_FP_PAGE =
     26  TEST_3RD_DOMAIN + TEST_PATH + "font-fingerprinter.html";
     27 
     28 const FINGERPRINT_BLOCKING_PREF =
     29  "privacy.trackingprotection.fingerprinting.enabled";
     30 const FINGERPRINT_PROTECTION_PREF = "privacy.fingerprintingProtection";
     31 const FINGERPRINT_PROTECTION_PBM_PREF =
     32  "privacy.fingerprintingProtection.pbmode";
     33 
     34 /**
     35 * A helper function to check whether or not an element has "notFound" class.
     36 *
     37 * @param {string} id The id of the testing element.
     38 * @returns {boolean} true when the element has "notFound" class.
     39 */
     40 function notFound(id) {
     41  return document.getElementById(id).classList.contains("notFound");
     42 }
     43 
     44 /**
     45 * A helper function to wait until the suspicious fingerprinting content
     46 * blocking event is dispatched.
     47 *
     48 * @param {Window} win The window to listen content blocking events.
     49 * @returns {Promise} A promise that resolves when the event files.
     50 */
     51 async function waitForSuspiciousFingerprintingEvent(win) {
     52  return new Promise(resolve => {
     53    let listener = {
     54      onContentBlockingEvent(webProgress, request, event) {
     55        info(`Received onContentBlockingEvent event: ${event}`);
     56        if (
     57          event &
     58          Ci.nsIWebProgressListener.STATE_BLOCKED_SUSPICIOUS_FINGERPRINTING
     59        ) {
     60          win.gBrowser.removeProgressListener(listener);
     61          resolve();
     62        }
     63      },
     64    };
     65    win.gBrowser.addProgressListener(listener);
     66  });
     67 }
     68 
     69 /**
     70 * A helper function that opens a tests page that embeds iframes with given
     71 * urls.
     72 *
     73 * @param {string[]} urls An array of urls that will be embedded in the test page.
     74 * @param {boolean} usePrivateWin true to indicate testing in a private window.
     75 * @param {Function} testFn The test function that will be called after the
     76 * iframes have been loaded.
     77 */
     78 async function openTestPage(urls, usePrivateWin, testFn) {
     79  let win = window;
     80 
     81  if (usePrivateWin) {
     82    win = await BrowserTestUtils.openNewBrowserWindow({ private: true });
     83  }
     84 
     85  await BrowserTestUtils.withNewTab(
     86    { gBrowser: win.gBrowser, url: TEST_PAGE },
     87    async browser => {
     88      info("Loading all iframes");
     89 
     90      for (const url of urls) {
     91        await SpecialPowers.spawn(browser, [url], async testUrl => {
     92          await new content.Promise(resolve => {
     93            let ifr = content.document.createElement("iframe");
     94            ifr.onload = resolve;
     95            ifr.src = testUrl;
     96 
     97            content.document.body.appendChild(ifr);
     98          });
     99        });
    100      }
    101 
    102      info("Running the test");
    103      await testFn(win, browser);
    104    }
    105  );
    106 
    107  if (usePrivateWin) {
    108    await BrowserTestUtils.closeWindow(win);
    109  }
    110 }
    111 
    112 /**
    113 * A testing function verifies that fingerprinting category is not shown.
    114 *
    115 * @param {*} win The window to run the test.
    116 */
    117 async function testCategoryNotShown(win) {
    118  await openProtectionsPanel(false, win);
    119 
    120  let categoryItem = win.document.getElementById(
    121    "protections-popup-category-fingerprinters"
    122  );
    123 
    124  // The fingerprinting category should have the 'notFound' class to indicate
    125  // that no fingerprinter was found in the page.
    126  ok(
    127    notFound("protections-popup-category-fingerprinters"),
    128    "Fingerprinting category is not found"
    129  );
    130 
    131  ok(
    132    !BrowserTestUtils.isVisible(categoryItem),
    133    "Fingerprinting category item is not visible"
    134  );
    135 
    136  await closeProtectionsPanel(win);
    137 }
    138 
    139 add_setup(async function () {
    140  await SpecialPowers.pushPrefEnv({
    141    set: [[FINGERPRINT_BLOCKING_PREF, true]],
    142  });
    143 });
    144 
    145 // Verify that fingerprinting category is not shown if fingerprinting protection
    146 // is disabled.
    147 add_task(async function testFPPDisabled() {
    148  await SpecialPowers.pushPrefEnv({
    149    set: [[FINGERPRINT_PROTECTION_PREF, false]],
    150  });
    151 
    152  await openTestPage(
    153    [TEST_3RD_CANVAS_FP_PAGE, TEST_3RD_FONT_FP_PAGE],
    154    false,
    155    testCategoryNotShown
    156  );
    157 });
    158 
    159 // Verify that fingerprinting category is properly shown and the fingerprinting
    160 // subview displays the origin of the suspicious fingerprinter.
    161 add_task(async function testFingerprintingSubview() {
    162  await SpecialPowers.pushPrefEnv({
    163    set: [[FINGERPRINT_PROTECTION_PREF, true]],
    164  });
    165 
    166  await openTestPage(
    167    [TEST_3RD_CANVAS_FP_PAGE, TEST_3RD_FONT_FP_PAGE],
    168    false,
    169    async (win, _) => {
    170      await openProtectionsPanel(false, win);
    171 
    172      let categoryItem = win.document.getElementById(
    173        "protections-popup-category-fingerprinters"
    174      );
    175 
    176      // Explicitly waiting for the category item becoming visible.
    177      await BrowserTestUtils.waitForMutationCondition(categoryItem, {}, () =>
    178        BrowserTestUtils.isVisible(categoryItem)
    179      );
    180 
    181      ok(
    182        BrowserTestUtils.isVisible(categoryItem),
    183        "Fingerprinting category item is visible"
    184      );
    185 
    186      // Click the fingerprinting category and wait until the fingerprinter view is
    187      // shown.
    188      let fingerprintersView = win.document.getElementById(
    189        "protections-popup-fingerprintersView"
    190      );
    191      let viewShown = BrowserTestUtils.waitForEvent(
    192        fingerprintersView,
    193        "ViewShown"
    194      );
    195      categoryItem.click();
    196      await viewShown;
    197 
    198      ok(true, "Fingerprinter view was shown");
    199 
    200      // Ensure the fingerprinter is listed on the tracker list.
    201      let listItems = Array.from(
    202        fingerprintersView.querySelectorAll(".protections-popup-list-item")
    203      );
    204      is(listItems.length, 1, "We have 1 fingerprinter in the list");
    205 
    206      let listItem = listItems.find(
    207        item => item.querySelector("label").value == "https://example.org"
    208      );
    209      ok(listItem, "Has an item for example.org");
    210      ok(BrowserTestUtils.isVisible(listItem), "List item is visible");
    211 
    212      // Back to the popup main view.
    213      let mainView = win.document.getElementById("protections-popup-mainView");
    214      viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
    215      let backButton = fingerprintersView.querySelector(".subviewbutton-back");
    216      backButton.click();
    217      await viewShown;
    218 
    219      ok(true, "Main view was shown");
    220 
    221      await closeProtectionsPanel(win);
    222    }
    223  );
    224 });
    225 
    226 // Verify the case where the fingerprinting protection is only enabled in PBM.
    227 add_task(async function testFingerprintingSubviewInPBM() {
    228  // Only enabled fingerprinting protection in PBM.
    229  await SpecialPowers.pushPrefEnv({
    230    set: [
    231      [FINGERPRINT_PROTECTION_PREF, false],
    232      [FINGERPRINT_PROTECTION_PBM_PREF, true],
    233    ],
    234  });
    235 
    236  // Verify that fingerprinting category isn't shown on a normal window.
    237  await openTestPage(
    238    [TEST_3RD_CANVAS_FP_PAGE, TEST_3RD_FONT_FP_PAGE],
    239    false,
    240    testCategoryNotShown
    241  );
    242 
    243  // Verify that fingerprinting category is shown on a private window.
    244  await openTestPage(
    245    [TEST_3RD_CANVAS_FP_PAGE, TEST_3RD_FONT_FP_PAGE],
    246    true,
    247    async (win, _) => {
    248      await openProtectionsPanel(false, win);
    249 
    250      let categoryItem = win.document.getElementById(
    251        "protections-popup-category-fingerprinters"
    252      );
    253 
    254      // Explicitly waiting for the category item becoming visible.
    255      await BrowserTestUtils.waitForMutationCondition(categoryItem, {}, () =>
    256        BrowserTestUtils.isVisible(categoryItem)
    257      );
    258 
    259      ok(
    260        BrowserTestUtils.isVisible(categoryItem),
    261        "Fingerprinting category item is visible"
    262      );
    263 
    264      // Click the fingerprinting category and wait until the fingerprinter view is
    265      // shown.
    266      let fingerprintersView = win.document.getElementById(
    267        "protections-popup-fingerprintersView"
    268      );
    269      let viewShown = BrowserTestUtils.waitForEvent(
    270        fingerprintersView,
    271        "ViewShown"
    272      );
    273      categoryItem.click();
    274      await viewShown;
    275 
    276      ok(true, "Fingerprinter view was shown");
    277 
    278      // Ensure the fingerprinter is listed on the tracker list.
    279      let listItems = Array.from(
    280        fingerprintersView.querySelectorAll(".protections-popup-list-item")
    281      );
    282      is(listItems.length, 1, "We have 1 fingerprinter in the list");
    283 
    284      let listItem = listItems.find(
    285        item => item.querySelector("label").value == "https://example.org"
    286      );
    287      ok(listItem, "Has an item for example.org");
    288      ok(BrowserTestUtils.isVisible(listItem), "List item is visible");
    289 
    290      // Back to the popup main view.
    291      let mainView = win.document.getElementById("protections-popup-mainView");
    292      viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
    293      let backButton = fingerprintersView.querySelector(".subviewbutton-back");
    294      backButton.click();
    295      await viewShown;
    296 
    297      ok(true, "Main view was shown");
    298 
    299      await closeProtectionsPanel(win);
    300    }
    301  );
    302 });
    303 
    304 // Verify that fingerprinting category will be shown after loading
    305 // fingerprinters.
    306 add_task(async function testDynamicallyLoadFingerprinter() {
    307  await SpecialPowers.pushPrefEnv({
    308    set: [[FINGERPRINT_PROTECTION_PREF, true]],
    309  });
    310 
    311  await openTestPage([], false, async (win, browser) => {
    312    await openProtectionsPanel(false, win);
    313 
    314    let categoryItem = win.document.getElementById(
    315      "protections-popup-category-fingerprinters"
    316    );
    317 
    318    // The fingerprinting category should have the 'notFound' class to indicate
    319    // that no suspicious fingerprinter was found in the page.
    320    ok(
    321      notFound("protections-popup-category-fingerprinters"),
    322      "Fingerprinting category is not found"
    323    );
    324 
    325    ok(
    326      !BrowserTestUtils.isVisible(categoryItem),
    327      "Fingerprinting category item is not visible"
    328    );
    329 
    330    // Add an iframe that triggers suspicious fingerprinting and wait until the
    331    // content event files.
    332 
    333    let contentBlockingEventPromise = waitForSuspiciousFingerprintingEvent(win);
    334    await SpecialPowers.spawn(browser, [TEST_3RD_CANVAS_FP_PAGE], test_url => {
    335      let ifr = content.document.createElement("iframe");
    336 
    337      content.document.body.appendChild(ifr);
    338      ifr.src = test_url;
    339    });
    340    await contentBlockingEventPromise;
    341 
    342    // Click the fingerprinting category and wait until the fingerprinter view
    343    // is shown.
    344    let fingerprintersView = win.document.getElementById(
    345      "protections-popup-fingerprintersView"
    346    );
    347    let viewShown = BrowserTestUtils.waitForEvent(
    348      fingerprintersView,
    349      "ViewShown"
    350    );
    351    categoryItem.click();
    352    await viewShown;
    353 
    354    ok(true, "Fingerprinter view was shown");
    355 
    356    // Ensure the fingerprinter is listed on the tracker list.
    357    let listItems = Array.from(
    358      fingerprintersView.querySelectorAll(".protections-popup-list-item")
    359    );
    360    is(listItems.length, 1, "We have 1 fingerprinter in the list");
    361 
    362    let listItem = listItems.find(
    363      item => item.querySelector("label").value == "https://example.org"
    364    );
    365    ok(listItem, "Has an item for example.org");
    366    ok(BrowserTestUtils.isVisible(listItem), "List item is visible");
    367 
    368    // Back to the popup main view.
    369    let mainView = win.document.getElementById("protections-popup-mainView");
    370    viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
    371    let backButton = fingerprintersView.querySelector(".subviewbutton-back");
    372    backButton.click();
    373    await viewShown;
    374 
    375    ok(true, "Main view was shown");
    376 
    377    await closeProtectionsPanel(win);
    378  });
    379 });