From 50f849ca2b9726976b5e17dbd2190857f8b5bcc8 Mon Sep 17 00:00:00 2001 From: Andrew Swan Date: Wed, 15 Feb 2017 15:40:56 -0800 Subject: [PATCH] Bug 1334096 Show permissions prompts when a sideloaded extension is enabled r=mossop MozReview-Commit-ID: 1yXgkBg6W1p --HG-- extra : rebase_source : 5eb54baafbf80e79c2901ff23eecfa9f017ee22f --- .../general/browser_extension_sideloading.js | 112 ++++++++++++++++-- browser/modules/ExtensionsUI.jsm | 20 ++++ .../mozapps/extensions/content/extensions.js | 20 ++++ .../mozapps/extensions/content/extensions.xml | 6 +- 4 files changed, 149 insertions(+), 9 deletions(-) diff --git a/browser/base/content/test/general/browser_extension_sideloading.js b/browser/base/content/test/general/browser_extension_sideloading.js index 0beb5ba296d0..3eae07be6441 100644 --- a/browser/base/content/test/general/browser_extension_sideloading.js +++ b/browser/base/content/test/general/browser_extension_sideloading.js @@ -31,6 +31,7 @@ class MockAddon { set userDisabled(val) { this._userDisabled = val; + AddonManagerPrivate.callAddonListeners(val ? "onDisabled" : "onEnabled", this); let fn = setCallbacks.get(this); if (fn) { setCallbacks.delete(this); @@ -133,7 +134,33 @@ add_task(function* () { }, }); - let provider = new MockProvider(mock1, mock2); + const ID3 = "addon3@tests.mozilla.org"; + let mock3 = new MockAddon({ + id: ID3, + name: "Test 3", + isWebExtension: true, + userDisabled: true, + seen: false, + userPermissions: { + permissions: [], + hosts: [""], + } + }); + + const ID4 = "addon4@tests.mozilla.org"; + let mock4 = new MockAddon({ + id: ID4, + name: "Test 4", + isWebExtension: true, + userDisabled: true, + seen: false, + userPermissions: { + permissions: [], + hosts: [""], + } + }); + + let provider = new MockProvider(mock1, mock2, mock3, mock4); AddonManagerPrivate.registerProvider(provider, [{ id: "extension", name: "Extensions", @@ -178,7 +205,7 @@ add_task(function* () { yield PanelUI.show(); let addons = document.getElementById("PanelUI-footer-addons"); - is(addons.children.length, 2, "Have 2 menu entries for sideloaded extensions"); + is(addons.children.length, 4, "Have 4 menu entries for sideloaded extensions"); // Click the first sideloaded extension let popupPromise = promisePopupNotificationShown("addon-webext-permissions"); @@ -204,26 +231,26 @@ add_task(function* () { let value = yield disablePromise; is(value, true, "Addon should remain disabled"); - let [addon1, addon2] = yield AddonManager.getAddonsByIDs([ID1, ID2]); + let [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]); ok(addon1.seen, "Addon should be marked as seen"); is(addon1.userDisabled, true, "Addon 1 should still be disabled"); is(addon2.userDisabled, true, "Addon 2 should still be disabled"); + is(addon3.userDisabled, true, "Addon 3 should still be disabled"); + is(addon4.userDisabled, true, "Addon 4 should still be disabled"); yield BrowserTestUtils.removeTab(gBrowser.selectedTab); - // Should still have 1 entry in the hamburger menu + // Should still have 3 entries in the hamburger menu yield PanelUI.show(); addons = document.getElementById("PanelUI-footer-addons"); - is(addons.children.length, 1, "Have 1 menu entry for sideloaded extensions"); + is(addons.children.length, 3, "Have 3 menu entries for sideloaded extensions"); // Click the second sideloaded extension and wait for the notification popupPromise = promisePopupNotificationShown("addon-webext-permissions"); addons.children[0].click(); panel = yield popupPromise; - isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge"); - // Again we should be at the extentions list in about:addons is(gBrowser.currentURI.spec, "about:addons", "Foreground tab is at about:addons"); @@ -240,9 +267,78 @@ add_task(function* () { value = yield disablePromise; is(value, false, "Addon should be set to enabled"); - [addon1, addon2] = yield AddonManager.getAddonsByIDs([ID1, ID2]); + [addon1, addon2, addon3, addon4] = yield AddonManager.getAddonsByIDs([ID1, ID2, ID3, ID4]); is(addon1.userDisabled, true, "Addon 1 should still be disabled"); is(addon2.userDisabled, false, "Addon 2 should now be enabled"); + is(addon3.userDisabled, true, "Addon 3 should still be disabled"); + is(addon4.userDisabled, true, "Addon 4 should still be disabled"); + + // Should still have 2 entries in the hamburger menu + yield PanelUI.show(); + + addons = document.getElementById("PanelUI-footer-addons"); + is(addons.children.length, 2, "Have 2 menu entries for sideloaded extensions"); + + // Close the hamburger menu and go directly to the addons manager + yield PanelUI.hide(); + + win = yield BrowserOpenAddonsMgr(VIEW); + + let list = win.document.getElementById("addon-list"); + + // Make sure XBL bindings are applied + list.clientHeight; + + let item = list.children.find(_item => _item.value == ID3); + ok(item, "Found entry for sideloaded extension in about:addons"); + item.scrollIntoView({behavior: "instant"}); + + ok(is_visible(item._enableBtn), "Enable button is visible for sideloaded extension"); + ok(is_hidden(item._disableBtn), "Disable button is not visible for sideloaded extension"); + + // When clicking enable we should see the permissions notification + popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + BrowserTestUtils.synthesizeMouseAtCenter(item._enableBtn, {}, + gBrowser.selectedBrowser); + panel = yield popupPromise; + + // Accept the permissions + disablePromise = promiseSetDisabled(mock3); + panel.button.click(); + value = yield disablePromise; + is(value, false, "userDisabled should be set on addon 3"); + + addon3 = yield AddonManager.getAddonByID(ID3); + is(addon3.userDisabled, false, "Addon 3 should be enabled"); + + // Should still have 1 entry in the hamburger menu + yield PanelUI.show(); + + addons = document.getElementById("PanelUI-footer-addons"); + is(addons.children.length, 1, "Have 1 menu entry for sideloaded extensions"); + + // Close the hamburger menu and go to the detail page for this addon + yield PanelUI.hide(); + + win = yield BrowserOpenAddonsMgr(`addons://detail/${encodeURIComponent(ID4)}`); + let button = win.document.getElementById("detail-enable-btn"); + + // When clicking enable we should see the permissions notification + popupPromise = promisePopupNotificationShown("addon-webext-permissions"); + BrowserTestUtils.synthesizeMouseAtCenter(button, {}, + gBrowser.selectedBrowser); + panel = yield popupPromise; + + // Accept the permissions + disablePromise = promiseSetDisabled(mock4); + panel.button.click(); + value = yield disablePromise; + is(value, false, "userDisabled should be set on addon 4"); + + addon4 = yield AddonManager.getAddonByID(ID4); + is(addon4.userDisabled, false, "Addon 4 should be enabled"); + + isnot(menuButton.getAttribute("badge-status"), "addon-alert", "Should no longer have addon alert badge"); yield BrowserTestUtils.removeTab(gBrowser.selectedTab); }); diff --git a/browser/modules/ExtensionsUI.jsm b/browser/modules/ExtensionsUI.jsm index c5a9dd4cc744..34c052484491 100644 --- a/browser/modules/ExtensionsUI.jsm +++ b/browser/modules/ExtensionsUI.jsm @@ -32,6 +32,7 @@ const HTML_NS = "http://www.w3.org/1999/xhtml"; this.ExtensionsUI = { sideloaded: new Set(), updates: new Set(), + sideloadListener: null, init() { Services.obs.addObserver(this, "webextension-permission-prompt", false); @@ -53,6 +54,25 @@ this.ExtensionsUI = { } if (WEBEXT_PERMISSION_PROMPTS) { + if (!this.sideloadListener) { + this.sideloadListener = { + onEnabled: addon => { + if (!this.sideloaded.has(addon)) { + return; + } + + this.sideloaded.delete(addon); + this.emit("change"); + + if (this.sideloaded.size == 0) { + AddonManager.removeAddonListener(this.sideloadListener); + this.sideloadListener = null; + } + }, + }; + AddonManager.addAddonListener(this.sideloadListener); + } + for (let addon of sideloaded) { this.sideloaded.add(addon); } diff --git a/toolkit/mozapps/extensions/content/extensions.js b/toolkit/mozapps/extensions/content/extensions.js index 6f74c1d2117a..2a6713d91165 100644 --- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -1278,6 +1278,26 @@ var gViewController = { hasPermission(aAddon, "enable")); }, doCommand(aAddon) { + if (aAddon.isWebExtension && !aAddon.seen && WEBEXT_PERMISSION_PROMPTS) { + let perms = aAddon.userPermissions; + if (perms.hosts.length > 0 || perms.permissions.length > 0) { + let subject = { + wrappedJSObject: { + target: getBrowserElement(), + info: { + type: "sideload", + addon: aAddon, + icon: aAddon.iconURL, + permissions: perms, + resolve() { aAddon.userDisabled = false }, + reject() {}, + }, + }, + }; + Services.obs.notifyObservers(subject, "webextension-permission-prompt", null); + return; + } + } aAddon.userDisabled = false; }, getTooltip(aAddon) { diff --git a/toolkit/mozapps/extensions/content/extensions.xml b/toolkit/mozapps/extensions/content/extensions.xml index 350bf37acb00..7240a7bdaae7 100644 --- a/toolkit/mozapps/extensions/content/extensions.xml +++ b/toolkit/mozapps/extensions/content/extensions.xml @@ -1108,7 +1108,11 @@ return this.mAddon.userDisabled; ]]>