/* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { RemoteSettings } = ChromeUtils.importESModule( "resource://services-settings/remote-settings.sys.mjs" ); XPCOMUtils.defineLazyServiceGetter( this, "urlQueryStrippingListService", "@mozilla.org/query-stripping-list-service;1", "nsIURLQueryStrippingListService" ); const COLLECTION_NAME = "query-stripping"; const TEST_URI = TEST_DOMAIN + TEST_PATH + "empty.html"; const TEST_THIRD_PARTY_URI = TEST_DOMAIN_2 + TEST_PATH + "empty.html"; // The Update Event here is used to listen the observer from the // URLQueryStrippingListService. We need to use the event here so that the same // observer can be called multiple times. class UpdateEvent extends EventTarget {} // The Observer that is registered needs to implement onQueryStrippingListUpdate // like a nsIURLQueryStrippingListObserver does class ListObserver { updateEvent = new UpdateEvent(); onQueryStrippingListUpdate(stripList, allowList) { let event = new CustomEvent("update", { detail: { stripList, allowList } }); this.updateEvent.dispatchEvent(event); } } function waitForEvent(element, eventName) { return BrowserTestUtils.waitForEvent(element, eventName).then(e => e.detail); } async function verifyQueryString(browser, expected) { await SpecialPowers.spawn(browser, [expected], expected => { // Strip the first question mark. let search = content.location.search.slice(1); is(search, expected, "The query string is correct."); }); } async function check(query, expected) { // Open a tab with the query string. let testURI = TEST_URI + "?" + query; // Test for stripping in parent process. await BrowserTestUtils.withNewTab(testURI, async browser => { // Verify if the query string is expected in the new tab. await verifyQueryString(browser, expected); }); testURI = TEST_URI + "?" + query; let expectedURI; if (expected != "") { expectedURI = TEST_URI + "?" + expected; } else { expectedURI = TEST_URI; } // Test for stripping in content processes. This will first open a third-party // page and create a link to the test uri. And then, click the link to // navigate the page, which will trigger the stripping in content processes. await BrowserTestUtils.withNewTab(TEST_THIRD_PARTY_URI, async browser => { // Create the promise to wait for the location change. let locationChangePromise = BrowserTestUtils.waitForLocationChange( gBrowser, expectedURI ); // Create a link and click it to navigate. await SpecialPowers.spawn(browser, [testURI], async uri => { let link = content.document.createElement("a"); link.setAttribute("href", uri); link.textContent = "Link"; content.document.body.appendChild(link); link.click(); }); await locationChangePromise; // Verify the query string in the content window. await verifyQueryString(browser, expected); }); } registerCleanupFunction(() => { Cc["@mozilla.org/query-stripping-list-service;1"] .getService(Ci.nsIURLQueryStrippingListService) .clearLists(); }); add_task(async function testPrefSettings() { // Enable query stripping and clear the prefs at the beginning. await SpecialPowers.pushPrefEnv({ set: [ ["privacy.query_stripping.enabled", true], ["privacy.query_stripping.strip_list", ""], ["privacy.query_stripping.allow_list", ""], ["privacy.query_stripping.testing", true], ], }); // Test if the observer been called when adding to the service. let obs = new ListObserver(); let promise = waitForEvent(obs.updateEvent, "update"); urlQueryStrippingListService.registerAndRunObserver(obs); let lists = await promise; is(lists.stripList, "", "No strip list at the beginning."); is(lists.allowList, "", "No allow list at the beginning."); // Verify that no query stripping happens. await check("pref_query1=123", "pref_query1=123"); await check("pref_query2=456", "pref_query2=456"); // Set pref for strip list promise = waitForEvent(obs.updateEvent, "update"); await SpecialPowers.pushPrefEnv({ set: [["privacy.query_stripping.strip_list", "pref_query1 pref_query2"]], }); lists = await promise; is( lists.stripList, "pref_query1 pref_query2", "There should be strip list entries." ); is(lists.allowList, "", "There should be no allow list entries."); // The query string should be stripped. await check("pref_query1=123", ""); await check("pref_query2=456", ""); // Set the pref for allow list. promise = waitForEvent(obs.updateEvent, "update"); await SpecialPowers.pushPrefEnv({ set: [["privacy.query_stripping.allow_list", "example.net"]], }); lists = await promise; is( lists.stripList, "pref_query1 pref_query2", "There should be strip list entires." ); is(lists.allowList, "example.net", "There should be one allow list entry."); // The query string shouldn't be stripped because this host is in allow list. await check("pref_query1=123", "pref_query1=123"); await check("pref_query2=123", "pref_query2=123"); urlQueryStrippingListService.unregisterObserver(obs); // Clear prefs. SpecialPowers.flushPrefEnv(); }); add_task(async function testRemoteSettings() { // Enable query stripping and clear the prefs at the beginning. await SpecialPowers.pushPrefEnv({ set: [ ["privacy.query_stripping.enabled", true], ["privacy.query_stripping.strip_list", ""], ["privacy.query_stripping.allow_list", ""], ["privacy.query_stripping.testing", true], ], }); // Add initial empty record. let db = RemoteSettings(COLLECTION_NAME).db; await db.importChanges({}, Date.now(), []); // Test if the observer been called when adding to the service. let obs = new ListObserver(); let promise = waitForEvent(obs.updateEvent, "update"); urlQueryStrippingListService.registerAndRunObserver(obs); let lists = await promise; is(lists.stripList, "", "No strip list at the beginning."); is(lists.allowList, "", "No allow list at the beginning."); // Verify that no query stripping happens. await check("remote_query1=123", "remote_query1=123"); await check("remote_query2=456", "remote_query2=456"); // Set record for strip list. promise = waitForEvent(obs.updateEvent, "update"); await RemoteSettings(COLLECTION_NAME).emit("sync", { data: { current: [ { id: "1", last_modified: 1000000000000001, stripList: ["remote_query1", "remote_query2"], allowList: [], }, ], }, }); lists = await promise; is( lists.stripList, "remote_query1 remote_query2", "There should be strip list entries." ); is(lists.allowList, "", "There should be no allow list entries."); // The query string should be stripped. await check("remote_query1=123", ""); await check("remote_query2=456", ""); // Set record for strip list and allow list. promise = waitForEvent(obs.updateEvent, "update"); await RemoteSettings(COLLECTION_NAME).emit("sync", { data: { current: [ { id: "2", last_modified: 1000000000000002, stripList: ["remote_query1", "remote_query2"], allowList: ["example.net"], }, ], }, }); lists = await promise; is( lists.stripList, "remote_query1 remote_query2", "There should be strip list entries." ); is(lists.allowList, "example.net", "There should be one allow list entry."); // The query string shouldn't be stripped because this host is in allow list. await check("remote_query1=123", "remote_query1=123"); await check("remote_query2=123", "remote_query2=123"); urlQueryStrippingListService.unregisterObserver(obs); // Clear the remote settings. await db.clear(); });