summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/test/browser/browser_contentBlockingAllowListPrincipal.js
blob: a9e2ac6fce9301bd303e13a54e86a7d4e7d49a20 (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
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const TEST_SANDBOX_URL =
  "https://example.com/browser/toolkit/components/antitracking/test/browser/sandboxed.html";

/**
 * Tests the contentBlockingAllowListPrincipal.
 * @param {Browser} browser - Browser to test.
 * @param {("content"|"system")} type - Expected principal type.
 * @param {String} [origin] - Expected origin of principal. Defaults to the
 * origin of the browsers content principal.
 */
function checkAllowListPrincipal(
  browser,
  type,
  origin = browser.contentPrincipal.origin
) {
  let principal =
    browser.browsingContext.currentWindowGlobal
      .contentBlockingAllowListPrincipal;
  ok(principal, "Principal is set");

  if (type == "content") {
    ok(principal.isContentPrincipal, "Is content principal");

    ok(
      principal.schemeIs("https"),
      "allowlist content principal must have https scheme"
    );
  } else if (type == "system") {
    ok(principal.isSystemPrincipal, "Is system principal");
  } else {
    throw new Error("Unexpected principal type");
  }

  is(principal.origin, origin, "Correct origin");
}

/**
 * Runs a given test in a normal window and in a private browsing window.
 * @param {String} initialUrl - URL to load in the initial test tab.
 * @param {Function} testCallback - Test function to run in both windows.
 */
async function runTestInNormalAndPrivateMode(initialUrl, testCallback) {
  for (let i = 0; i < 2; i++) {
    let isPrivateBrowsing = !!i;
    info("Running test. Private browsing: " + !!i);
    let win = await BrowserTestUtils.openNewBrowserWindow({
      private: isPrivateBrowsing,
    });
    let tab = BrowserTestUtils.addTab(win.gBrowser, initialUrl);
    let browser = tab.linkedBrowser;

    await BrowserTestUtils.browserLoaded(browser);

    await testCallback(browser, isPrivateBrowsing);

    await BrowserTestUtils.closeWindow(win);
  }
}

/**
 * Creates an iframe in the passed browser and waits for it to load.
 * @param {Browser} browser - Browser to create the frame in.
 * @param {String} src - Frame source url.
 * @param {String} id - Frame id.
 * @param {String} [sandboxAttr] - Optional list of sandbox attributes to set
 * for the iframe. Defaults to no sandbox.
 * @returns {Promise} - Resolves once the frame has loaded.
 */
function createFrame(browser, src, id, sandboxAttr) {
  return SpecialPowers.spawn(
    browser,
    [{ page: src, frameId: id, sandboxAttr }],
    async function (obj) {
      await new content.Promise(resolve => {
        let frame = content.document.createElement("iframe");
        frame.src = obj.page;
        frame.id = obj.frameId;
        if (obj.sandboxAttr) {
          frame.setAttribute("sandbox", obj.sandboxAttr);
        }
        frame.addEventListener("load", resolve, { once: true });
        content.document.body.appendChild(frame);
      });
    }
  );
}

add_task(async setup => {
  // Disable heuristics. We don't need them and if enabled the resulting
  // telemetry can race with the telemetry in the next test.
  // See Bug 1686836, Bug 1686894.
  await SpecialPowers.pushPrefEnv({
    set: [
      ["privacy.restrict3rdpartystorage.heuristic.redirect", false],
      ["privacy.restrict3rdpartystorage.heuristic.recently_visited", false],
      ["privacy.restrict3rdpartystorage.heuristic.window_open", false],
      ["dom.security.https_first_pbm", false],
    ],
  });
});

/**
 * Test that we get the correct allow list principal which matches the content
 * principal for an https site.
 */
add_task(async test_contentPrincipalHTTPS => {
  await runTestInNormalAndPrivateMode("https://example.com", browser => {
    checkAllowListPrincipal(browser, "content");
  });
});

/**
 * Tests that the scheme of the allowlist principal is HTTPS, even though the
 * site is loaded via HTTP.
 */
add_task(async test_contentPrincipalHTTP => {
  await runTestInNormalAndPrivateMode(
    "http://example.net",
    (browser, isPrivateBrowsing) => {
      checkAllowListPrincipal(
        browser,
        "content",
        "https://example.net" +
          (isPrivateBrowsing ? "^privateBrowsingId=1" : "")
      );
    }
  );
});

/**
 * Tests that the allow list principal is a system principal for the preferences
 * about site.
 */
add_task(async test_systemPrincipal => {
  await runTestInNormalAndPrivateMode("about:preferences", browser => {
    checkAllowListPrincipal(browser, "system");
  });
});

/**
 * Tests that we get a valid content principal for top level sandboxed pages,
 * and not the document principal which is a null principal.
 */
add_task(async test_TopLevelSandbox => {
  await runTestInNormalAndPrivateMode(
    TEST_SANDBOX_URL,
    (browser, isPrivateBrowsing) => {
      ok(
        browser.contentPrincipal.isNullPrincipal,
        "Top level sandboxed page should have null principal"
      );
      checkAllowListPrincipal(
        browser,
        "content",
        "https://example.com" +
          (isPrivateBrowsing ? "^privateBrowsingId=1" : "")
      );
    }
  );
});

/**
 * Tests that we get a valid content principal for a new tab opened via
 * window.open.
 */
add_task(async test_windowOpen => {
  await runTestInNormalAndPrivateMode("https://example.com", async browser => {
    checkAllowListPrincipal(browser, "content");

    let promiseTabOpened = BrowserTestUtils.waitForNewTab(
      browser.ownerGlobal.gBrowser,
      "https://example.org/",
      true
    );

    // Call window.open from iframe.
    await SpecialPowers.spawn(browser, [], async function () {
      content.open("https://example.org/");
    });

    let tab = await promiseTabOpened;

    checkAllowListPrincipal(tab.linkedBrowser, "content");

    BrowserTestUtils.removeTab(tab);
  });
});

/**
 * Tests that we get a valid content principal for a new tab opened via
 * window.open from a sandboxed iframe.
 */
add_task(async test_windowOpenFromSandboxedFrame => {
  await runTestInNormalAndPrivateMode(
    "https://example.com",
    async (browser, isPrivateBrowsing) => {
      checkAllowListPrincipal(browser, "content");

      // Create sandboxed iframe, allow popups.
      await createFrame(
        browser,
        "https://example.com",
        "sandboxedIframe",
        "allow-popups"
      );
      // Iframe BC is the only child of the test browser.
      let [frameBrowsingContext] = browser.browsingContext.children;

      let promiseTabOpened = BrowserTestUtils.waitForNewTab(
        browser.ownerGlobal.gBrowser,
        "https://example.org/",
        true
      );

      // Call window.open from iframe.
      await SpecialPowers.spawn(frameBrowsingContext, [], async function () {
        content.open("https://example.org/");
      });

      let tab = await promiseTabOpened;

      checkAllowListPrincipal(
        tab.linkedBrowser,
        "content",
        "https://example.org" +
          (isPrivateBrowsing ? "^privateBrowsingId=1" : "")
      );

      BrowserTestUtils.removeTab(tab);
    }
  );
});