summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_trackingprotection_errors.js
blob: c2d91fcb3bc3b2b0ef6db139ec9c75f868e128a8 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

// Load a page with tracking elements that get blocked and make sure that a
// 'learn more' link shows up in the webconsole.

"use strict";
requestLongerTimeout(2);

const TEST_PATH = "browser/devtools/client/webconsole/test/browser/";
const TEST_FILE = TEST_PATH + "test-trackingprotection-securityerrors.html";
const TEST_FILE_THIRD_PARTY_ONLY =
  TEST_PATH + "test-trackingprotection-securityerrors-thirdpartyonly.html";
const TEST_URI = "https://example.com/" + TEST_FILE;
const TEST_URI_THIRD_PARTY_ONLY =
  "https://example.com/" + TEST_FILE_THIRD_PARTY_ONLY;
const TRACKER_URL = "https://tracking.example.org/";
const THIRD_PARTY_URL = "https://example.org/";
const BLOCKED_URL = `\u201c${
  TRACKER_URL + TEST_PATH + "cookieSetter.html"
}\u201d`;
const PARTITIONED_URL = `\u201c${
  THIRD_PARTY_URL + TEST_PATH
}cookieSetter.html\u201d`;

const COOKIE_BEHAVIOR_PREF = "network.cookie.cookieBehavior";
const COOKIE_BEHAVIORS = {
  // reject all third-party cookies
  REJECT_FOREIGN: 1,
  // reject all cookies
  REJECT: 2,
  // reject third-party cookies unless the eTLD already has at least one cookie
  LIMIT_FOREIGN: 3,
  // reject trackers
  REJECT_TRACKER: 4,
  // dFPI - partitioned access to third-party cookies
  PARTITION_FOREIGN: 5,
};

const { UrlClassifierTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/UrlClassifierTestUtils.sys.mjs"
);

registerCleanupFunction(async function () {
  UrlClassifierTestUtils.cleanupTestTrackers();

  await new Promise(resolve => {
    Services.clearData.deleteData(Ci.nsIClearDataService.CLEAR_ALL, value =>
      resolve()
    );
  });
});

pushPref("devtools.webconsole.groupWarningMessages", false);

add_task(async function testContentBlockingMessage() {
  await UrlClassifierTestUtils.addTestTrackers();

  await pushPref("privacy.trackingprotection.enabled", true);
  const hud = await openNewTabAndConsole(TRACKER_URL + TEST_FILE);

  info("Test content blocking message");
  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `The resource at \u201chttps://tracking.example.com/\u201d was blocked because ` +
        `content blocking is enabled`
    )
  );

  await testLearnMoreClickOpenNewTab(
    message,
    "https://developer.mozilla.org/Firefox/Privacy/Tracking_Protection" +
      DOCS_GA_PARAMS
  );
});

add_task(async function testForeignCookieBlockedMessage() {
  info("Test foreign cookie blocked message");
  // Bug 1518138: GC heuristics are broken for this test, so that the test
  // ends up running out of memory. Try to work-around the problem by GCing
  // before the test begins.
  Cu.forceShrinkingGC();
  // We change the pref and open a new window to ensure it will be taken into account.
  await pushPref(COOKIE_BEHAVIOR_PREF, COOKIE_BEHAVIORS.REJECT_FOREIGN);
  const { hud, win } = await openNewWindowAndConsole(TEST_URI);
  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `Request to access cookie or storage on ${BLOCKED_URL} was blocked because we are ` +
        `blocking all third-party storage access requests and content blocking is enabled`
    )
  );
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookieBlockedForeign")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();
});

add_task(async function testLimitForeignCookieBlockedMessage() {
  info("Test unvisited eTLD foreign cookies blocked message");
  // Bug 1518138: GC heuristics are broken for this test, so that the test
  // ends up running out of memory. Try to work-around the problem by GCing
  // before the test begins.
  Cu.forceShrinkingGC();
  // We change the pref and open a new window to ensure it will be taken into account.
  await pushPref(COOKIE_BEHAVIOR_PREF, COOKIE_BEHAVIORS.LIMIT_FOREIGN);
  const { hud, win } = await openNewWindowAndConsole(TEST_URI);

  const message = await waitFor(
    () =>
      findWarningMessage(
        hud,
        `Request to access cookie or storage on ${BLOCKED_URL} was blocked because we are ` +
          `blocking all third-party storage access requests and content blocking is enabled`
      ),
    "Wait for 'blocking all third-party storage access' message",
    100
  );
  ok(true, "Third-party storage access blocked message was displayed");

  info("Check that clicking on the Learn More link works as expected");
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookieBlockedForeign")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();
});

add_task(async function testAllCookieBlockedMessage() {
  info("Test all cookies blocked message");
  // We change the pref and open a new window to ensure it will be taken into account.
  await pushPref(COOKIE_BEHAVIOR_PREF, COOKIE_BEHAVIORS.REJECT);
  const { hud, win } = await openNewWindowAndConsole(TEST_URI);

  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `Request to access cookie or storage on ${BLOCKED_URL} was blocked because we are ` +
        `blocking all storage access requests`
    )
  );
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookieBlockedAll")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();
});

add_task(async function testTrackerCookieBlockedMessage() {
  info("Test tracker cookie blocked message");
  // We change the pref and open a new window to ensure it will be taken into account.
  await pushPref(COOKIE_BEHAVIOR_PREF, COOKIE_BEHAVIORS.REJECT_TRACKER);
  const { hud, win } = await openNewWindowAndConsole(TEST_URI);

  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `Request to access cookie or storage on ${BLOCKED_URL} was blocked because it came ` +
        `from a tracker and content blocking is enabled`
    )
  );
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookieBlockedTracker")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();
});

add_task(async function testForeignCookiePartitionedMessage() {
  info("Test tracker cookie blocked message");
  // We change the pref and open a new window to ensure it will be taken into account.
  await pushPref(COOKIE_BEHAVIOR_PREF, COOKIE_BEHAVIORS.PARTITION_FOREIGN);
  const { hud, win } = await openNewWindowAndConsole(TEST_URI_THIRD_PARTY_ONLY);

  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `Partitioned cookie or storage access was provided to ${PARTITIONED_URL} because it is ` +
        `loaded in the third-party context and dynamic state partitioning is enabled.`
    )
  );
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookiePartitionedForeign")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();
});

add_task(async function testCookieBlockedByPermissionMessage() {
  info("Test cookie blocked by permission message");
  // Turn off tracking protection and add a block permission on the URL.
  await pushPref("privacy.trackingprotection.enabled", false);
  const p =
    Services.scriptSecurityManager.createContentPrincipalFromOrigin(
      TRACKER_URL
    );
  Services.perms.addFromPrincipal(
    p,
    "cookie",
    Ci.nsIPermissionManager.DENY_ACTION
  );

  const { hud, win } = await openNewWindowAndConsole(TEST_URI);
  const message = await waitFor(() =>
    findWarningMessage(
      hud,
      `Request to access cookies or ` +
        `storage on ${BLOCKED_URL} was blocked because of custom cookie permission`
    )
  );
  await testLearnMoreClickOpenNewTab(
    message,
    getStorageErrorUrl("CookieBlockedByPermission")
  );
  // We explicitely destroy the toolbox in order to ensure waiting for its full destruction
  // and avoid leak / pending requests
  await hud.toolbox.destroy();
  win.close();

  // Remove the custom permission.
  Services.perms.removeFromPrincipal(p, "cookie");
});

function getStorageErrorUrl(category) {
  const BASE_STORAGE_ERROR_URL =
    "https://developer.mozilla.org/docs/Mozilla/Firefox/" +
    "Privacy/Storage_access_policy/Errors/";
  const STORAGE_ERROR_URL_PARAMS = new URLSearchParams({
    utm_source: "devtools",
    utm_medium: "firefox-cookie-errors",
    utm_campaign: "default",
  }).toString();
  return `${BASE_STORAGE_ERROR_URL}${category}?${STORAGE_ERROR_URL_PARAMS}`;
}

async function testLearnMoreClickOpenNewTab(message, expectedUrl) {
  info("Clicking on the Learn More link");

  const learnMoreLink = message.querySelector(".learn-more-link");
  const linkSimulation = await simulateLinkClick(learnMoreLink);
  checkLink({
    ...linkSimulation,
    expectedLink: expectedUrl,
    expectedTab: "tab",
  });
}

function checkLink({ link, where, expectedLink, expectedTab }) {
  is(link, expectedLink, `Clicking the provided link opens ${link}`);
  is(where, expectedTab, `Clicking the provided link opens in expected tab`);
}