Bug 1381197 - Add tests for browser.cookies APIs with first-party isolation. r=robwu,rpl
authorChung-Sheng Fu <cfu@mozilla.com>
Tue, 07 Nov 2017 15:32:19 +0800
changeset 449587 6eb01df118de5c86f89e38ec5a0fcd3cedd331da
parent 449586 36bccd1ca96f91d2d1fccfbb3b7af37bc38ba279
child 449588 fb220a3cfbb48c1aeb5ad1d0d8ae4749c5afc3ce
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrobwu, rpl
bugs1381197
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1381197 - Add tests for browser.cookies APIs with first-party isolation. r=robwu,rpl 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>