From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../browser_canvas_fingerprinting_resistance.js | 383 +++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js (limited to 'browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js') diff --git a/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js b/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js new file mode 100644 index 0000000000..dbb2d1ea32 --- /dev/null +++ b/browser/base/content/test/permissions/browser_canvas_fingerprinting_resistance.js @@ -0,0 +1,383 @@ +/** + * When "privacy.resistFingerprinting" is set to true, user permission is + * required for canvas data extraction. + * This tests whether the site permission prompt for canvas data extraction + * works properly. + * When "privacy.resistFingerprinting.randomDataOnCanvasExtract" is true, + * canvas data extraction results in random data, and when it is false, canvas + * data extraction results in all-white data. + */ +"use strict"; + +const kUrl = "https://example.com/"; +const kPrincipal = Services.scriptSecurityManager.createContentPrincipal( + Services.io.newURI(kUrl), + {} +); +const kPermission = "canvas"; + +function initTab() { + let contentWindow = content.wrappedJSObject; + + let drawCanvas = (fillStyle, id) => { + let contentDocument = contentWindow.document; + let width = 64, + height = 64; + let canvas = contentDocument.createElement("canvas"); + if (id) { + canvas.setAttribute("id", id); + } + canvas.setAttribute("width", width); + canvas.setAttribute("height", height); + contentDocument.body.appendChild(canvas); + + let context = canvas.getContext("2d"); + context.fillStyle = fillStyle; + context.fillRect(0, 0, width, height); + + if (id) { + let button = contentDocument.createElement("button"); + button.addEventListener("click", function () { + canvas.toDataURL(); + }); + button.setAttribute("id", "clickme"); + button.innerHTML = "Click Me!"; + contentDocument.body.appendChild(button); + } + + return canvas; + }; + + let placeholder = drawCanvas("white"); + contentWindow.kPlaceholderData = placeholder.toDataURL(); + let canvas = drawCanvas("cyan", "canvas-id-canvas"); + contentWindow.kPlacedData = canvas.toDataURL(); + is( + canvas.toDataURL(), + contentWindow.kPlacedData, + "privacy.resistFingerprinting = false, canvas data == placed data" + ); + isnot( + canvas.toDataURL(), + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = false, canvas data != placeholder data" + ); +} + +function enableResistFingerprinting( + randomDataOnCanvasExtract, + autoDeclineNoInput +) { + return SpecialPowers.pushPrefEnv({ + set: [ + ["privacy.resistFingerprinting", true], + [ + "privacy.resistFingerprinting.randomDataOnCanvasExtract", + randomDataOnCanvasExtract, + ], + [ + "privacy.resistFingerprinting.autoDeclineNoUserInputCanvasPrompts", + autoDeclineNoInput, + ], + ], + }); +} + +function promisePopupShown() { + return BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown"); +} + +function promisePopupHidden() { + return BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden"); +} + +function extractCanvasData(randomDataOnCanvasExtract, grantPermission) { + let contentWindow = content.wrappedJSObject; + let canvas = contentWindow.document.getElementById("canvas-id-canvas"); + let canvasData = canvas.toDataURL(); + if (grantPermission) { + is( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, permission granted, canvas data == placed data" + ); + if (!randomDataOnCanvasExtract) { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission granted, canvas data != placeholderdata" + ); + } + } else if (grantPermission === false) { + isnot( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, permission denied, canvas data != placed data" + ); + if (!randomDataOnCanvasExtract) { + is( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission denied, canvas data == placeholderdata" + ); + } else { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = true, permission denied, canvas data != placeholderdata" + ); + } + } else { + isnot( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, requesting permission, canvas data != placed data" + ); + if (!randomDataOnCanvasExtract) { + is( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, requesting permission, canvas data == placeholderdata" + ); + } else { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = true, requesting permission, canvas data != placeholderdata" + ); + } + } +} + +function triggerCommand(button) { + let notifications = PopupNotifications.panel.children; + let notification = notifications[0]; + EventUtils.synthesizeMouseAtCenter(notification[button], {}); +} + +function triggerMainCommand() { + triggerCommand("button"); +} + +function triggerSecondaryCommand() { + triggerCommand("secondaryButton"); +} + +function testPermission() { + return Services.perms.testPermissionFromPrincipal(kPrincipal, kPermission); +} + +async function withNewTabNoInput( + randomDataOnCanvasExtract, + grantPermission, + browser +) { + await SpecialPowers.spawn(browser, [], initTab); + await enableResistFingerprinting(randomDataOnCanvasExtract, false); + let popupShown = promisePopupShown(); + await SpecialPowers.spawn( + browser, + [randomDataOnCanvasExtract], + extractCanvasData + ); + await popupShown; + let popupHidden = promisePopupHidden(); + if (grantPermission) { + triggerMainCommand(); + await popupHidden; + is(testPermission(), Services.perms.ALLOW_ACTION, "permission granted"); + } else { + triggerSecondaryCommand(); + await popupHidden; + is(testPermission(), Services.perms.DENY_ACTION, "permission denied"); + } + await SpecialPowers.spawn( + browser, + [randomDataOnCanvasExtract, grantPermission], + extractCanvasData + ); + await SpecialPowers.popPrefEnv(); +} + +async function doTestNoInput(randomDataOnCanvasExtract, grantPermission) { + await BrowserTestUtils.withNewTab( + kUrl, + withNewTabNoInput.bind(null, randomDataOnCanvasExtract, grantPermission) + ); + Services.perms.removeFromPrincipal(kPrincipal, kPermission); +} + +// With auto-declining disabled (not the default) +// Tests clicking "Don't Allow" button of the permission prompt. +add_task(doTestNoInput.bind(null, true, false)); +add_task(doTestNoInput.bind(null, false, false)); + +// Tests clicking "Allow" button of the permission prompt. +add_task(doTestNoInput.bind(null, true, true)); +add_task(doTestNoInput.bind(null, false, true)); + +async function withNewTabAutoBlockNoInput(randomDataOnCanvasExtract, browser) { + await SpecialPowers.spawn(browser, [], initTab); + await enableResistFingerprinting(randomDataOnCanvasExtract, true); + + let noShowHandler = () => { + ok(false, "The popup notification should not show in this case."); + }; + PopupNotifications.panel.addEventListener("popupshown", noShowHandler, { + once: true, + }); + + let promisePopupObserver = TestUtils.topicObserved( + "PopupNotifications-updateNotShowing" + ); + + // Try to extract canvas data without user inputs. + await SpecialPowers.spawn( + browser, + [randomDataOnCanvasExtract], + extractCanvasData + ); + + await promisePopupObserver; + info("There should be no popup shown on the panel."); + + // Check that the icon of canvas permission is shown. + let canvasNotification = PopupNotifications.getNotification( + "canvas-permissions-prompt", + browser + ); + + is( + canvasNotification.anchorElement.getAttribute("showing"), + "true", + "The canvas permission icon is correctly shown." + ); + PopupNotifications.panel.removeEventListener("popupshown", noShowHandler); + + await SpecialPowers.popPrefEnv(); +} + +async function doTestAutoBlockNoInput(randomDataOnCanvasExtract) { + await BrowserTestUtils.withNewTab( + kUrl, + withNewTabAutoBlockNoInput.bind(null, randomDataOnCanvasExtract) + ); +} + +add_task(doTestAutoBlockNoInput.bind(null, true)); +add_task(doTestAutoBlockNoInput.bind(null, false)); + +function extractCanvasDataUserInput( + randomDataOnCanvasExtract, + grantPermission +) { + let contentWindow = content.wrappedJSObject; + let canvas = contentWindow.document.getElementById("canvas-id-canvas"); + let canvasData = canvas.toDataURL(); + if (grantPermission) { + is( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, permission granted, canvas data == placed data" + ); + if (!randomDataOnCanvasExtract) { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission granted, canvas data != placeholderdata" + ); + } + } else if (grantPermission === false) { + isnot( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, permission denied, canvas data != placed data" + ); + if (!randomDataOnCanvasExtract) { + is( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, permission denied, canvas data == placeholderdata" + ); + } else { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = true, permission denied, canvas data != placeholderdata" + ); + } + } else { + isnot( + canvasData, + contentWindow.kPlacedData, + "privacy.resistFingerprinting = true, requesting permission, canvas data != placed data" + ); + if (!randomDataOnCanvasExtract) { + is( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = false, requesting permission, canvas data == placeholderdata" + ); + } else { + isnot( + canvasData, + contentWindow.kPlaceholderData, + "privacy.resistFingerprinting = true and randomDataOnCanvasExtract = true, requesting permission, canvas data != placeholderdata" + ); + } + } +} + +async function withNewTabInput( + randomDataOnCanvasExtract, + grantPermission, + browser +) { + await SpecialPowers.spawn(browser, [], initTab); + await enableResistFingerprinting(randomDataOnCanvasExtract, true); + let popupShown = promisePopupShown(); + await SpecialPowers.spawn(browser, [], function (host) { + E10SUtils.wrapHandlingUserInput(content, true, function () { + var button = content.document.getElementById("clickme"); + button.click(); + }); + }); + await popupShown; + let popupHidden = promisePopupHidden(); + if (grantPermission) { + triggerMainCommand(); + await popupHidden; + is(testPermission(), Services.perms.ALLOW_ACTION, "permission granted"); + } else { + triggerSecondaryCommand(); + await popupHidden; + is(testPermission(), Services.perms.DENY_ACTION, "permission denied"); + } + await SpecialPowers.spawn( + browser, + [randomDataOnCanvasExtract, grantPermission], + extractCanvasDataUserInput + ); + await SpecialPowers.popPrefEnv(); +} + +async function doTestInput( + randomDataOnCanvasExtract, + grantPermission, + autoDeclineNoInput +) { + await BrowserTestUtils.withNewTab( + kUrl, + withNewTabInput.bind(null, randomDataOnCanvasExtract, grantPermission) + ); + Services.perms.removeFromPrincipal(kPrincipal, kPermission); +} + +// With auto-declining enabled (the default) +// Tests clicking "Don't Allow" button of the permission prompt. +add_task(doTestInput.bind(null, true, false)); +add_task(doTestInput.bind(null, false, false)); + +// Tests clicking "Allow" button of the permission prompt. +add_task(doTestInput.bind(null, true, true)); +add_task(doTestInput.bind(null, false, true)); -- cgit v1.2.3