diff --git a/index.js b/index.js index a2a83dc..7b373c3 100644 --- a/index.js +++ b/index.js @@ -5,11 +5,6 @@ const webExtension = require('sdk/webextension'); function handleWebExtensionMessage(message, sender, sendReply) { console.log(message); switch (message) { - case 'get-identities': - sendReply({ - content: {identities: ContextualIdentityService.getIdentities()} - }); - break; case 'open-containers-preferences': tabs.open('about:preferences#containers'); sendReply({content: 'opened'}); diff --git a/webextension-experiment/LICENSE b/webextension-experiment/LICENSE new file mode 100644 index 0000000..f979cc3 --- /dev/null +++ b/webextension-experiment/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2010 - 2016, Mozilla Corporation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +* Neither the name of the Mozilla Corporation nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/webextension-experiment/README.md b/webextension-experiment/README.md new file mode 100644 index 0000000..17794f1 --- /dev/null +++ b/webextension-experiment/README.md @@ -0,0 +1,7 @@ + +## Webextension contextual identities API extension + +This project contains the implementation of the Firefox +browser.contextualIdentites API. + +Based on: https://bugzilla.mozilla.org/show_bug.cgi?id=1322856 diff --git a/webextension-experiment/api.js b/webextension-experiment/api.js new file mode 100644 index 0000000..0d17c69 --- /dev/null +++ b/webextension-experiment/api.js @@ -0,0 +1,118 @@ +"use strict"; +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +const {XPCOMUtils} = Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +const CONTAINER_STORE = "firefox-container-"; + +XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", + "resource://gre/modules/ContextualIdentityService.jsm"); + +function convert(identity) { + let result = { + name: ContextualIdentityService.getUserContextLabel(identity.userContextId), + icon: identity.icon, + color: identity.color, + cookieStoreId: getCookieStoreIdForContainer(identity.userContextId), + }; + + return result; +} + +function getCookieStoreIdForContainer(containerId) { + return CONTAINER_STORE + containerId; +} + +class API extends ExtensionAPI { + getAPI(context) { + let self = { + contextualIdentities: { + get(cookieStoreId) { + let containerId = getContainerForCookieStoreId(cookieStoreId); + if (!containerId) { + return Promise.resolve(null); + } + + let identity = ContextualIdentityService.getIdentityFromId(containerId); + return Promise.resolve(convert(identity)); + }, + + query(details) { + let identities = []; + ContextualIdentityService.getIdentities().forEach(identity => { + if (details.name && + ContextualIdentityService.getUserContextLabel(identity.userContextId) != details.name) { + return; + } + + identities.push(convert(identity)); + }); + + return Promise.resolve(identities); + }, + + create(details) { + let identity = ContextualIdentityService.create(details.name, + details.icon, + details.color); + return Promise.resolve(convert(identity)); + }, + + update(cookieStoreId, details) { + let containerId = getContainerForCookieStoreId(cookieStoreId); + if (!containerId) { + return Promise.resolve(null); + } + + let identity = ContextualIdentityService.getIdentityFromId(containerId); + if (!identity) { + return Promise.resolve(null); + } + + if (details.name !== null) { + identity.name = details.name; + } + + if (details.color !== null) { + identity.color = details.color; + } + + if (details.icon !== null) { + identity.icon = details.icon; + } + + if (!ContextualIdentityService.update(identity.userContextId, + identity.name, identity.icon, + identity.color)) { + return Promise.resolve(null); + } + + return Promise.resolve(convert(identity)); + }, + + remove(cookieStoreId) { + let containerId = getContainerForCookieStoreId(cookieStoreId); + if (!containerId) { + return Promise.resolve(null); + } + + let identity = ContextualIdentityService.getIdentityFromId(containerId); + if (!identity) { + return Promise.resolve(null); + } + + // We have to create the identity object before removing it. + let convertedIdentity = convert(identity); + + if (!ContextualIdentityService.remove(identity.userContextId)) { + return Promise.resolve(null); + } + + return Promise.resolve(convertedIdentity); + }, + }, + }; + + return self; + } +} diff --git a/webextension-experiment/install.rdf b/webextension-experiment/install.rdf new file mode 100644 index 0000000..e1d4e0b --- /dev/null +++ b/webextension-experiment/install.rdf @@ -0,0 +1,31 @@ + + + + contextualidentities@experiments.addons.mozilla.org + Experimental Contextual Identites API + 256 + 0.1 + Experimental Contextual Identities API + groovecoder, baku and jkt + true + + + + + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + 51.0 + * + + + + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/webextension-experiment/schema.json b/webextension-experiment/schema.json new file mode 100644 index 0000000..562ad7d --- /dev/null +++ b/webextension-experiment/schema.json @@ -0,0 +1,105 @@ +[ + { + "namespace": "contextualIdentities", + "description": "Use the browser.contextualIdentities API to query and modify contextual identity, also called as containers.", + "permissions": ["contextualidentities"], + "types": [ + { + "id": "ContextualIdentity", + "type": "object", + "description": "Represents information about a contextual identity.", + "properties": { + "name": {"type": "string", "description": "The name of the contextual identity."}, + "icon": {"type": "string", "description": "The icon of the contextual identity."}, + "color": {"type": "string", "description": "The color of the contextual identity."}, + "cookieStoreId": {"type": "string", "description": "The cookie store ID of the contextual identity."} + } + } + ], + "functions": [ + { + "name": "get", + "type": "function", + "description": "Retrieves information about a single contextual identity.", + "async": true, + "parameters": [ + { + "type": "string", + "name": "cookieStoreId", + "description": "The ID of the contextual identity cookie store. " + } + ] + }, + { + "name": "query", + "type": "function", + "description": "Retrieves all contextual identities", + "async": true, + "parameters": [ + { + "type": "object", + "name": "details", + "description": "Information to filter the contextual identities being retrieved.", + "properties": { + "name": {"type": "string", "optional": true, "description": "Filters the contextual identity by name."} + } + } + ] + }, + { + "name": "create", + "type": "function", + "description": "Creates a contextual identity with the given data.", + "async": true, + "parameters": [ + { + "type": "object", + "name": "details", + "description": "Details about the contextual identity being created.", + "properties": { + "name": {"type": "string", "optional": false, "description": "The name of the contextual identity." }, + "color": {"type": "string", "optional": false, "description": "The color of the contextual identity." }, + "icon": {"type": "string", "optional": false, "description": "The icon of the contextual identity." } + } + } + ] + }, + { + "name": "update", + "type": "function", + "description": "Updates a contextual identity with the given data.", + "async": true, + "parameters": [ + { + "type": "string", + "name": "cookieStoreId", + "description": "The ID of the contextual identity cookie store. " + }, + { + "type": "object", + "name": "details", + "description": "Details about the contextual identity being created.", + "properties": { + "name": {"type": "string", "optional": true, "description": "The name of the contextual identity." }, + "color": {"type": "string", "optional": true, "description": "The color of the contextual identity." }, + "icon": {"type": "string", "optional": true, "description": "The icon of the contextual identity." } + } + } + ] + }, + { + "name": "remove", + "type": "function", + "description": "Deletes a contetual identity by its cookie Store ID.", + "async": true, + "parameters": [ + { + "type": "string", + "name": "cookieStoreId", + "description": "The ID of the contextual identity cookie store. " + } + ] + } + ] + } +] diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 6d265fa..4a6128b 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -1,26 +1,15 @@ -const IDENTITY_L10NID_MATCH_INDEX = 1; +browser.contextualIdentities.query({}).then(identites=> { + identites.forEach(identity=> { + console.log('identity: ', identity); + const identityRow = ` + +
+ ${identity.name} + > + `; -browser.runtime.sendMessage('get-identities').then(reply=> { - if (reply) { - console.log('reply from sdk addon: ', reply); - reply.content.identities.forEach(identity=> { - let identityName = identity.name; - - console.log('identityName: ', identityName); - - if (typeof identityName === 'undefined') { - identityName = identity.l10nID.match(/userContext(\w*)\.label/)[IDENTITY_L10NID_MATCH_INDEX]; - } - const identityRow = ` - -
- ${identityName} - > - `; - - document.querySelector('.identities-list').innerHTML += identityRow; - }); - } + document.querySelector('.identities-list').innerHTML += identityRow; + }); }); document.querySelector('#edit-containers-link').addEventListener('click', ()=> { diff --git a/webextension/manifest.json b/webextension/manifest.json index 57ac5ff..511371b 100644 --- a/webextension/manifest.json +++ b/webextension/manifest.json @@ -20,6 +20,8 @@ "homepage_url": "https://testpilot.firefox.com/", "permissions": [ + "experiments.contextualidentities", + "contextualidentities" ], "browser_action": {