summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js')
-rw-r--r--toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js617
1 files changed, 617 insertions, 0 deletions
diff --git a/toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js b/toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js
new file mode 100644
index 0000000000..9594fdf270
--- /dev/null
+++ b/toolkit/components/antitracking/test/browser/browser_storageAccessPrivilegeAPI.js
@@ -0,0 +1,617 @@
+//
+// Bug 1724376 - Tests for the privilege requestStorageAccessForOrigin API.
+//
+
+/* import-globals-from storageAccessAPIHelpers.js */
+
+"use strict";
+
+const TEST_ANOTHER_TRACKER_DOMAIN = "https://itisatracker.org/";
+const TEST_ANOTHER_TRACKER_PAGE =
+ TEST_ANOTHER_TRACKER_DOMAIN + TEST_PATH + "3rdParty.html";
+const TEST_ANOTHER_4TH_PARTY_DOMAIN = "https://test1.example.org/";
+const TEST_ANOTHER_4TH_PARTY_PAGE =
+ TEST_ANOTHER_4TH_PARTY_DOMAIN + TEST_PATH + "3rdParty.html";
+
+// Insert an iframe with the given id into the content.
+async function insertSubFrame(browser, url, id) {
+ return SpecialPowers.spawn(browser, [url, id], async (url, id) => {
+ let ifr = content.document.createElement("iframe");
+ ifr.setAttribute("id", id);
+
+ let loaded = ContentTaskUtils.waitForEvent(ifr, "load", false);
+ content.document.body.appendChild(ifr);
+ ifr.src = url;
+ await loaded;
+ });
+}
+
+// Run the given script in the iframe with the given id.
+function runScriptInSubFrame(browser, id, script) {
+ return SpecialPowers.spawn(
+ browser,
+ [{ callback: script.toString(), id }],
+ async obj => {
+ await new content.Promise(resolve => {
+ let ifr = content.document.getElementById(obj.id);
+
+ content.addEventListener("message", function msg(event) {
+ if (event.data.type == "finish") {
+ content.removeEventListener("message", msg);
+ resolve();
+ return;
+ }
+
+ if (event.data.type == "ok") {
+ ok(event.data.what, event.data.msg);
+ return;
+ }
+
+ if (event.data.type == "info") {
+ info(event.data.msg);
+ return;
+ }
+
+ ok(false, "Unknown message");
+ });
+
+ ifr.contentWindow.postMessage(obj.callback, "*");
+ });
+ }
+ );
+}
+
+function waitStoragePermission(trackingOrigin) {
+ return TestUtils.topicObserved("perm-changed", (aSubject, aData) => {
+ let permission = aSubject.QueryInterface(Ci.nsIPermission);
+ let uri = Services.io.newURI(TEST_DOMAIN);
+ return (
+ permission.type == `3rdPartyStorage^${trackingOrigin}` &&
+ permission.principal.equalsURI(uri)
+ );
+ });
+}
+
+function clearStoragePermission(trackingOrigin) {
+ return SpecialPowers.removePermission(
+ `3rdPartyStorage^${trackingOrigin}`,
+ TEST_TOP_PAGE
+ );
+}
+
+function triggerCommand(button) {
+ let notifications = PopupNotifications.panel.children;
+ let notification = notifications[0];
+ EventUtils.synthesizeMouseAtCenter(notification[button], {});
+}
+
+function triggerMainCommand() {
+ triggerCommand("button");
+}
+
+function triggerSecondaryCommand() {
+ triggerCommand("secondaryButton");
+}
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.storage_access.auto_grants", true],
+ ["dom.storage_access.auto_grants.delayed", false],
+ ["dom.storage_access.enabled", true],
+ ["dom.storage_access.prompt.testing", false],
+ ["privacy.trackingprotection.enabled", false],
+ ["privacy.trackingprotection.pbmode.enabled", false],
+ ["privacy.trackingprotection.annotate_channels", true],
+ // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default"
+ ["network.cookie.sameSite.laxByDefault", false],
+ ],
+ });
+
+ await UrlClassifierTestUtils.addTestTrackers();
+
+ registerCleanupFunction(() => {
+ SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault");
+ UrlClassifierTestUtils.cleanupTestTrackers();
+ });
+});
+
+add_task(async function test_api_only_available_in_privilege_scope() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ await SpecialPowers.spawn(browser, [], async _ => {
+ ok(
+ content.document.requestStorageAccessForOrigin,
+ "The privilege API is available in system privilege code."
+ );
+ });
+
+ // Open an iframe and check if the privilege is not available in content code.
+ await insertSubFrame(browser, TEST_3RD_PARTY_PAGE, "test");
+ await runScriptInSubFrame(browser, "test", async function check() {
+ ok(
+ !document.requestStorageAccessForOrigin,
+ "The privilege API is not available in content code."
+ );
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_privilege_api_with_reject_tracker() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "network.cookie.cookieBehavior",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ [
+ "network.cookie.cookieBehavior.pbmode",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ ],
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ await insertSubFrame(browser, TEST_3RD_PARTY_PAGE, "test");
+
+ // Verify that the third party tracker doesn't have storage access at
+ // beginning.
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "No cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "", "Setting cookie is blocked");
+ });
+
+ let storagePermissionPromise = waitStoragePermission(
+ "https://tracking.example.org"
+ );
+
+ // Verify if the prompt has been shown.
+ let shownPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Call the privilege API.
+ let callAPIPromise = SpecialPowers.spawn(browser, [], async _ => {
+ // The privilege API requires user activation. So, we set the user
+ // activation flag before we call the API.
+ content.document.notifyUserGestureActivation();
+
+ try {
+ await content.document.requestStorageAccessForOrigin(
+ "https://tracking.example.org/"
+ );
+ } catch (e) {
+ ok(false, "The API shouldn't throw.");
+ }
+
+ content.document.clearUserGestureActivation();
+ });
+
+ await shownPromise;
+
+ // Accept the prompt
+ triggerMainCommand();
+
+ await callAPIPromise;
+
+ // Verify if the storage access permission is set correctly.
+ await storagePermissionPromise;
+
+ // Verify if the existing third-party tracker iframe gains the storage
+ // access.
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await hasStorageAccessInitially();
+
+ is(document.cookie, "", "Still no cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "name=value", "Successfully set cookies.");
+ });
+
+ // Insert another third-party tracker iframe and check if it has storage access.
+ await insertSubFrame(browser, TEST_3RD_PARTY_PAGE, "test2");
+ await runScriptInSubFrame(browser, "test2", async _ => {
+ await hasStorageAccessInitially();
+
+ is(document.cookie, "name=value", "Some cookies for me");
+ });
+
+ // Insert another iframe with different third-party tracker and check it has
+ // no storage access.
+ await insertSubFrame(browser, TEST_ANOTHER_TRACKER_PAGE, "test3");
+ await runScriptInSubFrame(browser, "test3", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "No cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "", "Setting cookie is blocked for another tracker.");
+ });
+
+ await clearStoragePermission("https://tracking.example.org");
+ Services.cookies.removeAll();
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_privilege_api_with_dFPI() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ "network.cookie.cookieBehavior",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
+ ],
+ [
+ "network.cookie.cookieBehavior.pbmode",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN,
+ ],
+ ],
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ await insertSubFrame(browser, TEST_4TH_PARTY_PAGE_HTTPS, "test");
+
+ // Verify that the third-party context doesn't have storage access at
+ // beginning.
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "No cookies for me");
+ document.cookie = "name=partitioned";
+ is(
+ document.cookie,
+ "name=partitioned",
+ "Setting cookie in partitioned context."
+ );
+ });
+
+ let storagePermissionPromise = waitStoragePermission(
+ "https://not-tracking.example.com"
+ );
+
+ // Verify if the prompt has been shown.
+ let shownPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ // Call the privilege API.
+ let callAPIPromise = SpecialPowers.spawn(browser, [], async _ => {
+ // The privilege API requires a user gesture. So, we set the user handling
+ // flag before we call the API.
+ content.document.notifyUserGestureActivation();
+
+ try {
+ await content.document.requestStorageAccessForOrigin(
+ "https://not-tracking.example.com/"
+ );
+ } catch (e) {
+ ok(false, "The API shouldn't throw.");
+ }
+
+ content.document.clearUserGestureActivation();
+ });
+
+ await shownPromise;
+
+ // Accept the prompt
+ triggerMainCommand();
+
+ await callAPIPromise;
+
+ // Verify if the storage access permission is set correctly.
+ await storagePermissionPromise;
+
+ // Verify if the existing third-party iframe gains the storage access.
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await hasStorageAccessInitially();
+
+ is(document.cookie, "", "No unpartitioned cookies");
+ document.cookie = "name=unpartitioned";
+ is(document.cookie, "name=unpartitioned", "Successfully set cookies.");
+ });
+
+ // Insert another third-party content iframe and check if it has storage access.
+ await insertSubFrame(browser, TEST_4TH_PARTY_PAGE_HTTPS, "test2");
+ await runScriptInSubFrame(browser, "test2", async _ => {
+ await hasStorageAccessInitially();
+
+ is(
+ document.cookie,
+ "name=unpartitioned",
+ "Some cookies for unpartitioned context"
+ );
+ });
+
+ // Insert another iframe with different third-party content and check it has
+ // no storage access.
+ await insertSubFrame(browser, TEST_ANOTHER_4TH_PARTY_PAGE, "test3");
+ await runScriptInSubFrame(browser, "test3", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "No cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "name=value", "Setting cookie to partitioned context.");
+ });
+
+ await clearStoragePermission("https://not-tracking.example.com");
+ Services.cookies.removeAll();
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function test_prompt() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.storage_access.auto_grants", false],
+ [
+ "network.cookie.cookieBehavior",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ [
+ "network.cookie.cookieBehavior.pbmode",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ ],
+ });
+
+ for (const allow of [false, true]) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ // Verify if the prompt has been shown.
+ let shownPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ let hiddenPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphidden"
+ );
+
+ // Call the privilege API.
+ let callAPIPromise = SpecialPowers.spawn(browser, [allow], async allow => {
+ // The privilege API requires a user gesture. So, we set the user handling
+ // flag before we call the API.
+ content.document.notifyUserGestureActivation();
+ let isThrown = false;
+
+ try {
+ await content.document.requestStorageAccessForOrigin(
+ "https://tracking.example.org"
+ );
+ } catch (e) {
+ isThrown = true;
+ }
+
+ is(isThrown, !allow, `The API ${allow ? "shouldn't" : "should"} throw.`);
+
+ content.document.clearUserGestureActivation();
+ });
+
+ await shownPromise;
+
+ let notification = await TestUtils.waitForCondition(_ =>
+ PopupNotifications.getNotification("storage-access", browser)
+ );
+ ok(notification, "Should have gotten the notification");
+
+ // Click the popup button.
+ if (allow) {
+ triggerMainCommand();
+ } else {
+ triggerSecondaryCommand();
+ }
+
+ // Wait until the popup disappears.
+ await hiddenPromise;
+
+ // Wait until the API finishes.
+ await callAPIPromise;
+
+ await insertSubFrame(browser, TEST_3RD_PARTY_PAGE, "test");
+
+ if (allow) {
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await hasStorageAccessInitially();
+
+ is(document.cookie, "", "Still no cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "name=value", "Successfully set cookies.");
+ });
+ } else {
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "Still no cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "", "No cookie after setting.");
+ });
+ }
+
+ BrowserTestUtils.removeTab(tab);
+ }
+
+ await clearStoragePermission("https://tracking.example.org");
+ Services.cookies.removeAll();
+});
+
+// Tests that the priviledged rSA method should show a prompt when auto grants
+// are enabled, but we don't have user activation. When requiring user
+// activation, rSA should still reject.
+add_task(async function test_prompt_no_user_activation() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["dom.storage_access.auto_grants", true],
+ [
+ "network.cookie.cookieBehavior",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ [
+ "network.cookie.cookieBehavior.pbmode",
+ Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER,
+ ],
+ ],
+ });
+
+ for (let requireUserActivation of [false, true]) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ let shownPromise, hiddenPromise;
+
+ // Verify if the prompt has been shown.
+ if (!requireUserActivation) {
+ shownPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+
+ hiddenPromise = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popuphidden"
+ );
+ }
+
+ // Call the privilege API.
+ let callAPIPromise = SpecialPowers.spawn(
+ browser,
+ [requireUserActivation],
+ async requireUserActivation => {
+ let isThrown = false;
+
+ try {
+ await content.document.requestStorageAccessForOrigin(
+ "https://tracking.example.org",
+ requireUserActivation
+ );
+ } catch (e) {
+ isThrown = true;
+ }
+
+ is(
+ isThrown,
+ requireUserActivation,
+ `The API ${requireUserActivation ? "shouldn't" : "should"} throw.`
+ );
+ }
+ );
+
+ if (!requireUserActivation) {
+ await shownPromise;
+
+ let notification = await TestUtils.waitForCondition(_ =>
+ PopupNotifications.getNotification("storage-access", browser)
+ );
+ ok(notification, "Should have gotten the notification");
+
+ // Click the popup button.
+ triggerMainCommand();
+
+ // Wait until the popup disappears.
+ await hiddenPromise;
+ }
+
+ // Wait until the API finishes.
+ await callAPIPromise;
+
+ await insertSubFrame(browser, TEST_3RD_PARTY_PAGE, "test");
+
+ if (!requireUserActivation) {
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await hasStorageAccessInitially();
+
+ is(document.cookie, "", "Still no cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "name=value", "Successfully set cookies.");
+ });
+ } else {
+ await runScriptInSubFrame(browser, "test", async _ => {
+ await noStorageAccessInitially();
+
+ is(document.cookie, "", "Still no cookies for me");
+ document.cookie = "name=value";
+ is(document.cookie, "", "No cookie after setting.");
+ });
+ }
+
+ BrowserTestUtils.removeTab(tab);
+ await clearStoragePermission("https://tracking.example.org");
+ Services.cookies.removeAll();
+ }
+});
+
+add_task(async function test_invalid_input() {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ TEST_TOP_PAGE
+ );
+ let browser = tab.linkedBrowser;
+
+ await SpecialPowers.spawn(browser, [], async _ => {
+ let isThrown = false;
+ try {
+ await content.document.requestStorageAccessForOrigin(
+ "https://tracking.example.org"
+ );
+ } catch (e) {
+ isThrown = true;
+ }
+ ok(isThrown, "The API should throw without user gesture.");
+
+ content.document.notifyUserGestureActivation();
+ isThrown = false;
+ try {
+ await content.document.requestStorageAccessForOrigin();
+ } catch (e) {
+ isThrown = true;
+ }
+ ok(isThrown, "The API should throw with no input.");
+
+ content.document.notifyUserGestureActivation();
+ isThrown = false;
+ try {
+ await content.document.requestStorageAccessForOrigin("");
+ } catch (e) {
+ isThrown = true;
+ is(e.name, "NS_ERROR_MALFORMED_URI", "The input is not a valid url");
+ }
+ ok(isThrown, "The API should throw with empty string.");
+
+ content.document.notifyUserGestureActivation();
+ isThrown = false;
+ try {
+ await content.document.requestStorageAccessForOrigin("invalid url");
+ } catch (e) {
+ isThrown = true;
+ is(e.name, "NS_ERROR_MALFORMED_URI", "The input is not a valid url");
+ }
+ ok(isThrown, "The API should throw with invalid url.");
+
+ content.document.clearUserGestureActivation();
+ });
+
+ BrowserTestUtils.removeTab(tab);
+});