Bug 537180 - Fennec uses old blocklisting URL [r=mfinkle]
authorWesley Johnston <wjohnston@mozilla.com>
Thu, 02 Sep 2010 00:05:22 -0400
changeset 1881 f482950a917df1a9fa07af0dde18390b7b1dccfa
parent 1880 3f2893b0c3cf2a0234c05a3379e21a5b453fe35a
child 1882 13b4414619c242c95220f6103cc97f65180d7006
child 1980 ba736e3dfda04c59697d336f09d404c30ce92cc9
push id1663
push usermfinkle@mozilla.com
push dateThu, 02 Sep 2010 04:04:00 +0000
reviewersmfinkle
bugs537180
Bug 537180 - Fennec uses old blocklisting URL [r=mfinkle]
app/mobile.js
chrome/content/bindings/extensions.xml
chrome/content/extensions.js
components/BlocklistPrompt.js
components/Makefile.in
components/MobileComponents.manifest
locales/en-US/chrome/browser.properties
--- a/app/mobile.js
+++ b/app/mobile.js
@@ -181,17 +181,17 @@ pref("extensions.getAddons.recommended.b
 pref("extensions.getAddons.recommended.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/list/featured/all/10/%OS%/%VERSION%");
 pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/mobile/search?q=%TERMS%");
 pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/mobile/api/%API_VERSION%/search/%TERMS%/all/10/%OS%/%VERSION%");
 pref("extensions.getAddons.browseAddons", "https://addons.mozilla.org/%LOCALE%/mobile/");
 
 /* blocklist preferences */
 pref("extensions.blocklist.enabled", true);
 pref("extensions.blocklist.interval", 86400);
-pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/2/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
+pref("extensions.blocklist.url", "https://addons.mozilla.org/blocklist/3/%APP_ID%/%APP_VERSION%/%PRODUCT%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/");
 pref("extensions.blocklist.detailsURL", "https://www.mozilla.com/%LOCALE%/blocklist/");
 
 /* block popups by default, and notify the user about blocked popups */
 pref("dom.disable_open_during_load", true);
 pref("privacy.popups.showBrowserMessage", true);
 
 pref("keyword.enabled", true);
 pref("keyword.URL", "http://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=");
--- a/chrome/content/bindings/extensions.xml
+++ b/chrome/content/bindings/extensions.xml
@@ -21,17 +21,18 @@
             <xul:label class="title" xbl:inherits="value=name" crop="end" flex="1"/>
             <xul:label class="normal" xbl:inherits="value=version"/>
             <xul:spacer flex="1000"/>
             <xul:label class="normal" xbl:inherits="value=typeLabel"/>
           </xul:hbox>
           <xul:vbox>
             <xul:label class="normal hide-on-select" xbl:inherits="value=description" crop="end" flex="1"/>
             <xul:description class="normal show-on-select" xbl:inherits="xbl:text=description" flex="1"/>
-            <xul:label class="normal-bold" xbl:inherits="value=updateStatus"/>
+            <xul:label class="updateStatus normal-bold" xbl:inherits="value=updateStatus"/>
+            <xul:label class="blockStatus normal-bold" xbl:inherits="value=blockedStatus"/>
           </xul:vbox>
         </xul:vbox>
       </xul:hbox>
       <xul:hbox class="show-on-select buttons-box">
         <xul:button anonid="options-button" type="checkbox" class="addon-options" label="&addonOptions.label;"
                     oncommand="document.getBindingParent(this).toggleOptions();"/>
         <xul:spacer flex="1"/>
         <xul:button anonid="enable-button" class="show-on-disable hide-on-enable hide-on-uninstall addon-enable" label="&addonEnable.label;"
--- a/chrome/content/extensions.js
+++ b/chrome/content/extensions.js
@@ -275,46 +275,60 @@ var ExtensionsView = {
       this.hideOptions();
   },
 
   getAddonsFromLocal: function ev_getAddonsFromLocal() {
     this.clearSection("local");
 
     let self = this;
     AddonManager.getAddonsByTypes(["extension", "theme", "locale"], function(items) {
+      let strings = Elements.browserBundle;
       let anyUpdateable = false;
       for (let i = 0; i < items.length; i++) {
         let addon = items[i];
         let appManaged = (addon.scope == AddonManager.SCOPE_APPLICATION);
         let opType = self._getOpTypeForOperations(addon.pendingOperations);
         let updateable = (addon.permissions & AddonManager.PERM_CAN_UPGRADE) > 0;
         let uninstallable = (addon.permissions & AddonManager.PERM_CAN_UNINSTALL) > 0;
 
+        let blocked = "";
+        switch(addon.blocklistState) {
+          case Ci.nsIBlocklistService.STATE_BLOCKED:
+            blocked = strings.getString("addonBlocked.blocked")
+            break;
+          case Ci.nsIBlocklistService.STATE_SOFTBLOCKED:
+            blocked = strings.getString("addonBlocked.softBlocked");
+            break;
+          case Ci.nsIBlocklistService.STATE_OUTDATED:
+            blocked = srings.getString("addonBlocked.outdated");
+            break;
+        }            
+
         if (updateable)
           anyUpdateable = true;
 
         let listitem = self._createItem(addon, "local");
         listitem.setAttribute("isDisabled", !addon.isActive);
         listitem.setAttribute("appDisabled", addon.appDisabled);
         listitem.setAttribute("appManaged", appManaged);
         listitem.setAttribute("description", addon.description);
         listitem.setAttribute("optionsURL", addon.optionsURL);
         listitem.setAttribute("opType", opType);
         listitem.setAttribute("updateable", updateable);
         listitem.setAttribute("isReadonly", !uninstallable);
+        listitem.setAttribute("blockedStatus", blocked);
         listitem.addon = addon;
         self._list.insertBefore(listitem, self._repoItem);
       }
 
       // Load the search engines
       let defaults = Services.search.getDefaultEngines({ }).map(function (e) e.name);
       function isDefault(aEngine)
         defaults.indexOf(aEngine.name) != -1
 
-      let strings = Elements.browserBundle;
       let defaultDescription = strings.getString("addonsSearchEngine.description");
 
       let engines = Services.search.getEngines({ });
       for (let e = 0; e < engines.length; e++) {
         let engine = engines[e];
         let addon = {};
         addon.id = engine.name;
         addon.type = "search";
@@ -697,22 +711,23 @@ var AddonSearchResults = {
 
 ///////////////////////////////////////////////////////////////////////////////
 // XPInstall download helper
 function AddonInstallListener() {
 }
 
 AddonInstallListener.prototype = {
   _updating: false,
+
   onInstallEnded: function(aInstall, aAddon) {
     // XXX fix updating stuff
     if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL)
       ExtensionsView.showRestart(this._updating ? "update" : "normal");
 
-    this._showAlert(true);
+    this._showInstallCompleteAlert(true);
 
     if (!ExtensionsView.visible)
       return;
 
     let element = ExtensionsView.getElementForAddon(aInstall.sourceURI.spec);
     if (!element)
       return;
 
@@ -726,17 +741,17 @@ AddonInstallListener.prototype = {
       element.removeAttribute("updating");
 
       // Remember that we are updating so we can customize the restart message
       this._updating = true;
     }
   },
 
   onInstallFailed: function(aInstall, aError) {
-    this._showAlert(false);
+    this._showInstallCompleteAlert(false);
 
     if (ExtensionsView.visible) {
       let element = ExtensionsView.getElementForAddon(aInstall.sourceURI.spec);
       if (!element)
         return;
   
       element.removeAttribute("opType");
       let strings = Services.strings.createBundle("chrome://global/locale/xpinstall/xpinstall.properties");
@@ -775,28 +790,59 @@ AddonInstallListener.prototype = {
     let progress = Math.round((aInstall.progress / aInstall.maxProgress) * 100);
     element.setAttribute("progress", progress);
   },
 
   onDownloadFailed: function(aInstall, aError) {
     this.onInstallFailed(aInstall, aError);
   },
 
-  _showAlert: function xpidm_showAlert(aSucceeded) {
+  onDownloadCancelled: function(aInstall, aAddon) {
+    let strings = Elements.browserBundle;
+    let brandBundle = document.getElementById("bundle_brand");
+    let brandShortName = brandBundle.getString("brandShortName");
+    let host = (aInstall.originatingURI instanceof Ci.nsIStandardURL) && aInstall.originatingURI.host;
+    if (!host)
+      host = (aInstall.sourceURI instanceof Ci.nsIStandardURL) && aInstall.sourceURI.host;
+
+    let error = (host || aInstall.error == 0) ? "addonError" : "addonLocalError";
+    if (aInstall.error != 0)
+      error += aInstall.error;
+    else if (aInstall.addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
+      error += "Blocklisted";
+    else
+      error += "Incompatible";
+
+    let messageString = strings.getString(error);
+    messageString = messageString.replace("#1", aInstall.name);
+    if (host)
+      messageString = messageString.replace("#2", host);
+    messageString = messageString.replace("#3", brandShortName);
+    messageString = messageString.replace("#4", Services.appinfo.version);
+    
+    this._showAlert(messageString);
+  },
+
+  _showInstallCompleteAlert: function xpidm_showAlert(aSucceeded) {
+    let strings = Elements.browserBundle;
+    let msg = aSucceeded ? strings.getString("alertAddonsInstalled") :
+                           strings.getString("alertAddonsFail");
+    this._showAlert(msg);
+  },
+  
+  _showAlert: function xpidm_showAlert(aMessage) {
     if (ExtensionsView.visible)
       return;
 
     let strings = Elements.browserBundle;
-    let message = aSucceeded ? strings.getString("alertAddonsInstalled") :
-                               strings.getString("alertAddonsFail");
 
     let observer = {
       observe: function (aSubject, aTopic, aData) {
         if (aTopic == "alertclickcallback")
           BrowserUI.showPanel("addons-container");
       }
     };
 
     let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
     alerts.showAlertNotification(URI_GENERIC_ICON_XPINSTALL, strings.getString("alertAddons"),
-                                 message, true, "", observer, "addons");
+                                 aMessage, true, "", observer, "addons");
   }
 };
new file mode 100644
--- /dev/null
+++ b/components/BlocklistPrompt.js
@@ -0,0 +1,93 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Alerts Service.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Wes Johnston <wjohnston@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+const Cc = Components.classes;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// -----------------------------------------------------------------------
+// BlocklistPrompt Service
+// -----------------------------------------------------------------------
+
+
+function BlocklistPrompt() { }
+
+BlocklistPrompt.prototype = {
+  prompt: function(aAddons, aCount) {
+    let win = Services.wm.getMostRecentWindow("navigator:browser");
+    if (win.ExtensionsView.visible) {
+      win.ExtensionsView.showRestart("blocked");
+    } else {
+      let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+      let notifyBox = win.getNotificationBox();
+      let restartCallback = function(aNotification, aDescription) {
+        // Notify all windows that an application quit has been requested
+        var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
+        Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
+  
+        // If nothing aborted, quit the app
+        if (cancelQuit.data == false) {
+          let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
+          appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
+        }
+      };
+      
+      let buttons = [{accessKey: null,
+                      label: bundle.GetStringFromName("notificationRestart.button"),
+                      callback: restartCallback}];
+      notifyBox.appendNotification(bundle.GetStringFromName("notificationRestart.blocked"),
+                                   "blocked-add-on",
+                                   "",
+                                   "PRIORITY_CRITICAL_HIGH",
+                                   buttons);
+    }
+    // Disable softblocked items automatically
+    for (let i = 0; i < aAddons.length; i++) {
+      if (aAddons[i].item instanceof Ci.nsIPluginTag)
+        addonList[i].item.disabled = true;
+      else
+        aAddons[i].item.userDisabled = true;
+    }
+  },
+  classID: Components.ID("{4e6ea350-b09a-11df-94e2-0800200c9a66}"),
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIBlocklistPrompt])
+};
+
+const NSGetFactory = XPCOMUtils.generateNSGetFactory([BlocklistPrompt]);
+
--- a/components/Makefile.in
+++ b/components/Makefile.in
@@ -66,16 +66,17 @@ EXTRA_COMPONENTS = \
         HelperAppDialog.js \
         PromptService.js \
         BrowserCLH.js \
         ContentDispatchChooser.js \
         AutoCompleteCache.js \
         AddonUpdateService.js \
         FormAutoComplete.js \
         LoginManager.js \
+        BlocklistPrompt.js \
 	$(NULL)
 
 ifndef ANDROID
 EXTRA_COMPONENTS += AlertsService.js
 endif
 
 ifneq (Android,$(OS_TARGET))
 DIRS =  phone \
--- a/components/MobileComponents.manifest
+++ b/components/MobileComponents.manifest
@@ -85,8 +85,12 @@ category update-timer AddonUpdateService
 
 # FormAutoComplete.js
 component {cccd414c-3ec2-4cc5-9dc4-36c87cc3c4fe} FormAutoComplete.js
 contract @mozilla.org/satchel/form-autocomplete;1 {cccd414c-3ec2-4cc5-9dc4-36c87cc3c4fe}
 
 # LoginManager.js
 component {f9a0edde-2a8d-4bfd-a08c-3f9333213a85} LoginManager.js
 contract @mozilla.org/login-manager;1 {f9a0edde-2a8d-4bfd-a08c-3f9333213a85}
+
+# BlocklistPrompt.js
+component {4e6ea350-b09a-11df-94e2-0800200c9a66} BlocklistPrompt.js
+contract @mozilla.org/addons/blocklist-prompt;1 {4e6ea350-b09a-11df-94e2-0800200c9a66}
--- a/locales/en-US/chrome/browser.properties
+++ b/locales/en-US/chrome/browser.properties
@@ -35,16 +35,36 @@ addonUpdate.checking=Checking for updates…
 addonUpdate.updating=Updating to %S
 addonUpdate.updated=Updated to %S
 addonUpdate.compatibility=A compatibility update has been applied
 addonUpdate.noupdate=No updates were found
 addonUpdate.notsupported=Updates not supported
 addonUpdate.disabled=Updates are disabled
 addonUpdate.error=An error occurred
 
+addonBlocked.blocked=Blocked
+addonBlocked.softBlocked=Known to cause security or stability issues
+addonBlocked.outdated=Out of date
+
+# LOCALIZATION NOTE (addonError-1, addonError-2, addonError-3, addonError-4):
+# #1 is the add-on name, #2 is the add-on host, #3 is the application name
+addonError-1=The add-on could not be downloaded because of a connection failure on #2.
+addonError-2=The add-on from #2 could not be installed because it does not match the add-on #3 expected.
+addonError-3=The add-on downloaded from #2 could not be installed because it appears to be corrupt.
+addonError-4=#1 could not be installed because #3 cannot modify the needed file.
+
+# LOCALIZATION NOTE (addonLocalError-1, addonLocalError-2, addonLocalError-3, addonLocalError-4, addonErrorIncompatible, addonErrorBlocklisted):
+# #1 is the add-on name, #3 is the application name, #4 is the application version
+addonLocalError-1=This add-on could not be installed because of a filesystem error.
+addonLocalError-2=This add-on could not be installed because it does not match the add-on #3 expected.
+addonLocalError-3=This add-on could not be installed because it appears to be corrupt.
+addonLocalError-4=#1 could not be installed because #3 cannot modify the needed file.
+addonErrorIncompatible=#1 could not be installed because it is not compatible with #3 #4.
+addonErrorBlocklisted=#1 could not be installed because it has a high risk of causing stability or security problems.
+
 # Download Manager
 # LOCALIZATION NOTE (Status): — is the "em dash" (long dash)
 # #1 download size for FINISHED or download state; #2 host (e.g., eTLD + 1, IP)
 downloadsStatus=#1 — #2
 downloadsUnknownSize=Unknown size
 # LOCALIZATION NOTE (KnownSize): #1 size number; #2 size unit
 downloadsKnownSize=#1 #2
 donwloadsYesterday=Yesterday
@@ -68,16 +88,17 @@ alertAddonsDisabled=#1 incompatible add-
 
 alertDownloads=Downloads
 alertDownloadsStart=Downloading: %S
 alertDownloadsDone=%S has finished downloading
 
 # Notifications
 notificationRestart.normal=Restart to complete changes.
 notificationRestart.update=Add-ons updated. Restart to complete changes.
+notificationRestart.blocked=Unsafe add-ons installed. Restart to disable.
 notificationRestart.button=Restart
 
 # Popup Blocker
 popupWarning=%S prevented this site from opening a pop-up window.
 popupWarningMultiple=%S prevented this site from opening %S pop-up windows.
 popupButtonAllowOnce=Show
 popupButtonAlwaysAllow2=Always Show
 popupButtonNeverWarn2=Never Show