tor-browser

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

browser_protectionsUI_fingerprinters.js (8598B)


      1 /* Any copyright is dedicated to the Public Domain.
      2 * http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 const TRACKING_PAGE =
      7  // eslint-disable-next-line @microsoft/sdl/no-insecure-url
      8  "http://example.org/browser/browser/base/content/test/protectionsUI/trackingPage.html";
      9 const FP_PROTECTION_PREF = "privacy.trackingprotection.fingerprinting.enabled";
     10 let fpHistogram;
     11 
     12 add_setup(async function () {
     13  await SpecialPowers.pushPrefEnv({
     14    set: [
     15      [
     16        "urlclassifier.features.fingerprinting.blacklistHosts",
     17        "fingerprinting.example.com",
     18      ],
     19      [
     20        "urlclassifier.features.fingerprinting.annotate.blacklistHosts",
     21        "fingerprinting.example.com",
     22      ],
     23      ["privacy.trackingprotection.enabled", false],
     24      ["privacy.trackingprotection.annotate_channels", false],
     25      ["privacy.trackingprotection.cryptomining.enabled", false],
     26      ["urlclassifier.features.cryptomining.annotate.blacklistHosts", ""],
     27      ["urlclassifier.features.cryptomining.annotate.blacklistTables", ""],
     28    ],
     29  });
     30  fpHistogram = Services.telemetry.getHistogramById(
     31    "FINGERPRINTERS_BLOCKED_COUNT"
     32  );
     33  registerCleanupFunction(() => {
     34    fpHistogram.clear();
     35  });
     36 });
     37 
     38 async function testIdentityState(hasException) {
     39  fpHistogram.clear();
     40  let promise = BrowserTestUtils.openNewForegroundTab({
     41    url: TRACKING_PAGE,
     42    gBrowser,
     43  });
     44  let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
     45 
     46  if (hasException) {
     47    let loaded = BrowserTestUtils.browserLoaded(
     48      tab.linkedBrowser,
     49      false,
     50      TRACKING_PAGE
     51    );
     52    gProtectionsHandler.disableForCurrentPage();
     53    await loaded;
     54  }
     55 
     56  await openProtectionsPanel();
     57 
     58  ok(
     59    !gProtectionsHandler._protectionsPopup.hasAttribute("detected"),
     60    "fingerprinters are not detected"
     61  );
     62  ok(
     63    !BrowserTestUtils.isHidden(gProtectionsHandler.iconBox),
     64    "icon box is visible regardless the exception"
     65  );
     66 
     67  promise = waitForContentBlockingEvent();
     68 
     69  await SpecialPowers.spawn(tab.linkedBrowser, [], function () {
     70    content.postMessage("fingerprinting", "*");
     71  });
     72 
     73  await promise;
     74 
     75  ok(
     76    gProtectionsHandler._protectionsPopup.hasAttribute("detected"),
     77    "trackers are detected"
     78  );
     79  ok(
     80    BrowserTestUtils.isVisible(gProtectionsHandler.iconBox),
     81    "icon box is visible"
     82  );
     83  is(
     84    gProtectionsHandler.iconBox.hasAttribute("hasException"),
     85    hasException,
     86    "Shows an exception when appropriate"
     87  );
     88 
     89  if (hasException) {
     90    let loaded = BrowserTestUtils.browserLoaded(
     91      tab.linkedBrowser,
     92      false,
     93      TRACKING_PAGE
     94    );
     95    gProtectionsHandler.enableForCurrentPage();
     96    await loaded;
     97  }
     98 
     99  let loads = hasException ? 3 : 1;
    100  testTelemetry(loads, 1, hasException);
    101 
    102  BrowserTestUtils.removeTab(tab);
    103 }
    104 
    105 async function testCategoryItem() {
    106  Services.prefs.setBoolPref(FP_PROTECTION_PREF, false);
    107  let promise = BrowserTestUtils.openNewForegroundTab({
    108    url: TRACKING_PAGE,
    109    gBrowser,
    110  });
    111  let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
    112 
    113  await openProtectionsPanel();
    114  let categoryItem = document.getElementById(
    115    "protections-popup-category-fingerprinters"
    116  );
    117 
    118  ok(
    119    !categoryItem.classList.contains("blocked"),
    120    "Category not marked as blocked"
    121  );
    122  ok(
    123    categoryItem.classList.contains("notFound"),
    124    "Category marked as not found"
    125  );
    126  Services.prefs.setBoolPref(FP_PROTECTION_PREF, true);
    127  ok(categoryItem.classList.contains("blocked"), "Category marked as blocked");
    128  ok(
    129    categoryItem.classList.contains("notFound"),
    130    "Category marked as not found"
    131  );
    132  Services.prefs.setBoolPref(FP_PROTECTION_PREF, false);
    133  ok(
    134    !categoryItem.classList.contains("blocked"),
    135    "Category not marked as blocked"
    136  );
    137  ok(
    138    categoryItem.classList.contains("notFound"),
    139    "Category marked as not found"
    140  );
    141  await closeProtectionsPanel();
    142 
    143  promise = waitForContentBlockingEvent();
    144 
    145  await SpecialPowers.spawn(tab.linkedBrowser, [], function () {
    146    content.postMessage("fingerprinting", "*");
    147  });
    148 
    149  await promise;
    150 
    151  await openProtectionsPanel();
    152  ok(
    153    !categoryItem.classList.contains("blocked"),
    154    "Category not marked as blocked"
    155  );
    156  ok(
    157    !categoryItem.classList.contains("notFound"),
    158    "Category not marked as not found"
    159  );
    160  Services.prefs.setBoolPref(FP_PROTECTION_PREF, true);
    161  ok(categoryItem.classList.contains("blocked"), "Category marked as blocked");
    162  ok(
    163    !categoryItem.classList.contains("notFound"),
    164    "Category not marked as not found"
    165  );
    166  Services.prefs.setBoolPref(FP_PROTECTION_PREF, false);
    167  ok(
    168    !categoryItem.classList.contains("blocked"),
    169    "Category not marked as blocked"
    170  );
    171  ok(
    172    !categoryItem.classList.contains("notFound"),
    173    "Category not marked as not found"
    174  );
    175  await closeProtectionsPanel();
    176 
    177  BrowserTestUtils.removeTab(tab);
    178 }
    179 
    180 async function testSubview(hasException) {
    181  fpHistogram.clear();
    182  let promise = BrowserTestUtils.openNewForegroundTab({
    183    url: TRACKING_PAGE,
    184    gBrowser,
    185  });
    186  let [tab] = await Promise.all([promise, waitForContentBlockingEvent()]);
    187 
    188  if (hasException) {
    189    let loaded = BrowserTestUtils.browserLoaded(
    190      tab.linkedBrowser,
    191      false,
    192      TRACKING_PAGE
    193    );
    194    gProtectionsHandler.disableForCurrentPage();
    195    await loaded;
    196  }
    197 
    198  promise = waitForContentBlockingEvent();
    199  await SpecialPowers.spawn(tab.linkedBrowser, [], function () {
    200    content.postMessage("fingerprinting", "*");
    201  });
    202  await promise;
    203 
    204  await openProtectionsPanel();
    205 
    206  let categoryItem = document.getElementById(
    207    "protections-popup-category-fingerprinters"
    208  );
    209 
    210  // Explicitly waiting for the category item becoming visible.
    211  await TestUtils.waitForCondition(() => {
    212    return BrowserTestUtils.isVisible(categoryItem);
    213  });
    214 
    215  ok(BrowserTestUtils.isVisible(categoryItem), "TP category item is visible");
    216 
    217  /* eslint-disable mozilla/no-arbitrary-setTimeout */
    218  // We have to wait until the ContentBlockingLog gets updated in the content.
    219  // Unfortunately, we need to use the setTimeout here since we don't have an
    220  // easy to know whether the log is updated in the content. This should be
    221  // removed after the log been removed in the content (Bug 1599046).
    222  await new Promise(resolve => {
    223    setTimeout(resolve, 500);
    224  });
    225  /* eslint-enable mozilla/no-arbitrary-setTimeout */
    226 
    227  let subview = document.getElementById("protections-popup-fingerprintersView");
    228  let viewShown = BrowserTestUtils.waitForEvent(subview, "ViewShown");
    229  categoryItem.click();
    230  await viewShown;
    231 
    232  let trackersViewShimHint = document.getElementById(
    233    "protections-popup-fingerprintersView-shim-allow-hint"
    234  );
    235  ok(trackersViewShimHint.hidden, "Shim hint is hidden");
    236 
    237  let listItems = subview.querySelectorAll(".protections-popup-list-item");
    238  is(listItems.length, 1, "We have 1 item in the list");
    239  let listItem = listItems[0];
    240  ok(BrowserTestUtils.isVisible(listItem), "List item is visible");
    241  is(
    242    listItem.querySelector("label").value,
    243    "https://fingerprinting.example.com",
    244    "Has the correct host"
    245  );
    246  is(
    247    listItem.classList.contains("allowed"),
    248    hasException,
    249    "Indicates the fingerprinter was blocked or allowed"
    250  );
    251 
    252  let mainView = document.getElementById("protections-popup-mainView");
    253  viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
    254  let backButton = subview.querySelector(".subviewbutton-back");
    255  backButton.click();
    256  await viewShown;
    257 
    258  ok(true, "Main view was shown");
    259 
    260  if (hasException) {
    261    let loaded = BrowserTestUtils.browserLoaded(
    262      tab.linkedBrowser,
    263      false,
    264      TRACKING_PAGE
    265    );
    266    gProtectionsHandler.enableForCurrentPage();
    267    await loaded;
    268  }
    269 
    270  let loads = hasException ? 3 : 1;
    271  testTelemetry(loads, 1, hasException);
    272 
    273  BrowserTestUtils.removeTab(tab);
    274 }
    275 
    276 function testTelemetry(pagesVisited, pagesWithBlockableContent, hasException) {
    277  let results = fpHistogram.snapshot();
    278  Assert.equal(
    279    results.values[0],
    280    pagesVisited,
    281    "The correct number of page loads have been recorded"
    282  );
    283  let expectedValue = hasException ? 2 : 1;
    284  Assert.equal(
    285    results.values[expectedValue],
    286    pagesWithBlockableContent,
    287    "The correct number of fingerprinters have been recorded as blocked or allowed."
    288  );
    289 }
    290 
    291 add_task(async function test() {
    292  Services.prefs.setBoolPref(FP_PROTECTION_PREF, true);
    293 
    294  await testIdentityState(false);
    295  await testIdentityState(true);
    296 
    297  await testSubview(false);
    298  await testSubview(true);
    299 
    300  await testCategoryItem();
    301 
    302  Services.prefs.clearUserPref(FP_PROTECTION_PREF);
    303 });