Bug 1395659 - Rejecting contextual identity APIs when containers are disabled. r?kmag draft
authorJonathan Kingston <jkt@mozilla.com>
Thu, 31 Aug 2017 11:46:31 -0700
changeset 661137 2def9bf01032576c4230b43a1e8f0469f89d0945
parent 660845 3c96d611ebd67fc219d22bcb476a72412c76f6c7
child 730461 06d0733cc52e7187d86946b32a67ea9ddf9020bb
push id78640
push userbmo:jkt@mozilla.com
push dateFri, 08 Sep 2017 00:35:24 +0000
reviewerskmag
bugs1395659
milestone57.0a1
Bug 1395659 - Rejecting contextual identity APIs when containers are disabled. r?kmag MozReview-Commit-ID: LCiI74SN12y
toolkit/components/extensions/ext-contextualIdentities.js
toolkit/components/extensions/test/xpcshell/test_ext_contextual_identities.js
--- a/toolkit/components/extensions/ext-contextualIdentities.js
+++ b/toolkit/components/extensions/ext-contextualIdentities.js
@@ -71,16 +71,22 @@ const convertIdentity = identity => {
     color: identity.color,
     colorCode: getContainerColor(identity.color),
     cookieStoreId: getCookieStoreIdForContainer(identity.userContextId),
   };
 
   return result;
 };
 
+const checkAPIEnabled = () => {
+  if (!containersEnabled) {
+    throw new ExtensionError("Contextual identities are currently disabled");
+  }
+};
+
 const convertIdentityFromObserver = wrappedIdentity => {
   let identity = wrappedIdentity.wrappedJSObject;
   let iconUrl, colorCode;
   try {
     iconUrl = getContainerIcon(identity.icon);
     colorCode = getContainerColor(identity.color);
   } catch (e) {
     return null;
@@ -122,28 +128,28 @@ this.contextualIdentities = class extend
       ExtensionPreferencesManager.setSetting(extension, CONTAINERS_ENABLED_SETTING_NAME, true);
     }
   }
 
   getAPI(context) {
     let self = {
       contextualIdentities: {
         async get(cookieStoreId) {
+          checkAPIEnabled();
           let containerId = getContainerForCookieStoreId(cookieStoreId);
           if (!containerId) {
-            return Promise.reject({
-              message: `Invalid contextual identitiy: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Invalid contextual identitiy: ${cookieStoreId}`);
           }
 
           let identity = ContextualIdentityService.getPublicIdentityFromId(containerId);
           return convertIdentity(identity);
         },
 
         async query(details) {
+          checkAPIEnabled();
           let identities = [];
           ContextualIdentityService.getPublicIdentities().forEach(identity => {
             if (details.name &&
                 ContextualIdentityService.getUserContextLabel(identity.userContextId) != details.name) {
               return;
             }
 
             identities.push(convertIdentity(identity));
@@ -158,29 +164,26 @@ this.contextualIdentities = class extend
           getContainerColor(details.color);
 
           let identity = ContextualIdentityService.create(details.name,
                                                           details.icon,
                                                           details.color);
           return convertIdentity(identity);
         },
 
-        update(cookieStoreId, details) {
+        async update(cookieStoreId, details) {
+          checkAPIEnabled();
           let containerId = getContainerForCookieStoreId(cookieStoreId);
           if (!containerId) {
-            return Promise.reject({
-              message: `Invalid contextual identitiy: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Invalid contextual identitiy: ${cookieStoreId}`);
           }
 
           let identity = ContextualIdentityService.getPublicIdentityFromId(containerId);
           if (!identity) {
-            return Promise.reject({
-              message: `Invalid contextual identitiy: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Invalid contextual identitiy: ${cookieStoreId}`);
           }
 
           if (details.name !== null) {
             identity.name = details.name;
           }
 
           if (details.color !== null) {
             identity.color = details.color;
@@ -188,46 +191,39 @@ this.contextualIdentities = class extend
 
           if (details.icon !== null) {
             identity.icon = details.icon;
           }
 
           if (!ContextualIdentityService.update(identity.userContextId,
                                                 identity.name, identity.icon,
                                                 identity.color)) {
-            return Promise.reject({
-              message: `Contextual identitiy failed to update: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Contextual identitiy failed to update: ${cookieStoreId}`);
           }
 
           return convertIdentity(identity);
         },
 
         async remove(cookieStoreId) {
+          checkAPIEnabled();
           let containerId = getContainerForCookieStoreId(cookieStoreId);
           if (!containerId) {
-            return Promise.reject({
-              message: `Invalid contextual identitiy: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Invalid contextual identitiy: ${cookieStoreId}`);
           }
 
           let identity = ContextualIdentityService.getPublicIdentityFromId(containerId);
           if (!identity) {
-            return Promise.reject({
-              message: `Invalid contextual identitiy: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Invalid contextual identitiy: ${cookieStoreId}`);
           }
 
           // We have to create the identity object before removing it.
           let convertedIdentity = convertIdentity(identity);
 
           if (!ContextualIdentityService.remove(identity.userContextId)) {
-            return Promise.reject({
-              message: `Contextual identitiy failed to remove: ${cookieStoreId}`,
-            });
+            throw new ExtensionError(`Contextual identitiy failed to remove: ${cookieStoreId}`);
           }
 
           return convertedIdentity;
         },
 
         onCreated: new EventManager(context, "contextualIdentities.onCreated", fire => {
           let observer = (subject, topic) => {
             let convertedIdentity = convertIdentityFromObserver(subject);
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contextual_identities.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contextual_identities.js
@@ -122,16 +122,40 @@ add_task(async function test_contextualI
     ci = await browser.contextualIdentities.get("firefox-container-1");
     browser.test.assertTrue(!!ci, "We have an identity");
     browser.test.assertTrue("name" in ci, "We have an identity.name");
     browser.test.assertTrue("color" in ci, "We have an identity.color");
     browser.test.assertTrue("icon" in ci, "We have an identity.icon");
     browser.test.assertEq("Personal", ci.name, "identity.name is correct");
     browser.test.assertEq("firefox-container-1", ci.cookieStoreId, "identity.cookieStoreId is correct");
 
+    function listenForMessage(messageName, stateChangeBool) {
+      return new Promise((resolve) => {
+        browser.test.onMessage.addListener(function listener(msg) {
+          browser.test.log(`Got message from background: ${msg}`);
+          if (msg === messageName + "-response") {
+            browser.test.onMessage.removeListener(listener);
+            resolve();
+          }
+        });
+        browser.test.log(`Sending message to background: ${messageName} ${stateChangeBool}`);
+        browser.test.sendMessage(messageName, stateChangeBool);
+      });
+    }
+
+    await listenForMessage("containers-state-change", false);
+
+    browser.test.assertRejects(
+      browser.contextualIdentities.query({}),
+      "Contextual identities are currently disabled",
+      "Throws when containers are disabled"
+    );
+
+    await listenForMessage("containers-state-change", true);
+
     let cis = await browser.contextualIdentities.query({});
     browser.test.assertEq(4, cis.length, "by default we should have 4 containers");
 
     cis = await browser.contextualIdentities.query({name: "Personal"});
     browser.test.assertEq(1, cis.length, "by default we should have 1 container called Personal");
 
     cis = await browser.contextualIdentities.query({name: "foobar"});
     browser.test.assertEq(0, cis.length, "by default we should have 0 container called foobar");
@@ -185,30 +209,39 @@ add_task(async function test_contextualI
     browser.test.assertEq("blue", ci.color, "identity.color is correct");
     browser.test.assertEq("cart", ci.icon, "identity.icon is correct");
 
     cis = await browser.contextualIdentities.query({});
     browser.test.assertEq(4, cis.length, "we are back to 4 identities");
 
     browser.test.notifyPass("contextualIdentities");
   }
+
   function makeExtension(id) {
     return ExtensionTestUtils.loadExtension({
       useAddonManager: "temporary",
       background,
       manifest: {
         applications: {
           gecko: {id},
         },
         permissions: ["contextualIdentities"],
       },
     });
   }
 
   let extension = makeExtension("containers-test@mozilla.org");
+
+  extension.onMessage("containers-state-change", (stateBool) => {
+    Components.utils.reportError(`Got message "containers-state-change", ${stateBool}`);
+    Services.prefs.setBoolPref(CONTAINERS_PREF, stateBool);
+    Components.utils.reportError("Changed pref");
+    extension.sendMessage("containers-state-change-response");
+  });
+
   await extension.startup();
   await extension.awaitFinish("contextualIdentities");
   equal(Services.prefs.getBoolPref(CONTAINERS_PREF), true, "Pref should now be enabled, whatever it's initial state");
   await extension.unload();
   equal(Services.prefs.getBoolPref(CONTAINERS_PREF), initial, "Pref should now be initial state");
 
   Services.prefs.clearUserPref(CONTAINERS_PREF);
 });