// This test ensures that the URL decoration annotations service works as // expected, and also we successfully downgrade document.referrer to the // eTLD+1 URL when tracking identifiers controlled by this service are // present in the referrer URI. "use strict"; const { RemoteSettings } = ChromeUtils.importESModule( "resource://services-settings/remote-settings.sys.mjs" ); const { Preferences } = ChromeUtils.importESModule( "resource://gre/modules/Preferences.sys.mjs" ); const APS_PREF = "privacy.partition.always_partition_third_party_non_cookie_storage"; const COLLECTION_NAME = "anti-tracking-url-decoration"; const PREF_NAME = "privacy.restrict3rdpartystorage.url_decorations"; const TOKEN_1 = "fooBar"; const TOKEN_2 = "foobaz"; const TOKEN_3 = "fooqux"; const TOKEN_4 = "bazqux"; const token_1 = TOKEN_1.toLowerCase(); const DOMAIN = TEST_DOMAIN_3; const SUB_DOMAIN = "https://sub1.xn--hxajbheg2az3al.xn--jxalpdlp/"; const TOP_PAGE_WITHOUT_TRACKING_IDENTIFIER = SUB_DOMAIN + TEST_PATH + "page.html"; const TOP_PAGE_WITH_TRACKING_IDENTIFIER = TOP_PAGE_WITHOUT_TRACKING_IDENTIFIER + "?" + TOKEN_1 + "=123"; add_task(async _ => { let uds = Cc["@mozilla.org/tracking-url-decoration-service;1"].getService( Ci.nsIURLDecorationAnnotationsService ); let records = [ { id: "1", last_modified: 1000000000000001, schema: Date.now(), token: TOKEN_1, }, ]; // Add some initial data async function emitSync() { await RemoteSettings(COLLECTION_NAME).emit("sync", { data: { current: records }, }); } let db = RemoteSettings(COLLECTION_NAME).db; await db.importChanges({}, Date.now(), [records[0]]); await emitSync(); await uds.ensureUpdated(); let list = Preferences.get(PREF_NAME).split(" "); ok(list.includes(TOKEN_1), "Token must now be available in " + PREF_NAME); ok(Preferences.locked(PREF_NAME), PREF_NAME + " must be locked"); async function verifyList(array, not_array) { await emitSync(); await uds.ensureUpdated(); list = Preferences.get(PREF_NAME).split(" "); for (let token of array) { ok( list.includes(token), token + " must now be available in " + PREF_NAME ); } for (let token of not_array) { ok( !list.includes(token), token + " must not be available in " + PREF_NAME ); } ok(Preferences.locked(PREF_NAME), PREF_NAME + " must be locked"); } records.push( { id: "2", last_modified: 1000000000000002, schema: Date.now(), token: TOKEN_2, }, { id: "3", last_modified: 1000000000000003, schema: Date.now(), token: TOKEN_3, }, { id: "4", last_modified: 1000000000000005, schema: Date.now(), token: TOKEN_4, } ); await verifyList([TOKEN_1, TOKEN_2, TOKEN_3, TOKEN_4], []); records.pop(); await verifyList([TOKEN_1, TOKEN_2, TOKEN_3], [TOKEN_4]); is( Services.eTLD.getBaseDomain(Services.io.newURI(DOMAIN)), Services.eTLD.getBaseDomain(Services.io.newURI(SUB_DOMAIN)), "Sanity check" ); registerCleanupFunction(async _ => { records = []; await db.clear(); await emitSync(); }); }); AntiTracking._createTask({ name: "Test that we do not downgrade document.referrer when it does not contain a tracking identifier", cookieBehavior: BEHAVIOR_REJECT_TRACKER, blockingByContentBlockingRTUI: true, allowList: false, callback: async _ => { let ref = new URL(document.referrer); is( ref.hostname, "sub1.xn--hxajbheg2az3al.xn--jxalpdlp", "Hostname shouldn't be stripped" ); ok(ref.pathname.length > 1, "Path must not be trimmed"); // eslint-disable-next-line no-unused-vars for (let entry of ref.searchParams.entries()) { ok(false, "No query parameters should be found"); } }, extraPrefs: [ ["network.http.referer.defaultPolicy", 3], // Ensure we don't downgrade because of the default policy. ["network.http.referer.defaultPolicy.trackers", 3], [APS_PREF, false], ], expectedBlockingNotifications: 0, runInPrivateWindow: false, iframeSandbox: null, accessRemoval: null, callbackAfterRemoval: null, topPage: TOP_PAGE_WITHOUT_TRACKING_IDENTIFIER, }); AntiTracking._createTask({ name: "Test that we do not downgrade document.referrer when it does not contain a tracking identifier even though it gets downgraded to origin only due to the default referrer policy", cookieBehavior: BEHAVIOR_REJECT_TRACKER, blockingByContentBlockingRTUI: true, allowList: false, callback: async _ => { let ref = new URL(document.referrer); is( ref.hostname, "sub1.xn--hxajbheg2az3al.xn--jxalpdlp", "Hostname shouldn't be stripped" ); is(ref.pathname.length, 1, "Path must be trimmed"); // eslint-disable-next-line no-unused-vars for (let entry of ref.searchParams.entries()) { ok(false, "No query parameters should be found"); } }, extraPrefs: [ ["network.http.referer.defaultPolicy.trackers", 2], [APS_PREF, false], ], expectedBlockingNotifications: 0, runInPrivateWindow: false, iframeSandbox: null, accessRemoval: null, callbackAfterRemoval: null, topPage: TOP_PAGE_WITHOUT_TRACKING_IDENTIFIER, }); AntiTracking._createTask({ name: "Test that we downgrade document.referrer when it contains a tracking identifier", cookieBehavior: BEHAVIOR_REJECT_TRACKER, blockingByContentBlockingRTUI: true, allowList: false, callback: async _ => { let ref = new URL(document.referrer); is( ref.hostname, "xn--hxajbheg2az3al.xn--jxalpdlp", "Hostname should be stripped" ); is(ref.pathname.length, 1, "Path must be trimmed"); // eslint-disable-next-line no-unused-vars for (let entry of ref.searchParams.entries()) { ok(false, "No query parameters should be found"); } }, extraPrefs: [ ["network.http.referer.defaultPolicy", 3], // Ensure we don't downgrade because of the default policy. ["network.http.referer.defaultPolicy.trackers", 3], [APS_PREF, false], ], expectedBlockingNotifications: 0, runInPrivateWindow: false, iframeSandbox: null, accessRemoval: null, callbackAfterRemoval: null, topPage: TOP_PAGE_WITH_TRACKING_IDENTIFIER, }); AntiTracking._createTask({ name: "Test that we don't downgrade document.referrer when it contains a tracking identifier if it gets downgraded to origin only due to the default referrer policy because the tracking identifier wouldn't be present in the referrer any more", cookieBehavior: BEHAVIOR_REJECT_TRACKER, blockingByContentBlockingRTUI: true, allowList: false, callback: async _ => { let ref = new URL(document.referrer); is( ref.hostname, "sub1.xn--hxajbheg2az3al.xn--jxalpdlp", "Hostname shouldn't be stripped" ); is(ref.pathname.length, 1, "Path must be trimmed"); // eslint-disable-next-line no-unused-vars for (let entry of ref.searchParams.entries()) { ok(false, "No query parameters should be found"); } }, extraPrefs: [ ["network.http.referer.defaultPolicy.trackers", 2], [APS_PREF, false], ], expectedBlockingNotifications: 0, runInPrivateWindow: false, iframeSandbox: null, accessRemoval: null, callbackAfterRemoval: null, topPage: TOP_PAGE_WITH_TRACKING_IDENTIFIER, }); add_task(async _ => { await new Promise(resolve => { Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value => resolve() ); }); });