summaryrefslogtreecommitdiffstats
path: root/devtools/client/webconsole/test/browser/browser_webconsole_warning_group_content_blocking.js
blob: 849dcd394f439dd4bb4212dbd7fccb2eec3b4f02 (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
/* 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_FILE =
  "browser/devtools/client/webconsole/test/browser/test-warning-groups.html";
const TEST_URI = "https://example.com/" + TEST_FILE;

const TRACKER_URL = "https://tracking.example.com/";
const IMG_FILE =
  "browser/devtools/client/webconsole/test/browser/test-image.png";
const TRACKER_IMG = "https://tracking.example.org/" + IMG_FILE;

const CONTENT_BLOCKING_GROUP_LABEL =
  "The resource at “<URL>” was blocked because content blocking is enabled.";

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,
};

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

pushPref("privacy.trackingprotection.enabled", true);
pushPref("devtools.webconsole.groupWarningMessages", true);

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

add_task(cleanUp);

add_task(async function testContentBlockingMessage() {
  const { hud, tab, win } = await openNewWindowAndConsole(
    "https://tracking.example.org/" + TEST_FILE
  );
  const now = Date.now();

  info("Test content blocking message");
  const message =
    `The resource at \u201chttps://tracking.example.com/?1&${now}\u201d ` +
    `was blocked because content blocking is enabled`;
  const onContentBlockingWarningMessage = waitForMessageByType(
    hud,
    message,
    ".warn"
  );
  emitContentBlockingMessage(tab, `${TRACKER_URL}?1&${now}`);
  await onContentBlockingWarningMessage;

  ok(true, "The content blocking message was displayed");

  info(
    "Emit a new content blocking message to check that it causes a grouping"
  );
  const onContentBlockingWarningGroupMessage = waitForMessageByType(
    hud,
    CONTENT_BLOCKING_GROUP_LABEL,
    ".warn"
  );
  emitContentBlockingMessage(tab, `${TRACKER_URL}?2&${now}`);
  const { node } = await onContentBlockingWarningGroupMessage;
  is(
    node.querySelector(".warning-group-badge").textContent,
    "2",
    "The badge has the expected text"
  );

  await checkConsoleOutputForWarningGroup(hud, [
    `▶︎⚠ ${CONTENT_BLOCKING_GROUP_LABEL} 2`,
  ]);

  info("Open the group");
  node.querySelector(".arrow").click();
  await waitFor(() =>
    findWarningMessage(hud, "https://tracking.example.com/?1")
  );

  await checkConsoleOutputForWarningGroup(hud, [
    `▼︎⚠ ${CONTENT_BLOCKING_GROUP_LABEL} 2`,
    `| The resource at \u201chttps://tracking.example.com/?1&${now}\u201d was blocked`,
    `| The resource at \u201chttps://tracking.example.com/?2&${now}\u201d was blocked`,
  ]);
  await win.close();
});

add_task(async function testForeignCookieBlockedMessage() {
  info("Test foreign 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_FOREIGN);
  await testStorageAccessBlockedGrouping(
    "Request to access cookie or storage on " +
      "“<URL>” was blocked because we are blocking all third-party storage access " +
      "requests and content blocking is enabled."
  );
});

add_task(async function testLimitForeignCookieBlockedMessage() {
  info("Test unvisited eTLD foreign 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.LIMIT_FOREIGN);
  await testStorageAccessBlockedGrouping(
    "Request to access cookie or storage on " +
      "“<URL>” was blocked because we are blocking all third-party storage access " +
      "requests and content blocking is enabled."
  );
});

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);
  await testStorageAccessBlockedGrouping(
    "Request to access cookie or storage on " +
      "“<URL>” was blocked because we are blocking all storage access requests."
  );
});

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);
  await testStorageAccessBlockedGrouping(
    "Request to access cookie or storage on " +
      "“<URL>” was blocked because it came from a tracker and content blocking is " +
      "enabled."
  );
});

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(
    "https://tracking.example.org/"
  );
  Services.perms.addFromPrincipal(
    p,
    "cookie",
    Ci.nsIPermissionManager.DENY_ACTION
  );

  await testStorageAccessBlockedGrouping(
    "Request to access cookies or storage on " +
      "“<URL>” was blocked because of custom cookie permission."
  );

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

add_task(cleanUp);

/**
 * Test that storage access blocked messages are grouped by emitting 2 messages.
 *
 * @param {String} groupLabel: The warning group label that should be created.
 *                             It should contain "<URL>".
 */
async function testStorageAccessBlockedGrouping(groupLabel) {
  const { hud, win, tab } = await openNewWindowAndConsole(TEST_URI);
  const now = Date.now();

  await clearOutput(hud);

  // Bug 1763367 - Filter out message like:
  //  Cookie “name=value” has been rejected as third-party.
  // that appear in a random order.
  await setFilterState(hud, { text: "-has been rejected" });

  const getWarningMessage = url => groupLabel.replace("<URL>", url);

  const onStorageAccessBlockedMessage = waitForMessageByType(
    hud,
    getWarningMessage(`${TRACKER_IMG}?1&${now}`),
    ".warn"
  );
  emitStorageAccessBlockedMessage(tab, `${TRACKER_IMG}?1&${now}`);
  await onStorageAccessBlockedMessage;

  info(
    "Emit a new content blocking message to check that it causes a grouping"
  );

  const onContentBlockingWarningGroupMessage = waitForMessageByType(
    hud,
    groupLabel,
    ".warn"
  );
  emitStorageAccessBlockedMessage(tab, `${TRACKER_IMG}?2&${now}`);
  const { node } = await onContentBlockingWarningGroupMessage;
  is(
    node.querySelector(".warning-group-badge").textContent,
    "2",
    "The badge has the expected text"
  );

  await checkConsoleOutputForWarningGroup(hud, [`▶︎⚠ ${groupLabel} 2`]);

  info("Open the group");
  node.querySelector(".arrow").click();
  await waitFor(() => findWarningMessage(hud, TRACKER_IMG));

  await checkConsoleOutputForWarningGroup(hud, [
    `▼︎⚠ ${groupLabel} 2`,
    `| ${getWarningMessage(TRACKER_IMG + "?1&" + now)}`,
    `| ${getWarningMessage(TRACKER_IMG + "?2&" + now)}`,
  ]);

  await clearOutput(hud);
  await win.close();
}

/**
 * Emit a Content Blocking message. This is done by loading an iframe from an origin
 * tagged as tracker. The image is loaded with a incremented counter query parameter
 * each time so we can get the warning message.
 */
function emitContentBlockingMessage(tab, url) {
  SpecialPowers.spawn(tab.linkedBrowser, [url], function (innerURL) {
    content.wrappedJSObject.loadIframe(innerURL);
  });
}

/**
 * Emit a Storage blocked message. This is done by loading an image from an origin
 * tagged as tracker. The image is loaded with a incremented counter query parameter
 * each time so we can get the warning message.
 */
function emitStorageAccessBlockedMessage(tab, url) {
  SpecialPowers.spawn(tab.linkedBrowser, [url], async function (innerURL) {
    content.wrappedJSObject.loadImage(innerURL);
  });
}