Bug 1149702 - Display a note about add-ons that aren't properly signed in the add-ons manager. r=mossop
authorDão Gottwald <dao@mozilla.com>
Thu, 30 Apr 2015 21:17:39 +0200
changeset 273226 65afb97fc3990a0f54e1d4a5265a0ec09d1e07e6
parent 273225 002bcc21b3543cae4a993292a019f393b0a3db86
child 273227 a375bdb7fb5d38a5d8829d226a1a3090d2952d5e
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmossop
bugs1149702
milestone40.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 1149702 - Display a note about add-ons that aren't properly signed in the add-ons manager. r=mossop
modules/libpref/init/all.js
toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/content/extensions.xml
toolkit/mozapps/extensions/test/browser/browser_details.js
toolkit/mozapps/extensions/test/browser/browser_list.js
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -4113,16 +4113,17 @@ pref("browser.history.allowPushState", t
 pref("browser.history.allowReplaceState", true);
 pref("browser.history.allowPopState", true);
 pref("browser.history.maxStateObjectSize", 655360);
 
 // XPInstall prefs
 pref("xpinstall.whitelist.required", true);
 // Only Firefox requires add-on signatures
 pref("xpinstall.signatures.required", false);
+pref("xpinstall.signatures.infoURL", "https://wiki.mozilla.org/Addons/Extension_Signing");
 pref("extensions.alwaysUnpack", false);
 pref("extensions.minCompatiblePlatformVersion", "2.0");
 
 pref("network.buffer.cache.count", 24);
 pref("network.buffer.cache.size",  32768);
 
 // Desktop Notification
 pref("notification.feature.enabled", false);
--- a/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/extensions/extensions.properties
@@ -18,16 +18,20 @@ uninstallNotice=%S has been removed.
 # #1 is the number of reviews
 numReviews=#1 review;#1 reviews
 
 #LOCALIZATION NOTE (dateUpdated) %S is the date the addon was last updated
 dateUpdated=Updated %S
 
 #LOCALIZATION NOTE (notification.incompatible) %1$S is the add-on name, %2$S is brand name, %3$S is application version
 notification.incompatible=%1$S is incompatible with %2$S %3$S.
+#LOCALIZATION NOTE (notification.unsigned, notification.unsignedAndDisabled) %1$S is the add-on name, %2$S is brand name
+notification.unsignedAndDisabled=%1$S could not be verified for use in %2$S and has been disabled.
+notification.unsigned=%1$S could not be verified for use in %2$S. Proceed with caution.
+notification.unsigned.link=More Information
 #LOCALIZATION NOTE (notification.blocked) %1$S is the add-on name
 notification.blocked=%1$S has been disabled due to security or stability issues.
 notification.blocked.link=More Information
 #LOCALIZATION NOTE (notification.softblocked) %1$S is the add-on name
 notification.softblocked=%1$S is known to cause security or stability issues.
 notification.softblocked.link=More Information
 #LOCALIZATION NOTE (notification.outdated) %1$S is the add-on name
 notification.outdated=An important update is available for %1$S.
@@ -69,16 +73,20 @@ installVerifying=Verifying
 installInstalling=Installing
 installEnablePending=Restart to enable
 installDisablePending=Restart to disable
 installFailed=Error installing
 installCancelled=Install cancelled
 
 #LOCALIZATION NOTE (details.notification.incompatible) %1$S is the add-on name, %2$S is brand name, %3$S is application version
 details.notification.incompatible=%1$S is incompatible with %2$S %3$S.
+#LOCALIZATION NOTE (details.notification.unsigned, details.notification.unsignedAndDisabled) %1$S is the add-on name, %2$S is brand name
+details.notification.unsignedAndDisabled=%1$S could not be verified for use in %2$S and has been disabled.
+details.notification.unsigned=%1$S could not be verified for use in %2$S. Proceed with caution.
+details.notification.unsigned.link=More Information
 #LOCALIZATION NOTE (details.notification.blocked) %1$S is the add-on name
 details.notification.blocked=%1$S has been disabled due to security or stability issues.
 details.notification.blocked.link=More Information
 #LOCALIZATION NOTE (details.notification.softblocked) %1$S is the add-on name
 details.notification.softblocked=%1$S is known to cause security or stability issues.
 details.notification.softblocked.link=More Information
 #LOCALIZATION NOTE (details.notification.outdated) %1$S is the add-on name
 details.notification.outdated=An important update is available for %1$S.
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3068,16 +3068,27 @@ var gDetailView = {
         document.getElementById("detail-error").textContent = gStrings.ext.formatStringFromName(
           "details.notification.blocked",
           [this._addon.name], 1
         );
         var errorLink = document.getElementById("detail-error-link");
         errorLink.value = gStrings.ext.GetStringFromName("details.notification.blocked.link");
         errorLink.href = this._addon.blocklistURL;
         errorLink.hidden = false;
+      } else if (this._addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
+        let msgType = this._addon.appDisabled ? "error" : "warning";
+        this.node.setAttribute("notification", msgType);
+        document.getElementById("detail-" + msgType).textContent = gStrings.ext.formatStringFromName(
+          "details.notification.unsigned" + (this._addon.appDisabled ? "AndDisabled" : ""),
+          [this._addon.name, gStrings.brandShortName], 2
+        );
+        var infoLink = document.getElementById("detail-" + msgType + "-link");
+        infoLink.value = gStrings.ext.GetStringFromName("details.notification.unsigned.link");
+        infoLink.href = Services.prefs.getCharPref("xpinstall.signatures.infoURL");
+        infoLink.hidden = false;
       } else if (!this._addon.isCompatible && (AddonManager.checkCompatibility ||
         (this._addon.blocklistState != Ci.nsIBlocklistService.STATE_SOFTBLOCKED))) {
         this.node.setAttribute("notification", "warning");
         document.getElementById("detail-warning").textContent = gStrings.ext.formatStringFromName(
           "details.notification.incompatible",
           [this._addon.name, gStrings.brandShortName, gStrings.appVersion], 3
         );
         document.getElementById("detail-warning-link").hidden = true;
@@ -3332,16 +3343,17 @@ var gDetailView = {
   onPropertyChanged: function gDetailView_onPropertyChanged(aProperties) {
     if (aProperties.indexOf("applyBackgroundUpdates") != -1) {
       this._autoUpdate.value = this._addon.applyBackgroundUpdates;
       let hideFindUpdates = AddonManager.shouldAutoUpdate(this._addon);
       document.getElementById("detail-findUpdates-btn").hidden = hideFindUpdates;
     }
 
     if (aProperties.indexOf("appDisabled") != -1 ||
+        aProperties.indexOf("signedState") != -1 ||
         aProperties.indexOf("userDisabled") != -1)
       this.updateState();
   },
 
   onExternalInstall: function gDetailView_onExternalInstall(aAddon, aExistingAddon, aNeedsRestart) {
     // Only care about upgrades for the currently displayed add-on
     if (!aExistingAddon || aExistingAddon.id != this._addon.id)
       return;
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -1242,16 +1242,28 @@
               this.setAttribute("notification", "error");
               this._error.textContent = gStrings.ext.formatStringFromName(
                 "notification.blocked",
                 [this.mAddon.name], 1
               );
               this._errorLink.value = gStrings.ext.GetStringFromName("notification.blocked.link");
               this._errorLink.href = this.mAddon.blocklistURL;
               this._errorLink.hidden = false;
+            } else if (!isUpgrade &&
+                       this.mAddon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
+              this.setAttribute("notification", this.mAddon.appDisabled ? "error" : "warning");
+              let msg = this.mAddon.appDisabled ? this._error : this._warning;
+              msg.textContent = gStrings.ext.formatStringFromName(
+                "notification.unsigned" + (this.mAddon.appDisabled ? "AndDisabled" : ""),
+                [this.mAddon.name, gStrings.brandShortName], 2
+              );
+              let infoLink = this.mAddon.appDisabled ? this._errorLink : this._warningLink;
+              infoLink.value = gStrings.ext.GetStringFromName("notification.unsigned.link");
+              infoLink.href = Services.prefs.getCharPref("xpinstall.signatures.infoURL");
+              infoLink.hidden = false;
             } else if ((!isUpgrade && !this.mAddon.isCompatible) && (AddonManager.checkCompatibility
             || (this.mAddon.blocklistState != Ci.nsIBlocklistService.STATE_SOFTBLOCKED))) {
               this.setAttribute("notification", "warning");
               this._warning.textContent = gStrings.ext.formatStringFromName(
                 "notification.incompatible",
                 [this.mAddon.name, gStrings.brandShortName, gStrings.appVersion], 3
               );
               this._warningLink.hidden = true;
@@ -1642,16 +1654,17 @@
           this._updateState();
         ]]></body>
       </method>
 
       <method name="onPropertyChanged">
         <parameter name="aProperties"/>
         <body><![CDATA[
           if (aProperties.indexOf("appDisabled") != -1 ||
+              aProperties.indexOf("signedState") != -1 ||
               aProperties.indexOf("userDisabled") != -1)
             this._updateState();
         ]]></body>
       </method>
 
       <method name="onNoUpdateAvailable">
         <body><![CDATA[
           this._showStatus("none");
--- a/toolkit/mozapps/extensions/test/browser/browser_details.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_details.js
@@ -139,16 +139,26 @@ function test() {
     _userDisabled: true,
     isActive: false
   }, {
     id: "addon8@tests.mozilla.org",
     blocklistURL: "http://example.com/addon8@tests.mozilla.org",
     name: "Test add-on 8",
     blocklistState: Ci.nsIBlocklistService.STATE_OUTDATED
   }, {
+    id: "addon9@tests.mozilla.org",
+    name: "Test add-on 9",
+    signedState: AddonManager.SIGNEDSTATE_MISSING,
+  }, {
+    id: "addon10@tests.mozilla.org",
+    name: "Test add-on 10",
+    signedState: AddonManager.SIGNEDSTATE_MISSING,
+    isActive: false,
+    appDisabled: true,
+  }, {
     id: "hotfix@tests.mozilla.org",
     name: "Test hotfix 1",
   }]);
 
   open_manager(null, function(aWindow) {
     gManagerWindow = aWindow;
     gCategoryUtilities = new CategoryUtilities(gManagerWindow);
 
@@ -681,16 +691,62 @@ add_test(function() {
       is_element_hidden(get("detail-error-link"), "Error link should be hidden");
       is_element_hidden(get("detail-pending"), "Pending message should be hidden");
 
       run_next_test();
     });
   });
 });
 
+// Opens and tests the details view for add-on 9
+add_test(function() {
+  open_details("addon9@tests.mozilla.org", "extension", function() {
+    is(get("detail-name").textContent, "Test add-on 9", "Name should be correct");
+
+    is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+    is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+    is_element_visible(get("detail-disable-btn"), "Disable button should be visible");
+    is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+    is_element_hidden(get("detail-error"), "Error message should be hidden");
+    is_element_hidden(get("detail-error-link"), "Error link should be hidden");
+    is_element_visible(get("detail-warning"), "Error message should be visible");
+    is(get("detail-warning").textContent, "Test add-on 9 could not be verified for use in " + gApp + ". Proceed with caution.", "Warning message should be correct");
+    is_element_visible(get("detail-warning-link"), "Warning link should be visible");
+    is(get("detail-warning-link").value, "More Information", "Warning link text should be correct");
+    is(get("detail-warning-link").href, Services.prefs.getCharPref("xpinstall.signatures.infoURL"), "Warning link should be correct");
+    is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+    run_next_test();
+  });
+});
+
+// Opens and tests the details view for add-on 10
+add_test(function() {
+  open_details("addon10@tests.mozilla.org", "extension", function() {
+    is(get("detail-name").textContent, "Test add-on 10", "Name should be correct");
+
+    is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
+    is_element_hidden(get("detail-enable-btn"), "Enable button should be hidden");
+    is_element_hidden(get("detail-disable-btn"), "Disable button should be hidden");
+    is_element_visible(get("detail-uninstall-btn"), "Remove button should be visible");
+
+    is_element_hidden(get("detail-warning"), "Warning message should be hidden");
+    is_element_hidden(get("detail-warning-link"), "Warning link should be hidden");
+    is_element_visible(get("detail-error"), "Error message should be visible");
+    is(get("detail-error").textContent, "Test add-on 10 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+    is_element_visible(get("detail-error-link"), "Error link should be visible");
+    is(get("detail-error-link").value, "More Information", "Error link text should be correct");
+    is(get("detail-error-link").href, Services.prefs.getCharPref("xpinstall.signatures.infoURL"), "Error link should be correct");
+    is_element_hidden(get("detail-pending"), "Pending message should be hidden");
+
+    run_next_test();
+  });
+});
+
 // Opens and tests the details view for hotfix 1
 add_test(function() {
   open_details("hotfix@tests.mozilla.org", "extension", function() {
     is(get("detail-name").textContent, "Test hotfix 1", "Name should be correct");
 
     is_element_hidden(get("detail-updates-row"), "Updates should be hidden");
 
     is_element_hidden(get("detail-prefs-btn"), "Preferences button should be hidden");
--- a/toolkit/mozapps/extensions/test/browser/browser_list.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_list.js
@@ -91,16 +91,26 @@ function test() {
     blocklistURL: "http://example.com/addon8@tests.mozilla.org",
     name: "Test add-on 8",
     blocklistState: Ci.nsIBlocklistService.STATE_VULNERABLE_UPDATE_AVAILABLE,
   }, {
     id: "addon9@tests.mozilla.org",
     blocklistURL: "http://example.com/addon9@tests.mozilla.org",
     name: "Test add-on 9",
     blocklistState: Ci.nsIBlocklistService.STATE_VULNERABLE_NO_UPDATE,
+  }, {
+    id: "addon10@tests.mozilla.org",
+    name: "Test add-on 10",
+    signedState: AddonManager.SIGNEDSTATE_MISSING,
+  }, {
+    id: "addon11@tests.mozilla.org",
+    name: "Test add-on 11",
+    signedState: AddonManager.SIGNEDSTATE_MISSING,
+    isActive: false,
+    appDisabled: true,
   }]);
 
   open_manager(null, function(aWindow) {
     gManagerWindow = aWindow;
     gCategoryUtilities = new CategoryUtilities(gManagerWindow);
     run_next_test();
   });
 }
@@ -134,17 +144,17 @@ function get_class_node(parent, cls) {
   return parent.ownerDocument.getAnonymousElementByAttribute(parent, "class", cls);
 }
 
 // Check that the list appears to have displayed correctly and trigger some
 // changes
 add_test(function() {
   gCategoryUtilities.openType("extension", function() {
     let items = get_test_items();
-    is(Object.keys(items).length, 9, "Should be nine add-ons installed");
+    is(Object.keys(items).length, 11, "Should be the right number of add-ons installed");
 
     info("Addon 1");
     let addon = items["Test add-on"];
     addon.parentNode.ensureElementIsVisible(addon);
     is(get_node(addon, "name").value, "Test add-on", "Name should be correct");
     is_element_visible(get_node(addon, "version"), "Version should be visible");
     is(get_node(addon, "version").value, "1.0", "Version should be correct");
     is_element_visible(get_node(addon, "description"), "Description should be visible");
@@ -382,16 +392,54 @@ add_test(function() {
     is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
     is_element_visible(get_node(addon, "error"), "Error message should be visible");
     is(get_node(addon, "error").textContent, "Test add-on 9 is known to be vulnerable. Use with caution.", "Error message should be correct");
     is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
     is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
     is(get_node(addon, "error-link").href, "http://example.com/addon9@tests.mozilla.org", "Error link should be correct");
     is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
 
+    info("Addon 10");
+    addon = items["Test add-on 10"];
+    addon.parentNode.ensureElementIsVisible(addon);
+    is(get_node(addon, "name").value, "Test add-on 10", "Name should be correct");
+
+    is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+    is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+    is_element_visible(get_node(addon, "disable-btn"), "Disable button should be visible");
+    is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+    is_element_visible(get_node(addon, "warning"), "Warning message should be visible");
+    is(get_node(addon, "warning").textContent, "Test add-on 10 could not be verified for use in " + gApp + ". Proceed with caution.", "Warning message should be correct");
+    is_element_visible(get_node(addon, "warning-link"), "Warning link should be visible");
+    is(get_node(addon, "warning-link").value, "More Information", "Warning link text should be correct");
+    is(get_node(addon, "warning-link").href, Services.prefs.getCharPref("xpinstall.signatures.infoURL"), "Warning link should be correct");
+    is_element_hidden(get_node(addon, "error"), "Error message should be hidden");
+    is_element_hidden(get_node(addon, "error-link"), "Error link should be hidden");
+    is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
+    info("Addon 11");
+    addon = items["Test add-on 11"];
+    addon.parentNode.ensureElementIsVisible(addon);
+    is(get_node(addon, "name").value, "Test add-on 11", "Name should be correct");
+
+    is_element_hidden(get_node(addon, "preferences-btn"), "Preferences button should be hidden");
+    is_element_hidden(get_node(addon, "enable-btn"), "Enable button should be hidden");
+    is_element_hidden(get_node(addon, "disable-btn"), "Disable button should be hidden");
+    is_element_visible(get_node(addon, "remove-btn"), "Remove button should be visible");
+
+    is_element_hidden(get_node(addon, "warning"), "Warning message should be hidden");
+    is_element_hidden(get_node(addon, "warning-link"), "Warning link should be hidden");
+    is_element_visible(get_node(addon, "error"), "Error message should be visible");
+    is(get_node(addon, "error").textContent, "Test add-on 11 could not be verified for use in " + gApp + " and has been disabled.", "Error message should be correct");
+    is_element_visible(get_node(addon, "error-link"), "Error link should be visible");
+    is(get_node(addon, "error-link").value, "More Information", "Error link text should be correct");
+    is(get_node(addon, "error-link").href, Services.prefs.getCharPref("xpinstall.signatures.infoURL"), "Error link should be correct");
+    is_element_hidden(get_node(addon, "pending"), "Pending message should be hidden");
+
     run_next_test();
   });
 });
 
 // Check the add-ons are now in the right state
 add_test(function() {
   AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
                                "addon2@tests.mozilla.org",
@@ -407,17 +455,17 @@ add_test(function() {
 });
 
 // Reload the list to make sure the changes are still pending and that undoing
 // works
 add_test(function() {
   gCategoryUtilities.openType("plugin", function() {
     gCategoryUtilities.openType("extension", function() {
       let items = get_test_items();
-      is(Object.keys(items).length, 9, "Should be nine add-ons installed");
+      is(Object.keys(items).length, 11, "Should be the right number of add-ons installed");
 
       info("Addon 1");
       let addon = items["Test add-on"];
       addon.parentNode.ensureElementIsVisible(addon);
       is(get_node(addon, "name").value, "Test add-on", "Name should be correct");
       is_element_visible(get_node(addon, "version"), "Version should be visible");
       is(get_node(addon, "version").value, "1.0", "Version should be correct");
       is_element_visible(get_node(addon, "description"), "Description should be visible");
@@ -611,17 +659,17 @@ add_test(function() {
     name: "Test add-on replacement",
     version: "2.0",
     description: "A test add-on with a new description",
     updateDate: gDate,
     operationsRequiringRestart: AddonManager.OP_NEEDS_RESTART_NONE
   }]);
 
   let items = get_test_items();
-  is(Object.keys(items).length, 9, "Should be nine add-ons installed");
+  is(Object.keys(items).length, 11, "Should be the right number of add-ons installed");
 
   let addon = items["Test add-on replacement"];
   addon.parentNode.ensureElementIsVisible(addon);
   is(get_node(addon, "name").value, "Test add-on replacement", "Name should be correct");
   is_element_visible(get_node(addon, "version"), "Version should be visible");
   is(get_node(addon, "version").value, "2.0", "Version should be correct");
   is_element_visible(get_node(addon, "description"), "Description should be visible");
   is(get_node(addon, "description").value, "A test add-on with a new description", "Description should be correct");