Bug 1363925: Part 8c - Move isUsableAddon to XPIDatabase.jsm. r?aswan draft
authorKris Maglione <maglione.k@gmail.com>
Sun, 22 Apr 2018 14:52:27 -0700
changeset 786322 a61bc2c1054998ad0eb0219b74e8c4468c9eb8be
parent 786321 295c3fc3ee8c153d358cc1e7c8b6f85925a03bd7
child 786323 7a5b72ef201f356ed1b9e5a3bada52fc3056f708
push id107433
push usermaglione.k@gmail.com
push dateSun, 22 Apr 2018 22:24:27 +0000
reviewersaswan
bugs1363925
milestone61.0a1
Bug 1363925: Part 8c - Move isUsableAddon to XPIDatabase.jsm. r?aswan MozReview-Commit-ID: 1aIA9Lu5sS2
toolkit/mozapps/extensions/internal/XPIDatabase.jsm
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIDatabase.jsm
@@ -32,30 +32,28 @@ const {nsIBlocklistService} = Ci;
 /* globals
  *         BOOTSTRAP_REASONS,
  *         DB_SCHEMA,
  *         SIGNED_TYPES,
  *         XPIProvider,
  *         XPIStates,
  *         descriptorToPath,
  *         isTheme,
- *         isUsableAddon,
  *         isWebExtension,
  *         recordAddonTelemetry,
  */
 
 for (let sym of [
   "BOOTSTRAP_REASONS",
   "DB_SCHEMA",
   "SIGNED_TYPES",
   "XPIProvider",
   "XPIStates",
   "descriptorToPath",
   "isTheme",
-  "isUsableAddon",
   "isWebExtension",
   "recordAddonTelemetry",
 ]) {
   XPCOMUtils.defineLazyGetter(this, sym, () => XPIInternal[sym]);
 }
 
 ChromeUtils.import("resource://gre/modules/Log.jsm");
 const LOGGER_ID = "addons.xpi-utils";
@@ -73,16 +71,17 @@ const FILE_JSON_DB                    = 
 // The last version of DB_SCHEMA implemented in SQLITE
 const LAST_SQLITE_DB_SCHEMA           = 14;
 
 const PREF_BLOCKLIST_ITEM_URL         = "extensions.blocklist.itemURL";
 const PREF_DB_SCHEMA                  = "extensions.databaseSchema";
 const PREF_EM_AUTO_DISABLED_SCOPES    = "extensions.autoDisableScopes";
 const PREF_EM_EXTENSION_FORMAT        = "extensions.";
 const PREF_PENDING_OPERATIONS         = "extensions.pendingOperations";
+const PREF_XPI_SIGNATURES_DEV_ROOT    = "xpinstall.signatures.dev-root";
 
 const TOOLKIT_ID                      = "toolkit@mozilla.org";
 
 const KEY_APP_SYSTEM_ADDONS           = "app-system-addons";
 const KEY_APP_SYSTEM_DEFAULTS         = "app-system-defaults";
 const KEY_APP_SYSTEM_LOCAL            = "app-system-local";
 const KEY_APP_SYSTEM_SHARE            = "app-system-share";
 const KEY_APP_GLOBAL                  = "app-global";
@@ -114,16 +113,20 @@ const PROP_JSON_FIELDS = ["id", "syncGUI
                           "skinnable", "size", "sourceURI", "releaseNotesURI",
                           "softDisabled", "foreignInstall",
                           "strictCompatibility", "locales", "targetApplications",
                           "targetPlatforms", "signedState",
                           "seen", "dependencies", "hasEmbeddedWebExtension",
                           "userPermissions", "icons", "iconURL", "icon64URL",
                           "blocklistState", "blocklistURL", "startupData"];
 
+const LEGACY_TYPES = new Set([
+  "extension",
+]);
+
 // Time to wait before async save of XPI JSON database, in milliseconds
 const ASYNC_SAVE_DELAY_MS = 20;
 
 // Note: When adding/changing/removing items here, remember to change the
 // DB schema version to ensure changes are picked up ASAP.
 const STATIC_BLOCKLIST_PATTERNS = [
   { creator: "Mozilla Corp.",
     level: nsIBlocklistService.STATE_BLOCKED,
@@ -467,17 +470,17 @@ AddonInternal.prototype = {
         softDisabled = false;
       }
     }
 
     if (this.inDatabase && updateDatabase) {
       XPIProvider.updateAddonDisabledState(this, userDisabled, softDisabled);
       XPIDatabase.saveChanges();
     } else {
-      this.appDisabled = !isUsableAddon(this);
+      this.appDisabled = !XPIDatabase.isUsableAddon(this);
       if (userDisabled !== undefined) {
         this.userDisabled = userDisabled;
       }
       if (softDisabled !== undefined) {
         this.softDisabled = softDisabled;
       }
     }
   },
@@ -487,17 +490,17 @@ AddonInternal.prototype = {
       for (let updateTarget of aUpdate.targetApplications) {
         if (targetApp.id == updateTarget.id && (aSyncCompatibility ||
             Services.vc.compare(targetApp.maxVersion, updateTarget.maxVersion) < 0)) {
           targetApp.minVersion = updateTarget.minVersion;
           targetApp.maxVersion = updateTarget.maxVersion;
         }
       }
     }
-    this.appDisabled = !isUsableAddon(this);
+    this.appDisabled = !XPIDatabase.isUsableAddon(this);
   },
 
   /**
    * toJSON is called by JSON.stringify in order to create a filtered version
    * of this object to be serialized to a JSON file. A new object is returned
    * with copies of all non-private properties. Functions, getters and setters
    * are not copied.
    *
@@ -546,17 +549,17 @@ AddonInternal.prototype = {
     for (let prop of PENDING_INSTALL_METADATA) {
       if (!(prop in aObj))
         continue;
 
       this[prop] = aObj[prop];
     }
 
     // Compatibility info may have changed so update appDisabled
-    this.appDisabled = !isUsableAddon(this);
+    this.appDisabled = !XPIDatabase.isUsableAddon(this);
   },
 
   permissions() {
     let permissions = 0;
 
     // Add-ons that aren't installed cannot be modified in any way
     if (!(this.inDatabase))
       return permissions;
@@ -1886,16 +1889,127 @@ this.XPIDatabase = {
    */
   getAddons() {
     if (!this.addonDB) {
       return [];
     }
     return _filterDB(this.addonDB, aAddon => true);
   },
 
+
+  /**
+   * Returns true if signing is required for the given add-on type.
+   *
+   * @param {string} aType
+   *        The add-on type to check.
+   * @returns {boolean}
+   */
+  mustSign(aType) {
+    if (!SIGNED_TYPES.has(aType))
+      return false;
+
+    if (aType == "webextension-langpack") {
+      return AddonSettings.LANGPACKS_REQUIRE_SIGNING;
+    }
+
+    return AddonSettings.REQUIRE_SIGNING;
+  },
+
+  /**
+   * Determine if this addon should be disabled due to being legacy
+   *
+   * @param {Addon} addon The addon to check
+   *
+   * @returns {boolean} Whether the addon should be disabled for being legacy
+   */
+  isDisabledLegacy(addon) {
+    return (!AddonSettings.ALLOW_LEGACY_EXTENSIONS &&
+            LEGACY_TYPES.has(addon.type) &&
+
+            // Legacy add-ons are allowed in the system location.
+            !addon._installLocation.isSystem &&
+
+            // Legacy extensions may be installed temporarily in
+            // non-release builds.
+            !(AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS &&
+              addon._installLocation.name == KEY_APP_TEMPORARY) &&
+
+            // Properly signed legacy extensions are allowed.
+            addon.signedState !== AddonManager.SIGNEDSTATE_PRIVILEGED);
+  },
+
+  /**
+   * Calculates whether an add-on should be appDisabled or not.
+   *
+   * @param {AddonInternal} aAddon
+   *        The add-on to check
+   * @returns {boolean}
+   *        True if the add-on should not be appDisabled
+   */
+  isUsableAddon(aAddon) {
+    if (this.mustSign(aAddon.type) && !aAddon.isCorrectlySigned) {
+      logger.warn(`Add-on ${aAddon.id} is not correctly signed.`);
+      if (Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
+        logger.warn(`Preference ${PREF_XPI_SIGNATURES_DEV_ROOT} is set.`);
+      }
+      return false;
+    }
+
+    if (aAddon.blocklistState == nsIBlocklistService.STATE_BLOCKED) {
+      logger.warn(`Add-on ${aAddon.id} is blocklisted.`);
+      return false;
+    }
+
+    // If we can't read it, it's not usable:
+    if (aAddon.brokenManifest) {
+      return false;
+    }
+
+    if (AddonManager.checkUpdateSecurity && !aAddon.providesUpdatesSecurely) {
+      logger.warn(`Updates for add-on ${aAddon.id} must be provided over HTTPS.`);
+      return false;
+    }
+
+
+    if (!aAddon.isPlatformCompatible) {
+      logger.warn(`Add-on ${aAddon.id} is not compatible with platform.`);
+      return false;
+    }
+
+    if (aAddon.dependencies.length) {
+      let isActive = id => {
+        let active = XPIProvider.activeAddons.get(id);
+        return active && !active.disable;
+      };
+
+      if (aAddon.dependencies.some(id => !isActive(id)))
+        return false;
+    }
+
+    if (this.isDisabledLegacy(aAddon)) {
+      logger.warn(`disabling legacy extension ${aAddon.id}`);
+      return false;
+    }
+
+    if (AddonManager.checkCompatibility) {
+      if (!aAddon.isCompatible) {
+        logger.warn(`Add-on ${aAddon.id} is not compatible with application version.`);
+        return false;
+      }
+    } else {
+      let app = aAddon.matchingTargetApplication;
+      if (!app) {
+        logger.warn(`Add-on ${aAddon.id} is not compatible with target application.`);
+        return false;
+      }
+    }
+
+    return true;
+  },
+
   /**
    * Synchronously adds an AddonInternal's metadata to the database.
    *
    * @param {AddonInternal} aAddon
    *        AddonInternal to add
    * @param {string} aPath
    *        The file path of the add-on
    * @returns {DBAddonInternal}
@@ -2246,17 +2360,17 @@ this.XPIDatabaseReconcile = {
 
     // Assume that add-ons in the system add-ons install location aren't
     // foreign and should default to enabled.
     aNewAddon.foreignInstall = isDetectedInstall &&
                                aInstallLocation.name != KEY_APP_SYSTEM_ADDONS &&
                                aInstallLocation.name != KEY_APP_SYSTEM_DEFAULTS;
 
     // appDisabled depends on whether the add-on is a foreignInstall so update
-    aNewAddon.appDisabled = !isUsableAddon(aNewAddon);
+    aNewAddon.appDisabled = !XPIDatabase.isUsableAddon(aNewAddon);
 
     if (isDetectedInstall && aNewAddon.foreignInstall) {
       // If the add-on is a foreign install and is in a scope where add-ons
       // that were dropped in should default to disabled then disable it
       let disablingScopes = Services.prefs.getIntPref(PREF_EM_AUTO_DISABLED_SCOPES, 0);
       if (aInstallLocation.scope & disablingScopes) {
         logger.warn("Disabling foreign installed add-on " + aNewAddon.id + " in "
             + aInstallLocation.name);
@@ -2404,17 +2518,17 @@ this.XPIDatabaseReconcile = {
       let remove = ["syncGUID", "foreignInstall", "visible", "active",
                     "userDisabled", "applyBackgroundUpdates", "sourceURI",
                     "releaseNotesURI", "targetApplications"];
 
       let props = PROP_JSON_FIELDS.filter(a => !remove.includes(a));
       copyProperties(manifest, props, aOldAddon);
     }
 
-    aOldAddon.appDisabled = !isUsableAddon(aOldAddon);
+    aOldAddon.appDisabled = !XPIDatabase.isUsableAddon(aOldAddon);
 
     return aOldAddon;
   },
 
   /**
    * Compares the add-ons that are currently installed to those that were
    * known to be installed when the application last ran and applies any
    * changes found to the database. Also sends "startupcache-invalidate" signal to
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -76,34 +76,32 @@ const PREF_DISTRO_ADDONS_PERMS        = 
 const PREF_INSTALL_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin";
 const PREF_PENDING_OPERATIONS         = "extensions.pendingOperations";
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_DIRECT_WHITELISTED     = "xpinstall.whitelist.directRequest";
 const PREF_XPI_FILE_WHITELISTED       = "xpinstall.whitelist.fileRequest";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
 
-/* globals BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, PREF_BRANCH_INSTALLED_ADDON, PREF_SYSTEM_ADDON_SET, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPI_PERMISSION, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, mustSign */
+/* globals BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, PREF_BRANCH_INSTALLED_ADDON, PREF_SYSTEM_ADDON_SET, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPI_PERMISSION, XPIStates, getExternalType, isTheme, isWebExtension */
 const XPI_INTERNAL_SYMBOLS = [
   "BOOTSTRAP_REASONS",
   "KEY_APP_SYSTEM_ADDONS",
   "KEY_APP_SYSTEM_DEFAULTS",
   "KEY_APP_TEMPORARY",
   "PREF_BRANCH_INSTALLED_ADDON",
   "PREF_SYSTEM_ADDON_SET",
   "SIGNED_TYPES",
   "TEMPORARY_ADDON_SUFFIX",
   "TOOLKIT_ID",
   "XPI_PERMISSION",
   "XPIStates",
   "getExternalType",
   "isTheme",
-  "isUsableAddon",
   "isWebExtension",
-  "mustSign",
 ];
 
 for (let name of XPI_INTERNAL_SYMBOLS) {
   XPCOMUtils.defineLazyGetter(this, name, () => XPIInternal[name]);
 }
 
 /**
  * Returns a nsIFile instance for the given path, relative to the given
@@ -929,17 +927,17 @@ var loadManifest = async function(aPacka
       }
     }
     if (!addon.id && aInstallLocation.name == KEY_APP_TEMPORARY) {
       addon.id = generateTemporaryInstallID(aPackage.file);
     }
   }
 
   await addon.updateBlocklistState({oldAddon: aOldAddon});
-  addon.appDisabled = !isUsableAddon(addon);
+  addon.appDisabled = !XPIDatabase.isUsableAddon(addon);
 
   defineSyncGUID(addon);
 
   return addon;
 };
 
 /**
  * Loads an add-on's manifest from the given file or directory.
@@ -1773,17 +1771,17 @@ class AddonInstall {
         }
 
         if (isWebExtension(this.existingAddon.type) && !isWebExtension(this.addon.type)) {
           return Promise.reject([AddonManager.ERROR_UNEXPECTED_ADDON_TYPE,
                                  "WebExtensions may not be updated to other extension types"]);
         }
       }
 
-      if (mustSign(this.addon.type)) {
+      if (XPIDatabase.mustSign(this.addon.type)) {
         if (this.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
           // This add-on isn't properly signed by a signature that chains to the
           // trusted root.
           let state = this.addon.signedState;
           this.addon = null;
 
           if (state == AddonManager.SIGNEDSTATE_MISSING)
             return Promise.reject([AddonManager.ERROR_SIGNEDSTATE_REQUIRED,
@@ -1816,17 +1814,17 @@ class AddonInstall {
         [repoAddon] = await AddonRepository.cacheAddons([this.addon.id]);
       } catch (err) {
         logger.debug(`Error getting metadata for ${this.addon.id}: ${err.message}`);
       }
     }
 
     this.addon._repositoryAddon = repoAddon;
     this.name = this.name || this.addon._repositoryAddon.name;
-    this.addon.appDisabled = !isUsableAddon(this.addon);
+    this.addon.appDisabled = !XPIDatabase.isUsableAddon(this.addon);
     return undefined;
   }
 
   getIcon(desiredSize = 64) {
     if (!this.addon.icons || !this.file) {
       return null;
     }
 
@@ -3730,17 +3728,17 @@ var XPIInstall = {
 
     // Check that the directory's name is a valid ID.
     if (!gIDTest.test(id) || !source.exists() || !source.isFile()) {
       throw new Error(`Ignoring invalid staging directory entry: ${id}`);
     }
 
     let addon = await loadManifestFromFile(source, location);
 
-    if (mustSign(addon.type) &&
+    if (XPIDatabase.mustSign(addon.type) &&
         addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
       throw new Error(`Refusing to install staged add-on ${id} with signed state ${addon.signedState}`);
     }
 
     addon.importMetadata(metadata);
 
     var oldBootstrap = null;
     logger.debug(`Processing install of ${id} in ${location.name}`);
@@ -4393,17 +4391,17 @@ var XPIInstall = {
     AddonManagerPrivate.recordSimpleMeasure("XPIDB_startup_disabled", startupChanges.length);
 
     let forceUpdate = [];
     if (startupChanges.length > 0) {
     let addons = XPIDatabase.getAddons();
       for (let addon of addons) {
         if ((startupChanges.includes(addon.id)) &&
             (addon.permissions() & AddonManager.PERM_CAN_UPGRADE) &&
-            (!addon.isCompatible || XPIProvider.isDisabledLegacy(addon))) {
+            (!addon.isCompatible || XPIDatabase.isDisabledLegacy(addon))) {
           logger.debug("shouldForceUpdateCheck: can upgrade disabled add-on " + addon.id);
           forceUpdate.push(addon.id);
         }
       }
     }
 
     if (forceUpdate.length > 0) {
       return forceUpdate;
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -29,18 +29,16 @@ XPCOMUtils.defineLazyModuleGetters(this,
   LegacyExtensionsUtils: "resource://gre/modules/LegacyExtensionsUtils.jsm",
 
   XPIDatabase: "resource://gre/modules/addons/XPIDatabase.jsm",
   XPIDatabaseReconcile: "resource://gre/modules/addons/XPIDatabase.jsm",
   XPIInstall: "resource://gre/modules/addons/XPIInstall.jsm",
   verifyBundleSignedState: "resource://gre/modules/addons/XPIInstall.jsm",
 });
 
-const {nsIBlocklistService} = Ci;
-
 XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
                                    "@mozilla.org/addons/addon-manager-startup;1",
                                    "amIAddonManagerStartup");
 
 Cu.importGlobalProperties(["URL"]);
 
 const nsIFile = Components.Constructor("@mozilla.org/file/local;1", "nsIFile",
                                        "initWithPath");
@@ -49,17 +47,16 @@ const PREF_DB_SCHEMA                  = 
 const PREF_XPI_STATE                  = "extensions.xpiState";
 const PREF_BOOTSTRAP_ADDONS           = "extensions.bootstrappedAddons";
 const PREF_PENDING_OPERATIONS         = "extensions.pendingOperations";
 const PREF_EM_ENABLED_SCOPES          = "extensions.enabledScopes";
 const PREF_EM_STARTUP_SCAN_SCOPES     = "extensions.startupScanScopes";
 const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";
 // xpinstall.signatures.required only supported in dev builds
 const PREF_XPI_SIGNATURES_REQUIRED    = "xpinstall.signatures.required";
-const PREF_XPI_SIGNATURES_DEV_ROOT    = "xpinstall.signatures.dev-root";
 const PREF_LANGPACK_SIGNATURES        = "extensions.langpacks.signatures.required";
 const PREF_XPI_PERMISSIONS_BRANCH     = "xpinstall.";
 const PREF_INSTALL_DISTRO_ADDONS      = "extensions.installDistroAddons";
 const PREF_BRANCH_INSTALLED_ADDON     = "extensions.installedDistroAddon.";
 const PREF_SYSTEM_ADDON_SET           = "extensions.systemAddonSet";
 const PREF_ALLOW_LEGACY               = "extensions.legacy.enabled";
 
 const PREF_EM_MIN_COMPAT_APP_VERSION      = "extensions.minCompatibleAppVersion";
@@ -161,39 +158,23 @@ const CHROME_TYPES = new Set([
 
 const SIGNED_TYPES = new Set([
   "extension",
   "webextension",
   "webextension-langpack",
   "webextension-theme",
 ]);
 
-const LEGACY_TYPES = new Set([
-  "extension",
-]);
-
 const ALL_EXTERNAL_TYPES = new Set([
   "dictionary",
   "extension",
   "locale",
   "theme",
 ]);
 
-// Whether add-on signing is required.
-function mustSign(aType) {
-  if (!SIGNED_TYPES.has(aType))
-    return false;
-
-  if (aType == "webextension-langpack") {
-    return AddonSettings.LANGPACKS_REQUIRE_SIGNING;
-  }
-
-  return AddonSettings.REQUIRE_SIGNING;
-}
-
 // Keep track of where we are in startup for telemetry
 // event happened during XPIDatabase.startup()
 const XPI_STARTING = "XPIStarting";
 // event happened after startup() but before the final-ui-startup event
 const XPI_BEFORE_UI_STARTUP = "BeforeFinalUIStartup";
 // event happened after final-ui-startup
 const XPI_AFTER_UI_STARTUP = "AfterFinalUIStartup";
 
@@ -391,108 +372,16 @@ function canRunInSafeMode(aAddon) {
 
   if (location.name == KEY_APP_TEMPORARY)
     return true;
 
   return location.isSystem;
 }
 
 /**
- * Determine if this addon should be disabled due to being legacy
- *
- * @param {Addon} addon The addon to check
- *
- * @returns {boolean} Whether the addon should be disabled for being legacy
- */
-function isDisabledLegacy(addon) {
-  return (!AddonSettings.ALLOW_LEGACY_EXTENSIONS &&
-          LEGACY_TYPES.has(addon.type) &&
-
-          // Legacy add-ons are allowed in the system location.
-          !addon._installLocation.isSystem &&
-
-          // Legacy extensions may be installed temporarily in
-          // non-release builds.
-          !(AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS &&
-            addon._installLocation.name == KEY_APP_TEMPORARY) &&
-
-          // Properly signed legacy extensions are allowed.
-          addon.signedState !== AddonManager.SIGNEDSTATE_PRIVILEGED);
-}
-
-/**
- * Calculates whether an add-on should be appDisabled or not.
- *
- * @param {AddonInternal} aAddon
- *        The add-on to check
- * @returns {boolean}
- *        True if the add-on should not be appDisabled
- */
-function isUsableAddon(aAddon) {
-  if (mustSign(aAddon.type) && !aAddon.isCorrectlySigned) {
-    logger.warn(`Add-on ${aAddon.id} is not correctly signed.`);
-    if (Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
-      logger.warn(`Preference ${PREF_XPI_SIGNATURES_DEV_ROOT} is set.`);
-    }
-    return false;
-  }
-
-  if (aAddon.blocklistState == nsIBlocklistService.STATE_BLOCKED) {
-    logger.warn(`Add-on ${aAddon.id} is blocklisted.`);
-    return false;
-  }
-
-  // If we can't read it, it's not usable:
-  if (aAddon.brokenManifest) {
-    return false;
-  }
-
-  if (AddonManager.checkUpdateSecurity && !aAddon.providesUpdatesSecurely) {
-    logger.warn(`Updates for add-on ${aAddon.id} must be provided over HTTPS.`);
-    return false;
-  }
-
-
-  if (!aAddon.isPlatformCompatible) {
-    logger.warn(`Add-on ${aAddon.id} is not compatible with platform.`);
-    return false;
-  }
-
-  if (aAddon.dependencies.length) {
-    let isActive = id => {
-      let active = XPIProvider.activeAddons.get(id);
-      return active && !active.disable;
-    };
-
-    if (aAddon.dependencies.some(id => !isActive(id)))
-      return false;
-  }
-
-  if (isDisabledLegacy(aAddon)) {
-    logger.warn(`disabling legacy extension ${aAddon.id}`);
-    return false;
-  }
-
-  if (AddonManager.checkCompatibility) {
-    if (!aAddon.isCompatible) {
-      logger.warn(`Add-on ${aAddon.id} is not compatible with application version.`);
-      return false;
-    }
-  } else {
-    let app = aAddon.matchingTargetApplication;
-    if (!app) {
-      logger.warn(`Add-on ${aAddon.id} is not compatible with target application.`);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-/**
  * Converts an internal add-on type to the type presented through the API.
  *
  * @param {string} aType
  *        The internal add-on type
  * @returns {string}
  *        An external add-on type
  */
 function getExternalType(aType) {
@@ -2899,17 +2788,17 @@ var XPIProvider = {
       aSoftDisabled = false;
     }
 
     // If not changing softDisabled or the add-on is already userDisabled then
     // use the existing value for softDisabled
     if (aSoftDisabled === undefined || aUserDisabled)
       aSoftDisabled = aAddon.softDisabled;
 
-    let appDisabled = !isUsableAddon(aAddon);
+    let appDisabled = !XPIDatabase.isUsableAddon(aAddon);
     // No change means nothing to do here
     if (aAddon.userDisabled == aUserDisabled &&
         aAddon.appDisabled == appDisabled &&
         aAddon.softDisabled == aSoftDisabled)
       return undefined;
 
     let wasDisabled = aAddon.disabled;
     let isDisabled = aUserDisabled || aSoftDisabled || appDisabled;
@@ -3527,21 +3416,18 @@ var XPIInternal = {
   XPIProvider,
   XPIStates,
   XPI_PERMISSION,
   awaitPromise,
   canRunInSafeMode,
   descriptorToPath,
   getExternalType,
   getURIForResourceInFile,
-  isDisabledLegacy,
   isTheme,
-  isUsableAddon,
   isWebExtension,
-  mustSign,
 };
 
 var addonTypes = [
   new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
                                     "type.extension.name",
                                     AddonManager.VIEW_TYPE_LIST, 4000,
                                     AddonManager.TYPE_SUPPORTS_UNDO_RESTARTLESS_UNINSTALL),
   new AddonManagerPrivate.AddonType("theme", URI_EXTENSION_STRINGS,