Bug 1273184 - Don't allow reloading of unsupported add-ons. r=ochameau
authorKumar McMillan <kumar.mcmillan@gmail.com>
Mon, 16 May 2016 16:08:46 -0500
changeset 298145 18f8aacfdc9d7106183ebb80c8a19124f2189680
parent 298144 4217fe06545364658570efadb1ff8d8956241bc8
child 298146 eb54f97ddfd410d426df5989a8ddd962d97bee44
push id77042
push userryanvm@gmail.com
push dateThu, 19 May 2016 16:50:24 +0000
treeherdermozilla-inbound@159d29866810 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersochameau
bugs1273184
milestone49.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 1273184 - Don't allow reloading of unsupported add-ons. r=ochameau MozReview-Commit-ID: ERSpt8X9MD8
devtools/client/aboutdebugging/components/addons/panel.js
devtools/client/aboutdebugging/components/addons/target.js
devtools/client/aboutdebugging/test/addons/bug1273184.xpi
devtools/client/aboutdebugging/test/browser.ini
devtools/client/aboutdebugging/test/browser_addons_reload.js
devtools/client/locales/en-US/aboutdebugging.properties
devtools/server/actors/addon.js
--- a/devtools/client/aboutdebugging/components/addons/panel.js
+++ b/devtools/client/aboutdebugging/components/addons/panel.js
@@ -62,17 +62,18 @@ module.exports = createClass({
   updateAddonsList() {
     this.props.client.listAddons()
       .then(({addons}) => {
         let extensions = addons.filter(addon => addon.debuggable).map(addon => {
           return {
             name: addon.name,
             icon: addon.iconURL || ExtensionIcon,
             addonID: addon.id,
-            addonActor: addon.actor
+            addonActor: addon.actor,
+            temporarilyInstalled: addon.temporarilyInstalled
           };
         });
 
         this.setState({ extensions });
       }, error => {
         throw new Error("Client error while listing addons: " + error);
       });
   },
--- a/devtools/client/aboutdebugging/components/addons/target.js
+++ b/devtools/client/aboutdebugging/components/addons/target.js
@@ -35,16 +35,18 @@ module.exports = createClass({
     }).then(() => {}, error => {
       throw new Error(
         "Error reloading addon " + target.addonID + ": " + error);
     });
   },
 
   render() {
     let { target, debugDisabled } = this.props;
+    // Only temporarily installed add-ons can be reloaded.
+    const canBeReloaded = target.temporarilyInstalled;
 
     return dom.li({ className: "target-container" },
       dom.img({
         className: "target-icon",
         role: "presentation",
         src: target.icon
       }),
       dom.div({ className: "target" },
@@ -52,13 +54,16 @@ module.exports = createClass({
       ),
       dom.button({
         className: "debug-button",
         onClick: this.debug,
         disabled: debugDisabled,
       }, Strings.GetStringFromName("debug")),
       dom.button({
         className: "reload-button",
-        onClick: this.reload
+        onClick: this.reload,
+        disabled: !canBeReloaded,
+        title: !canBeReloaded ?
+          Strings.GetStringFromName("reloadDisabledTooltip") : ""
       }, Strings.GetStringFromName("reload"))
     );
   }
 });
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..946422b6f188b1c597d7d59236b076c3949706ac
GIT binary patch
literal 280
zc$^FHW@Zs#U|`^2m{GC8!!T$2#0(&B8W8g`$S~w4=4Ga(7MJK{73b%LhHx@4-&eN^
z{|CgS72FJrEMFNJ7{J<BKMM*7IOTihw2!y0UZ=jduGYCT=Yux|8C+uYe4_en8Iz@#
z=hBy4ZEnwwwTY>DC2+PlsXE&-cSIyPI{Kv*C2<Dqk<bX_6=CjLwp=a!`Qe=ojb}tw
zbOtcXdNr7dYd0><-s!Mo8aG3LHzSiAGcE^9Fn|EiO$<vKK`b=qvqGGY=JWt>RyK$>
MMuuP@y&h}`09TPrj{pDw
--- a/devtools/client/aboutdebugging/test/browser.ini
+++ b/devtools/client/aboutdebugging/test/browser.ini
@@ -1,16 +1,17 @@
 [DEFAULT]
 tags = devtools
 subsuite = devtools
 support-files =
   head.js
   addons/unpacked/bootstrap.js
   addons/unpacked/install.rdf
   addons/bad/manifest.json
+  addons/bug1273184.xpi
   service-workers/empty-sw.html
   service-workers/empty-sw.js
   service-workers/push-sw.html
   service-workers/push-sw.js
 
 [browser_addons_debug_bootstrapped.js]
 [browser_addons_debugging_initial_state.js]
 [browser_addons_install.js]
--- a/devtools/client/aboutdebugging/test/browser_addons_reload.js
+++ b/devtools/client/aboutdebugging/test/browser_addons_reload.js
@@ -17,26 +17,58 @@ function promiseAddonEvent(event) {
         resolve(args);
       }
     };
 
     AddonManager.addAddonListener(listener);
   });
 }
 
+function* tearDownAddon(addon) {
+  const onUninstalled = promiseAddonEvent("onUninstalled");
+  addon.uninstall();
+  const [uninstalledAddon] = yield onUninstalled;
+  is(uninstalledAddon.id, addon.id,
+     `Add-on was uninstalled: ${uninstalledAddon.id}`);
+}
+
 function getReloadButton(document, addonName) {
   const names = [...document.querySelectorAll("#addons .target-name")];
   const name = names.filter(element => element.textContent === addonName)[0];
   ok(name, `Found ${addonName} add-on in the list`);
   const targetElement = name.parentNode.parentNode;
   const reloadButton = targetElement.querySelector(".reload-button");
   info(`Found reload button for ${addonName}`);
   return reloadButton;
 }
 
+function installAddonWithManager(filePath) {
+  return new Promise((resolve, reject) => {
+    AddonManager.getInstallForFile(filePath, install => {
+      if (!install) {
+        throw new Error(`An install was not created for ${filePath}`);
+      }
+      install.addListener({
+        onDownloadFailed: reject,
+        onDownloadCancelled: reject,
+        onInstallFailed: reject,
+        onInstallCancelled: reject,
+        onInstallEnded: resolve
+      });
+      install.install();
+    });
+  });
+}
+
+function getAddonByID(addonId) {
+  return new Promise(resolve => {
+    AddonManager.getAddonByID(addonId, addon => resolve(addon));
+  });
+}
+
 /**
  * Creates a web extension from scratch in a temporary location.
  * The object must be removed when you're finished working with it.
  */
 class TempWebExt {
   constructor(addonId) {
     this.addonId = addonId;
     this.tmpDir = FileUtils.getDir("TmpD", ["browser_addons_reload"]);
@@ -76,16 +108,18 @@ class TempWebExt {
 
 add_task(function* reloadButtonReloadsAddon() {
   const { tab, document } = yield openAboutDebugging("addons");
   yield waitForInitialAddonList(document);
   yield installAddon(document, "addons/unpacked/install.rdf",
                      ADDON_NAME, ADDON_NAME);
 
   const reloadButton = getReloadButton(document, ADDON_NAME);
+  is(reloadButton.disabled, false, "Reload button should not be disabled");
+  is(reloadButton.title, "", "Reload button should not have a tooltip");
   const onInstalled = promiseAddonEvent("onInstalled");
 
   const onBootstrapInstallCalled = new Promise(done => {
     Services.obs.addObserver(function listener() {
       Services.obs.removeObserver(listener, ADDON_NAME, false);
       info("Add-on was re-installed: " + ADDON_NAME);
       done();
     }, ADDON_NAME, false);
@@ -93,24 +127,17 @@ add_task(function* reloadButtonReloadsAd
 
   reloadButton.click();
 
   const [reloadedAddon] = yield onInstalled;
   is(reloadedAddon.name, ADDON_NAME,
      "Add-on was reloaded: " + reloadedAddon.name);
 
   yield onBootstrapInstallCalled;
-
-  info("Uninstall addon installed earlier.");
-  const onUninstalled = promiseAddonEvent("onUninstalled");
-  reloadedAddon.uninstall();
-  const [uninstalledAddon] = yield onUninstalled;
-  is(uninstalledAddon.id, ADDON_ID,
-     "Add-on was uninstalled: " + uninstalledAddon.id);
-
+  yield tearDownAddon(reloadedAddon);
   yield closeAboutDebugging(tab);
 });
 
 add_task(function* reloadButtonRefreshesMetadata() {
   const { tab, document } = yield openAboutDebugging("addons");
   yield waitForInitialAddonList(document);
 
   const manifestBase = {
@@ -148,15 +175,30 @@ add_task(function* reloadButtonRefreshes
   yield onAddonReloaded;
   const [reloadedAddon] = yield onReInstall;
   // Make sure the name was updated correctly.
   const allAddons = [...document.querySelectorAll("#addons .target-name")]
     .map(element => element.textContent);
   const nameWasUpdated = allAddons.some(name => name === newName);
   ok(nameWasUpdated, `New name appeared in reloaded add-ons: ${allAddons}`);
 
-  const onUninstalled = promiseAddonEvent("onUninstalled");
-  reloadedAddon.uninstall();
-  yield onUninstalled;
-
+  yield tearDownAddon(reloadedAddon);
   tempExt.remove();
   yield closeAboutDebugging(tab);
 });
+
+add_task(function* onlyTempInstalledAddonsCanBeReloaded() {
+  const { tab, document } = yield openAboutDebugging("addons");
+  yield waitForInitialAddonList(document);
+  const onAddonListUpdated = waitForMutation(getAddonList(document),
+                                             { childList: true });
+  yield installAddonWithManager(getSupportsFile("addons/bug1273184.xpi").file);
+  yield onAddonListUpdated;
+  const addon = yield getAddonByID("bug1273184@tests");
+
+  const reloadButton = getReloadButton(document, addon.name);
+  ok(reloadButton, "Reload button exists");
+  is(reloadButton.disabled, true, "Reload button should be disabled");
+  ok(reloadButton.title, "Disabled reload button should have a tooltip");
+
+  yield tearDownAddon(addon);
+  yield closeAboutDebugging(tab);
+});
--- a/devtools/client/locales/en-US/aboutdebugging.properties
+++ b/devtools/client/locales/en-US/aboutdebugging.properties
@@ -12,16 +12,17 @@ unregister = unregister
 addons = Add-ons
 addonDebugging.label = Enable add-on debugging
 addonDebugging.tooltip = Turning this on will allow you to debug add-ons and various other parts of the browser chrome
 addonDebugging.moreInfo = more info
 loadTemporaryAddon = Load Temporary Add-on
 extensions = Extensions
 selectAddonFromFile2 = Select Manifest File or Package (.xpi)
 reload = Reload
+reloadDisabledTooltip = Only temporarily installed add-ons can be reloaded
 
 workers = Workers
 serviceWorkers = Service Workers
 sharedWorkers = Shared Workers
 otherWorkers = Other Workers
 
 tabs = Tabs
 
--- a/devtools/server/actors/addon.js
+++ b/devtools/server/actors/addon.js
@@ -80,16 +80,17 @@ BrowserAddonActor.prototype = {
 
     return {
       actor: this.actorID,
       id: this.id,
       name: this._addon.name,
       url: this.url,
       iconURL: this._addon.iconURL,
       debuggable: this._addon.isDebuggable,
+      temporarilyInstalled: this._addon.temporarilyInstalled,
       consoleActor: this._consoleActor.actorID,
 
       traits: {
         highlightable: false,
         networkMonitor: false,
       },
     };
   },