From 50b58f649f512011386888e738ee91dbb066c765 Mon Sep 17 00:00:00 2001 From: baku Date: Thu, 2 Mar 2017 15:53:24 +0100 Subject: [PATCH 1/9] Cleanup cookieJar when addon is uninstall - issue #300 --- .eslintrc.js | 3 ++- index.js | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 3876d96..2650c58 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,8 @@ module.exports = { "globals": { "CustomizableUI": true, "CustomizableWidgets": true, - "SessionStore": true + "SessionStore": true, + "Services": true }, "plugins": [ "promise" diff --git a/index.js b/index.js index 1fa0e91..1615cad 100644 --- a/index.js +++ b/index.js @@ -30,6 +30,7 @@ const IDENTITY_ICONS = [ { name: "briefcase", image: "chrome://browser/skin/usercontext/work.svg" }, { name: "dollar", image: "chrome://browser/skin/usercontext/banking.svg" }, { name: "cart", image: "chrome://browser/skin/usercontext/shopping.svg" }, + // All of these do not exist in gecko { name: "gift", image: "gift" }, { name: "vacation", image: "vacation" }, { name: "food", image: "food" }, @@ -37,7 +38,7 @@ const IDENTITY_ICONS = [ { name: "pet", image: "pet" }, { name: "tree", image: "tree" }, { name: "chill", image: "chill" }, - { name: "circle", image: "circle" }, // this doesn't exist in m-b + { name: "circle", image: "circle" }, ]; const PREFS = [ @@ -68,6 +69,7 @@ const windowUtils = require("sdk/window/utils"); Cu.import("resource:///modules/CustomizableUI.jsm"); Cu.import("resource:///modules/CustomizableWidgets.jsm"); Cu.import("resource:///modules/sessionstore/SessionStore.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); // ---------------------------------------------------------------------------- // ContextualIdentityProxy @@ -1076,6 +1078,10 @@ const ContainerService = { ContextualIdentityProxy.getIdentities().forEach(identity => { if (!preInstalledIdentities.includes(identity.userContextId)) { ContextualIdentityProxy.remove(identity.userContextId); + } else { + // Let's cleanup all the cookies for this container. + Services.obs.notifyObservers(null, "clear-origin-attributes-data", + JSON.stringify({ userContextId: identity.userContextId })); } }); From 08fe35510108c8044727ec62d9fc92a6ed185b3c Mon Sep 17 00:00:00 2001 From: baku Date: Fri, 3 Mar 2017 08:48:11 +0100 Subject: [PATCH 2/9] If localStorage is disabled, we skip the onboarding - #302 --- webextension/js/popup.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/webextension/js/popup.js b/webextension/js/popup.js index c75985c..b58138a 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -32,7 +32,8 @@ const Logic = { // Routing to the correct panel. .then(() => { - if (localStorage.getItem("onboarded3")) { + // If localStorage is disabled, we don't show the onboarding. + if (!localStorage || localStorage.getItem("onboarded3")) { this.showPanel(P_CONTAINERS_LIST); } else if (localStorage.getItem("onboarded2")) { this.showPanel(P_ONBOARDING_3); From a0d8a55a92d6ef887907e3f2ae023d8306d4096a Mon Sep 17 00:00:00 2001 From: groovecoder Date: Thu, 2 Mar 2017 09:19:40 -0600 Subject: [PATCH 3/9] add irc notifications for Travis CI builds --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index c2a2c34..4614306 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ language: node_js node_js: - "6.1" + +notifications: + irc: + - "ircs://irc.mozilla.org:6697/#testpilot-containers-bots" From 6b995586fdc25b146bd46470fe74c38a37d24347 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Thu, 9 Mar 2017 00:22:26 +0000 Subject: [PATCH 4/9] Fix submission of edit form by enter key. Fixes #341~ --- webextension/js/popup.js | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/webextension/js/popup.js b/webextension/js/popup.js index c75985c..d312565 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -481,22 +481,28 @@ Logic.registerPanel(P_CONTAINER_EDIT, { Logic.showPreviousPanel(); }); - document.querySelector("#edit-container-ok-link").addEventListener("click", () => { - const identity = Logic.currentIdentity(); - const formValues = new FormData(document.getElementById("edit-container-panel-form")); - browser.runtime.sendMessage({ - method: identity.userContextId ? "updateIdentity" : "createIdentity", - userContextId: identity.userContextId || 0, - name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(), - icon: formValues.get("container-icon") || DEFAULT_ICON, - color: formValues.get("container-color") || DEFAULT_COLOR, - }).then(() => { - return Logic.refreshIdentities(); - }).then(() => { - Logic.showPreviousPanel(); - }).catch(() => { - Logic.showPanel(P_CONTAINERS_LIST); - }); + this._editForm = document.getElementById("edit-container-panel-form"); + const editLink = document.querySelector("#edit-container-ok-link"); + editLink.addEventListener("click", this._submitForm); + editLink.addEventListener("submit", this._submitForm); + this._editForm.addEventListener("submit", this._submitForm); + }, + + _submitForm() { + const identity = Logic.currentIdentity(); + const formValues = new FormData(this._editForm); + browser.runtime.sendMessage({ + method: identity.userContextId ? "updateIdentity" : "createIdentity", + userContextId: identity.userContextId || 0, + name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(), + icon: formValues.get("container-icon") || DEFAULT_ICON, + color: formValues.get("container-color") || DEFAULT_COLOR, + }).then(() => { + return Logic.refreshIdentities(); + }).then(() => { + Logic.showPreviousPanel(); + }).catch(() => { + Logic.showPanel(P_CONTAINERS_LIST); }); }, From 0220135880a47a967f4da89bd988f9dfb76106ab Mon Sep 17 00:00:00 2001 From: TJ Walker Date: Wed, 8 Mar 2017 20:39:00 -0800 Subject: [PATCH 5/9] Update README.md Correct indication of feature availability. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c8b6a8..3fead42 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Containers: Test Pilot Experiment -Soon to be [![Available on Test Pilot](https://img.shields.io/badge/available_on-Test_Pilot-0996F8.svg)](https://testpilot.firefox.com/) +[![Available on Test Pilot](https://img.shields.io/badge/available_on-Test_Pilot-0996F8.svg)](https://testpilot.firefox.com/experiments/containers) [Embedded Web Extension](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Embedded_WebExtensions) to experiment with [Containers](https://blog.mozilla.org/tanvi/2016/06/16/contextual-identities-on-the-web/) in [Firefox Test Pilot](https://testpilot.firefox.com/) to learn: From f1c2cbc686215599857dea6dfa3153d389060d55 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Wed, 22 Feb 2017 17:02:53 +0000 Subject: [PATCH 6/9] Add ability to check for theme dark on changing themes. Fixes #207 --- index.js | 51 ++++++++++++++++++++++++++++++++++++++ webextension/background.js | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/index.js b/index.js index 1615cad..2b9a1fa 100644 --- a/index.js +++ b/index.js @@ -52,10 +52,12 @@ const { attachTo, detachFrom } = require("sdk/content/mod"); const { Cu } = require("chrome"); const { ContextualIdentityService } = require("resource://gre/modules/ContextualIdentityService.jsm"); const { getFavicon } = require("sdk/places/favicon"); +const { LightweightThemeManager } = Cu.import("resource://gre/modules/LightweightThemeManager.jsm", {}); const Metrics = require("./testpilot-metrics"); const { modelFor } = require("sdk/model/core"); const prefService = require("sdk/preferences/service"); const self = require("sdk/self"); +const { Services } = require("resource://gre/modules/Services.jsm"); const ss = require("sdk/simple-storage"); const { Style } = require("sdk/stylesheet/style"); const tabs = require("sdk/tabs"); @@ -115,6 +117,7 @@ const ContainerService = { _identitiesState: {}, _windowMap: new Map(), _containerWasEnabled: false, + _onThemeChangedCallback: null, init(installation) { // If we are just been installed, we must store some information for the @@ -196,6 +199,7 @@ const ContainerService = { "updateIdentity", "getPreference", "sendTelemetryPayload", + "getTheme", "checkIncompatibleAddons" ]; @@ -254,6 +258,8 @@ const ContainerService = { sendReply(this[message.method](message)); } }); + + this.registerThemeConnection(api); }).catch(() => { throw new Error("WebExtension startup failed. Unable to continue."); }); @@ -292,6 +298,51 @@ const ContainerService = { }; } // End-Of-Hack + + Services.obs.addObserver(this, "lightweight-theme-changed", false); + }, + + registerThemeConnection(api) { + // This is only used for theme notifications + api.browser.runtime.onConnect.addListener((port) => { + this.onThemeChanged((theme, topic) => { + port.postMessage({ + type: topic, + theme + }); + }); + }); + }, + + triggerThemeChanged(theme, topic) { + if (this._onThemeChangedCallback) { + this._onThemeChangedCallback(theme, topic); + } + }, + + observe(subject, topic) { + if (topic === "lightweight-theme-changed") { + this.getTheme().then((theme) => { + this.triggerThemeChanged(theme, topic); + }).catch(() => { + throw new Error("Unable to get theme"); + }); + } + }, + + getTheme() { + const defaultTheme = "firefox-compact-light@mozilla.org"; + return new Promise(function (resolve) { + let theme = defaultTheme; + if (LightweightThemeManager.currentTheme && LightweightThemeManager.currentTheme.id) { + theme = LightweightThemeManager.currentTheme.id; + } + resolve(theme); + }); + }, + + onThemeChanged(callback) { + this._onThemeChangedCallback = callback; }, // utility methods diff --git a/webextension/background.js b/webextension/background.js index 3875580..e909c6b 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -1,3 +1,50 @@ + +const themeManager = { + existingTheme: null, + init() { + this.check(); + + const port = browser.runtime.connect(); + port.onMessage.addListener(m => { + if (m.type === "lightweight-theme-changed") { + this.update(m.theme); + } + }); + }, + setPopupIcon(theme) { + let icons = { + 16: "img/container-site-d-24.png", + 32: "img/container-site-d-48.png" + }; + if (theme === "firefox-compact-dark@mozilla.org") { + icons = { + 16: "img/container-site-w-24.png", + 32: "img/container-site-w-48.png" + }; + } + browser.browserAction.setIcon({ + path: icons + }); + }, + check() { + browser.runtime.sendMessage({ + method: "getTheme" + }).then((theme) => { + this.update(theme); + }).catch(() => { + throw new Error("Unable to get theme"); + }); + }, + update(theme) { + if (this.existingTheme !== theme) { + this.setPopupIcon(theme); + this.existingTheme = theme; + } + } +}; + +themeManager.init(); + browser.runtime.sendMessage({ method: "getPreference", pref: "browser.privatebrowsing.autostart" From d0e57a0339dddf4d50cf348242cab92b300ecbb7 Mon Sep 17 00:00:00 2001 From: groovecoder Date: Thu, 9 Mar 2017 14:26:00 -0600 Subject: [PATCH 7/9] 1.1.0 :tada: --- package.json | 2 +- webextension/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 4a0172a..94d011e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Containers Experiment", "description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.", - "version": "1.0.4", + "version": "1.1.0", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/testpilot-containers/issues" diff --git a/webextension/manifest.json b/webextension/manifest.json index f7e473a..3bb95da 100644 --- a/webextension/manifest.json +++ b/webextension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Containers Experiment", - "version": "1.0.4", + "version": "1.1.0", "description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.", "icons": { From 9d5223cd71d0c0782d0ac77e5da5879c5b6eca00 Mon Sep 17 00:00:00 2001 From: groovecoder Date: Fri, 10 Mar 2017 11:02:29 -0600 Subject: [PATCH 8/9] bind submitForm event listener to keep _editForm --- webextension/js/popup.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 80c852e..abb1c64 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -484,9 +484,9 @@ Logic.registerPanel(P_CONTAINER_EDIT, { this._editForm = document.getElementById("edit-container-panel-form"); const editLink = document.querySelector("#edit-container-ok-link"); - editLink.addEventListener("click", this._submitForm); - editLink.addEventListener("submit", this._submitForm); - this._editForm.addEventListener("submit", this._submitForm); + editLink.addEventListener("click", this._submitForm.bind(this)); + editLink.addEventListener("submit", this._submitForm.bind(this)); + this._editForm.addEventListener("submit", this._submitForm.bind(this)); }, _submitForm() { From 52cf6df7ff7c0f7c909476e5f45d5ff4389e3ab5 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Mon, 13 Mar 2017 01:22:47 +0000 Subject: [PATCH 9/9] Fix escaping of container names in popups. Bug 1346653 --- .eslintrc.js | 5 +++- package.json | 5 ++-- webextension/js/popup.js | 48 ++++++++++++++++++++++++++++++++++---- webextension/manifest.json | 2 +- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 2650c58..748b27b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,8 @@ module.exports = { "Services": true }, "plugins": [ - "promise" + "promise", + "unsafe-property-assignment" ], "root": true, "rules": { @@ -28,6 +29,8 @@ module.exports = { "promise/no-promise-in-callback": "warn", "promise/no-return-wrap": "error", "promise/param-names": "error", + "unsafe-property-assignment/no-key-assignment": ["error"], + "unsafe-property-assignment/enforce-tagged-template-protection": ["error"], "eqeqeq": "error", "indent": ["error", 2], diff --git a/package.json b/package.json index 94d011e..75f6de1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "testpilot-containers", "title": "Containers Experiment", "description": "Containers works by isolating cookie jars using separate origin-attributes defined visually by colored ‘Container Tabs’. This add-on is a modified version of the containers feature for Firefox Test Pilot.", - "version": "1.1.0", + "version": "1.1.1", "author": "Andrea Marchesini, Luke Crouch and Jonathan Kingston", "bugs": { "url": "https://github.com/mozilla/testpilot-containers/issues" @@ -11,8 +11,9 @@ "devDependencies": { "addons-linter": "^0.15.14", "deploy-txp": "^1.0.7", - "eslint": "^3.12.2", + "eslint": "^3.17.1", "eslint-plugin-promise": "^3.4.0", + "eslint-plugin-unsafe-property-assign": "^1.0.2", "htmllint-cli": "^0.0.5", "jpm": "^1.2.2", "npm-run-all": "^4.0.0", diff --git a/webextension/js/popup.js b/webextension/js/popup.js index abb1c64..c108558 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -18,6 +18,42 @@ const P_CONTAINER_INFO = "containerInfo"; const P_CONTAINER_EDIT = "containerEdit"; const P_CONTAINER_DELETE = "containerDelete"; +/** + * Escapes any occurances of &, ", < or > with XML entities. + * + * @param {string} str + * The string to escape. + * @return {string} The escaped string. + */ +function escapeXML(str) { + const replacements = {"&": "&", "\"": """, "'": "'", "<": "<", ">": ">"}; + return String(str).replace(/[&"''<>]/g, m => replacements[m]); +} + +/** + * A tagged template function which escapes any XML metacharacters in + * interpolated values. + * + * @param {Array} strings + * An array of literal strings extracted from the templates. + * @param {Array} values + * An array of interpolated values extracted from the template. + * @returns {string} + * The result of the escaped values interpolated with the literal + * strings. + */ +function escaped(strings, ...values) { + const result = []; + + for (const [i, string] of strings.entries()) { + result.push(string); + if (i < values.length) + result.push(escapeXML(values[i])); + } + + return result.join(""); +} + // This object controls all the panels, identities and many other things. const Logic = { _identities: [], @@ -235,7 +271,7 @@ Logic.registerPanel(P_CONTAINERS_LIST, { tr.classList.add("container-panel-row"); context.classList.add("userContext-wrapper", "open-newtab", "clickable"); manage.classList.add("show-tabs", "pop-button"); - context.innerHTML = ` + context.innerHTML = escaped`
${tab.title}`; @@ -422,7 +458,7 @@ Logic.registerPanel(P_CONTAINERS_EDIT, { const tr = document.createElement("tr"); fragment.appendChild(tr); tr.classList.add("container-panel-row"); - tr.innerHTML = ` + tr.innerHTML = escaped`
{ - return ` + return escaped`