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 });