Bug 1381197 - Add tests for browser.cookies APIs with first-party isolation. draft
authorChung-Sheng Fu <cfu@mozilla.com>
Tue, 07 Nov 2017 15:32:19 +0800
changeset 715581 7310ea59e959deee68648e6b4f88dc52aed98ab9
parent 715580 9093fb5d1ed92c1dd8fb589035e8cbe96a444292
child 744831 92cca0b3d161d40316bbbb903149a3ef8728d3df
push id94200
push userbmo:cfu@mozilla.com
push dateThu, 04 Jan 2018 07:55:16 +0000
bugs1381197
milestone59.0a1
Bug 1381197 - Add tests for browser.cookies APIs with first-party isolation. MozReview-Commit-ID: 25Cx65Cr8Ry
toolkit/components/extensions/test/mochitest/mochitest-common.ini
toolkit/components/extensions/test/mochitest/test_ext_cookies_first_party.html
--- a/toolkit/components/extensions/test/mochitest/mochitest-common.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest-common.ini
@@ -113,16 +113,17 @@ skip-if = os == "win" # Bug 1398518
 [test_ext_sendmessage_reply2.html]
 skip-if = true # Bug 1258897
 [test_ext_storage_content.html]
 [test_ext_storage_tab.html]
 [test_ext_storage_manager_capabilities.html]
 scheme=https
 [test_ext_test.html]
 [test_ext_cookies.html]
+[test_ext_cookies_first_party.html]
 [test_ext_background_api_injection.html]
 [test_ext_background_generated_url.html]
 [test_ext_background_teardown.html]
 [test_ext_tab_teardown.html]
 skip-if = os == 'android' # Bug 1258975 on android.
 [test_ext_unlimitedStorage.html]
 [test_ext_unlimitedStorage_legacy_persistent_indexedDB.html]
 # IndexedDB persistent storage mode is not allowed on Fennec from a non-chrome privileged code
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_cookies_first_party.html
@@ -0,0 +1,218 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script src="/tests/SimpleTest/SpawnTask.js"></script>
+<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+<script src="head.js"></script>
+<script>
+"use strict";
+
+async function background() {
+  const url = "http://ext-cookie-first-party.mochi.test/";
+  const firstPartyDomain = "ext-cookie-first-party.mochi.test";
+  const expectedError = "First-Party Isolation is enabled, but the required 'firstPartyDomain' attribute was not set.";
+
+  const assertExpectedCookies = (expected, cookies, message) => {
+    let matches = (cookie, expected) => {
+      for (let key of Object.keys(expected)) {
+        if (cookie[key] !== expected[key]) {
+          return false;
+        }
+      }
+      return true;
+    };
+    browser.test.assertEq(expected.length, cookies.length, `Got expected number of cookies - ${message}`);
+    if (cookies.length !== expected.length) {
+      return;
+    }
+    for (let expect of expected) {
+      let foundCookies = cookies.filter(cookie => matches(cookie, expect));
+      browser.test.assertEq(1, foundCookies.length,
+                            `Expected cookie ${JSON.stringify(expect)} found - ${message}`);
+    }
+  };
+
+  // Test when FPI is disabled.
+  const test_fpi_disabled = async () => {
+    let cookie, cookies;
+
+    // set
+    cookie = await browser.cookies.set({url, name: "foo1", value: "bar1"});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+    ], [cookie], "set: FPI off, w/o firstPartyDomain, non-FP cookie");
+    cookie = await browser.cookies.set({url, name: "foo2", value: "bar2", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], [cookie], "set: FPI off, w/ firstPartyDomain, FP cookie");
+
+    // get
+    cookie = await browser.cookies.get({url, name: "foo1"});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+    ], [cookie], "get: FPI off, w/o firstPartyDomain, non-FP cookie");
+    cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], [cookie], "get: FPI off, w/ firstPartyDomain, FP cookie");
+
+    // getAll
+    cookies = await browser.cookies.getAll({});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+    ], cookies, "getAll: FPI off, w/o firstPartyDomain, non-FP cookies");
+    cookies = await browser.cookies.getAll({firstPartyDomain: null});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], cookies, "getAll: FPI off, w/ null firstPartyDomain, all cookies");
+    cookies = await browser.cookies.getAll({firstPartyDomain: undefined});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], cookies, "getAll: FPI off, w/ undefined firstPartyDomain, all cookies");
+    cookies = await browser.cookies.getAll({firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], cookies, "getAll: FPI off, w/ firstPartyDomain, FP cookies");
+
+    // remove
+    cookie = await browser.cookies.remove({url, name: "foo1"});
+    assertExpectedCookies([
+      {url, name: "foo1", firstPartyDomain: ""},
+    ], [cookie], "remove: FPI off, w/o firstPartyDomain, non-FP cookie");
+    cookie = await browser.cookies.remove({url, name: "foo2", firstPartyDomain});
+    assertExpectedCookies([
+      {url, name: "foo2", firstPartyDomain},
+    ], [cookie], "remove: FPI off, w/ firstPartyDomain, FP cookie");
+
+    // Test if FP cookies set when FPI off can be accessed when FPI on.
+    await browser.cookies.set({url, name: "foo1", value: "bar1"});
+    await browser.cookies.set({url, name: "foo2", value: "bar2", firstPartyDomain});
+
+    browser.test.sendMessage("test_fpi_disabled");
+  };
+
+  // Test when FPI is enabled.
+  const test_fpi_enabled = async () => {
+    let cookie, cookies;
+
+    // set
+    browser.test.assertRejects(browser.cookies.set({url, name: "foo3", value: "bar3"}),
+                               expectedError,
+                               "set: FPI on, w/o firstPartyDomain, rejection");
+    cookie = await browser.cookies.set({url, name: "foo4", value: "bar4", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo4", value: "bar4", firstPartyDomain},
+    ], [cookie], "set: FPI on, w/ firstPartyDomain, FP cookie");
+
+    // get
+    browser.test.assertRejects(browser.cookies.get({url, name: "foo3"}),
+                               expectedError,
+                               "get: FPI on, w/o firstPartyDomain, rejection");
+    cookie = await browser.cookies.get({url, name: "foo4", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo4", value: "bar4", firstPartyDomain},
+    ], [cookie], "get: FPI on, w/ firstPartyDomain, FP cookie");
+    cookie = await browser.cookies.get({url, name: "foo2", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo2", value: "bar2", firstPartyDomain},
+    ], [cookie], "get: FPI on, w/ firstPartyDomain, FP cookie (set when FPI off)");
+
+    // getAll
+    browser.test.assertRejects(browser.cookies.getAll({}),
+                               expectedError,
+                               "getAll: FPI on, w/o firstPartyDomain, rejection");
+    cookies = await browser.cookies.getAll({firstPartyDomain: null});
+    assertExpectedCookies([
+      {name: "foo1", value: "bar1", firstPartyDomain: ""},
+      {name: "foo2", value: "bar2", firstPartyDomain},
+      {name: "foo4", value: "bar4", firstPartyDomain},
+    ], cookies, "getAll: FPI on, w/ null firstPartyDomain, all cookies");
+    cookies = await browser.cookies.getAll({firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo2", value: "bar2", firstPartyDomain},
+      {name: "foo4", value: "bar4", firstPartyDomain},
+    ], cookies, "getAll: FPI on, w/ firstPartyDomain, FP cookies");
+
+    // remove
+    browser.test.assertRejects(browser.cookies.remove({url, name: "foo3"}),
+                               expectedError,
+                               "remove: FPI on, w/o firstPartyDomain, rejection");
+    cookie = await browser.cookies.remove({url, name: "foo4", firstPartyDomain});
+    assertExpectedCookies([
+      {url, name: "foo4", firstPartyDomain},
+    ], [cookie], "remove: FPI on, w/ firstPartyDomain, FP cookie");
+    cookie = await browser.cookies.remove({url, name: "foo2", firstPartyDomain});
+    assertExpectedCookies([
+      {url, name: "foo2", firstPartyDomain},
+    ], [cookie], "remove: FPI on, w/ firstPartyDomain, FP cookie (set when FPI off)");
+
+    // Test if FP cookies set when FPI on can be accessed when FPI off.
+    await browser.cookies.set({url, name: "foo4", value: "bar4", firstPartyDomain});
+
+    browser.test.sendMessage("test_fpi_enabled");
+  };
+
+  // Test when FPI is disabled again, accessing FP cookies set when FPI is enabled.
+  const test_fpd_cookies_on_fpi_disabled = async () => {
+    let cookie, cookies;
+    cookie = await browser.cookies.get({url, name: "foo4", firstPartyDomain});
+    assertExpectedCookies([
+      {name: "foo4", value: "bar4", firstPartyDomain},
+    ], [cookie], "get: FPI off, w/ firstPartyDomain, FP cookie (set when FPI on)");
+    cookie = await browser.cookies.remove({url, name: "foo4", firstPartyDomain});
+    assertExpectedCookies([
+      {url, name: "foo4", firstPartyDomain},
+    ], [cookie], "remove: FPI off, w/ firstPartyDomain, FP cookie (set when FPI on)");
+
+    // Clean up.
+    await browser.cookies.remove({url, name: "foo1"});
+
+    cookies = await browser.cookies.getAll({firstPartyDomain: null});
+    assertExpectedCookies([], cookies, "Test is finishing, all cookies removed");
+
+    browser.test.sendMessage("test_fpd_cookies_on_fpi_disabled");
+  };
+
+  browser.test.onMessage.addListener((message) => {
+    switch (message) {
+      case "test_fpi_disabled": return test_fpi_disabled();
+      case "test_fpi_enabled": return test_fpi_enabled();
+      case "test_fpd_cookies_on_fpi_disabled": return test_fpd_cookies_on_fpi_disabled();
+      default: return browser.test.notifyFail("unknown-message");
+    }
+  });
+}
+
+function enableFirstPartyIsolation() {
+  return SpecialPowers.pushPrefEnv({
+    set: [
+      ["privacy.firstparty.isolate", true],
+    ],
+  });
+}
+
+function disableFirstPartyIsolation() {
+  return SpecialPowers.popPrefEnv();
+}
+
+add_task(async () => {
+  let extension = ExtensionTestUtils.loadExtension({
+    background,
+    manifest: {
+      permissions: ["cookies", "*://ext-cookie-first-party.mochi.test/"],
+    },
+  });
+  await extension.startup();
+  extension.sendMessage("test_fpi_disabled");
+  await extension.awaitMessage("test_fpi_disabled");
+  await enableFirstPartyIsolation();
+  extension.sendMessage("test_fpi_enabled");
+  await extension.awaitMessage("test_fpi_enabled");
+  await disableFirstPartyIsolation();
+  extension.sendMessage("test_fpd_cookies_on_fpi_disabled");
+  await extension.awaitMessage("test_fpd_cookies_on_fpi_disabled");
+  await extension.unload();
+});
+</script>