summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/bouncetrackingprotection/test/browser/browser_bouncetracking_popup.js
blob: 9e6fa8caf1942c6f4782ec78263650b6b99acb01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/* Any copyright is dedicated to the Public Domain.
   https://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

let bounceTrackingProtection;

add_setup(async function () {
  await SpecialPowers.pushPrefEnv({
    set: [
      ["privacy.bounceTrackingProtection.requireStatefulBounces", true],
      ["privacy.bounceTrackingProtection.bounceTrackingGracePeriodSec", 0],
    ],
  });
  bounceTrackingProtection = Cc[
    "@mozilla.org/bounce-tracking-protection;1"
  ].getService(Ci.nsIBounceTrackingProtection);
});

async function runTest(spawnWindowType) {
  if (!spawnWindowType || !["newTab", "popup"].includes(spawnWindowType)) {
    throw new Error(`Invalid option '${spawnWindowType}' for spawnWindowType`);
  }

  Assert.equal(
    bounceTrackingProtection.testGetBounceTrackerCandidateHosts({}).length,
    0,
    "No bounce tracker hosts initially."
  );
  Assert.equal(
    bounceTrackingProtection.testGetUserActivationHosts({}).length,
    0,
    "No user activation hosts initially."
  );

  // Spawn a tab with A, the start of the bounce chain.
  await BrowserTestUtils.withNewTab(
    getBaseUrl(ORIGIN_A) + "file_start.html",
    async browser => {
      // The destination site C to navigate to after the bounce.
      let finalURL = new URL(getBaseUrl(ORIGIN_B) + "file_start.html");
      // The middle hop in the bounce chain B that redirects to finalURL C.
      let bounceURL = getBounceURL({
        bounceType: "client",
        targetURL: finalURL,
        setState: "cookie-client",
      });

      // Register a promise for the new popup window. This resolves once the popup
      // has opened and the final url (C) has been loaded.
      let openPromise;

      if (spawnWindowType == "newTab") {
        openPromise = BrowserTestUtils.waitForNewTab(gBrowser, finalURL.href);
      } else {
        openPromise = BrowserTestUtils.waitForNewWindow({ url: finalURL.href });
      }

      // Navigate through the bounce chain by opening a popup to the bounce URL.
      await navigateLinkClick(browser, bounceURL, {
        spawnWindow: spawnWindowType,
      });

      let tabOrWindow = await openPromise;

      let tabOrWindowBrowser;
      if (spawnWindowType == "newTab") {
        tabOrWindowBrowser = tabOrWindow.linkedBrowser;
      } else {
        tabOrWindowBrowser = tabOrWindow.gBrowser.selectedBrowser;
      }

      let promiseRecordBounces = waitForRecordBounces(tabOrWindowBrowser);

      // Navigate again with user gesture which triggers
      // BounceTrackingProtection::RecordStatefulBounces. We could rely on the
      // timeout (mClientBounceDetectionTimeout) here but that can cause races
      // in debug where the load is quite slow.
      await navigateLinkClick(
        tabOrWindowBrowser,
        new URL(getBaseUrl(ORIGIN_C) + "file_start.html")
      );

      info("Wait for bounce trackers to be recorded.");
      await promiseRecordBounces;

      // Cleanup popup or tab.
      if (spawnWindowType == "newTab") {
        await BrowserTestUtils.removeTab(tabOrWindow);
      } else {
        await BrowserTestUtils.closeWindow(tabOrWindow);
      }
    }
  );

  // Check that the bounce tracker was detected.
  Assert.deepEqual(
    bounceTrackingProtection
      .testGetBounceTrackerCandidateHosts({})
      .map(entry => entry.siteHost),
    [SITE_TRACKER],
    "Bounce tracker in popup detected."
  );

  // Cleanup.
  bounceTrackingProtection.clearAll();
  await SiteDataTestUtils.clear();
}

/**
 * Tests that bounce trackers which use popups as the first hop in the bounce
 * chain can not bypass detection.
 *
 * A -> popup -> B -> C
 *
 * A opens a popup and loads B in it. B is the tracker that performs a
 * short-lived redirect and C is the final destination.
 */

add_task(async function test_popup() {
  await runTest("popup");
});

add_task(async function test_new_tab() {
  await runTest("newTab");
});