Bug 1444487 Add preference for langpack signing draft
authorAndrew Swan <aswan@mozilla.com>
Fri, 09 Mar 2018 11:31:39 -0800
changeset 766390 f91fef0caafbee4e0a078bf2aa7d0d7a83eb67fb
parent 766381 718e04535230d53a590b7dbb1a3cd983c259a622
push id102312
push useraswan@mozilla.com
push dateMon, 12 Mar 2018 20:32:36 +0000
bugs1444487
milestone61.0a1
Bug 1444487 Add preference for langpack signing MozReview-Commit-ID: FEPa2wlLBST
modules/libpref/init/all.js
toolkit/mozapps/extensions/internal/AddonSettings.jsm
toolkit/mozapps/extensions/internal/XPIInstall.jsm
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_signed.xpi
toolkit/mozapps/extensions/test/xpcshell/data/signing_checks/langpack_unsigned.xpi
toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js
toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5095,16 +5095,17 @@ pref("html5.flushtimer.subsequentdelay",
 pref("browser.history.maxStateObjectSize", 655360);
 
 pref("browser.meta_refresh_when_inactive.disabled", false);
 
 // XPInstall prefs
 pref("xpinstall.whitelist.required", true);
 // Only Firefox requires add-on signatures
 pref("xpinstall.signatures.required", false);
+pref("extensions.langpacks.signatures.required", false);
 pref("extensions.minCompatiblePlatformVersion", "2.0");
 pref("extensions.webExtensionsMinPlatformVersion", "42.0a1");
 pref("extensions.legacy.enabled", true);
 pref("extensions.allow-non-mpc-extensions", true);
 
 // Other webextensions prefs
 pref("extensions.webextensions.keepStorageOnUninstall", false);
 pref("extensions.webextensions.keepUuidOnUninstall", false);
--- a/toolkit/mozapps/extensions/internal/AddonSettings.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonSettings.jsm
@@ -5,16 +5,17 @@
 "use strict";
 
 var EXPORTED_SYMBOLS = [ "AddonSettings" ];
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 const PREF_SIGNATURES_REQUIRED = "xpinstall.signatures.required";
+const PREF_LANGPACK_SIGNATURES = "extensions.langpacks.signatures.required";
 const PREF_ALLOW_LEGACY = "extensions.legacy.enabled";
 
 var AddonSettings = {};
 
 // Make a non-changable property that can't be manipulated from other
 // code in the app.
 function makeConstant(name, value) {
   Object.defineProperty(AddonSettings, name, {
@@ -29,14 +30,17 @@ makeConstant("ADDON_SIGNING", AppConstan
 
 if (AppConstants.MOZ_REQUIRE_SIGNING && !Cu.isInAutomation) {
   makeConstant("REQUIRE_SIGNING", true);
 } else {
   XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "REQUIRE_SIGNING",
                                         PREF_SIGNATURES_REQUIRED, false);
 }
 
+XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "LANGPACKS_REQUIRE_SIGNING",
+                                      PREF_LANGPACK_SIGNATURES, false);
+
 if (AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS || Cu.isInAutomation) {
   XPCOMUtils.defineLazyPreferenceGetter(AddonSettings, "ALLOW_LEGACY_EXTENSIONS",
                                         PREF_ALLOW_LEGACY, true);
 } else {
   makeConstant("ALLOW_LEGACY_EXTENSIONS", false);
 }
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -55,31 +55,33 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    Ci.nsIRDFService);
 
 
 ChromeUtils.defineModuleGetter(this, "XPIInternal",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 ChromeUtils.defineModuleGetter(this, "XPIProvider",
                                "resource://gre/modules/addons/XPIProvider.jsm");
 
-/* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, TOOLKIT_ID, XPIDatabase, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, recordAddonTelemetry */
+/* globals AddonInternal, BOOTSTRAP_REASONS, KEY_APP_SYSTEM_ADDONS, KEY_APP_SYSTEM_DEFAULTS, KEY_APP_TEMPORARY, TEMPORARY_ADDON_SUFFIX, SIGNED_TYPES, TOOLKIT_ID, XPIDatabase, XPIStates, getExternalType, isTheme, isUsableAddon, isWebExtension, mustSign, recordAddonTelemetry */
 const XPI_INTERNAL_SYMBOLS = [
   "AddonInternal",
   "BOOTSTRAP_REASONS",
   "KEY_APP_SYSTEM_ADDONS",
   "KEY_APP_SYSTEM_DEFAULTS",
   "KEY_APP_TEMPORARY",
+  "SIGNED_TYPES",
   "TEMPORARY_ADDON_SUFFIX",
   "TOOLKIT_ID",
   "XPIDatabase",
   "XPIStates",
   "getExternalType",
   "isTheme",
   "isUsableAddon",
   "isWebExtension",
+  "mustSign",
   "recordAddonTelemetry",
 ];
 
 for (let name of XPI_INTERNAL_SYMBOLS) {
   XPCOMUtils.defineLazyGetter(this, name, () => XPIInternal[name]);
 }
 
 /**
@@ -151,40 +153,23 @@ const COMPATIBLE_BY_DEFAULT_TYPES = {
 const RESTARTLESS_TYPES = new Set([
   "apiextension",
   "dictionary",
   "experiment",
   "webextension",
   "webextension-theme",
 ]);
 
-const SIGNED_TYPES = new Set([
-  "apiextension",
-  "extension",
-  "experiment",
-  "webextension",
-  "webextension-theme",
-]);
-
-
 // This is a random number array that can be used as "salt" when generating
 // an automatic ID based on the directory path of an add-on. It will prevent
 // someone from creating an ID for a permanent add-on that could be replaced
 // by a temporary add-on (because that would be confusing, I guess).
 const TEMP_INSTALL_ID_GEN_SESSION =
   new Uint8Array(Float64Array.of(Math.random()).buffer);
 
-// Whether add-on signing is required.
-function mustSign(aType) {
-  if (!SIGNED_TYPES.has(aType))
-    return false;
-
-  return AddonSettings.REQUIRE_SIGNING;
-}
-
 const MSG_JAR_FLUSH = "AddonJarFlush";
 const MSG_MESSAGE_MANAGER_CACHES_FLUSH = "AddonMessageManagerCachesFlush";
 
 
 /**
  * Valid IDs fit this pattern.
  */
 var gIDTest = /^(\{[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\}|[a-z0-9-\._]*\@[a-z0-9-\._]+)$/i;
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -75,16 +75,17 @@ const PREF_EM_STARTUP_SCAN_SCOPES     = 
 const PREF_EM_SHOW_MISMATCH_UI        = "extensions.showMismatchUI";
 const PREF_XPI_ENABLED                = "xpinstall.enabled";
 const PREF_XPI_WHITELIST_REQUIRED     = "xpinstall.whitelist.required";
 const PREF_XPI_DIRECT_WHITELISTED     = "xpinstall.whitelist.directRequest";
 const PREF_XPI_FILE_WHITELISTED       = "xpinstall.whitelist.fileRequest";
 // 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_REQUIRESECUREORIGIN = "extensions.install.requireSecureOrigin";
 const PREF_INSTALL_DISTRO_ADDONS      = "extensions.installDistroAddons";
 const PREF_BRANCH_INSTALLED_ADDON     = "extensions.installedDistroAddon.";
 const PREF_DISTRO_ADDONS_PERMS        = "extensions.distroAddons.promptForPermissions";
 const PREF_SYSTEM_ADDON_SET           = "extensions.systemAddonSet";
 const PREF_SYSTEM_ADDON_UPDATE_URL    = "extensions.systemAddon.update.url";
 const PREF_ALLOW_LEGACY               = "extensions.legacy.enabled";
@@ -213,16 +214,17 @@ const CHROME_TYPES = new Set([
   "experiment",
 ]);
 
 const SIGNED_TYPES = new Set([
   "apiextension",
   "extension",
   "experiment",
   "webextension",
+  "webextension-langpack",
   "webextension-theme",
 ]);
 
 const LEGACY_TYPES = new Set([
   "apiextension",
   "extension",
   "theme",
 ]);
@@ -235,16 +237,20 @@ const ALL_EXTERNAL_TYPES = new Set([
   "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";
@@ -2164,16 +2170,17 @@ var XPIProvider = {
                                                                   null);
       this.minCompatiblePlatformVersion = Services.prefs.getStringPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
                                                                        null);
 
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_APP_VERSION, this);
       Services.prefs.addObserver(PREF_EM_MIN_COMPAT_PLATFORM_VERSION, this);
       if (!AppConstants.MOZ_REQUIRE_SIGNING || Cu.isInAutomation)
         Services.prefs.addObserver(PREF_XPI_SIGNATURES_REQUIRED, this);
+      Services.prefs.addObserver(PREF_LANGPACK_SIGNATURES, this);
       Services.prefs.addObserver(PREF_ALLOW_LEGACY, this);
       Services.prefs.addObserver(PREF_ALLOW_NON_MPC, this);
       Services.obs.addObserver(this, NOTIFICATION_FLUSH_PERMISSIONS);
       Services.obs.addObserver(this, NOTIFICATION_TOOLBOX_CONNECTION_CHANGE);
 
 
       let flushCaches = this.checkForChanges(aAppChanged, aOldAppVersion,
                                              aOldPlatformVersion);
@@ -4024,16 +4031,17 @@ var XPIProvider = {
         this.updateAddonAppDisabledStates();
         break;
       case PREF_EM_MIN_COMPAT_PLATFORM_VERSION:
         this.minCompatiblePlatformVersion = Services.prefs.getStringPref(PREF_EM_MIN_COMPAT_PLATFORM_VERSION,
                                                                          null);
         this.updateAddonAppDisabledStates();
         break;
       case PREF_XPI_SIGNATURES_REQUIRED:
+      case PREF_LANGPACK_SIGNATURES:
       case PREF_ALLOW_LEGACY:
       case PREF_ALLOW_NON_MPC:
         this.updateAddonAppDisabledStates();
         break;
       }
     }
   },
 
@@ -6978,23 +6986,25 @@ class WinRegInstallLocation extends Dire
 }
 
 var XPIInternal = {
   AddonInternal,
   BOOTSTRAP_REASONS,
   KEY_APP_SYSTEM_ADDONS,
   KEY_APP_SYSTEM_DEFAULTS,
   KEY_APP_TEMPORARY,
+  SIGNED_TYPES,
   TEMPORARY_ADDON_SUFFIX,
   TOOLKIT_ID,
   XPIStates,
   getExternalType,
   isTheme,
   isUsableAddon,
   isWebExtension,
+  mustSign,
   recordAddonTelemetry,
 
   get XPIDatabase() { return gGlobalScope.XPIDatabase; },
 };
 
 var addonTypes = [
   new AddonManagerPrivate.AddonType("extension", URI_EXTENSION_STRINGS,
                                     "type.extension.name",
new file mode 100644
index 0000000000000000000000000000000000000000..f60d00348eb41058cc3e49680029083954ba05e9
GIT binary patch
literal 4452
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
XZ)>Kdihui$!mZy2^gAvX#UJ#4dK?oE
new file mode 100644
index 0000000000000000000000000000000000000000..89de7f4409521ecb1f33fa3975ac3b7f5f8a6f59
GIT binary patch
literal 413
zc$^FHW@Zs#U|`^2*jt+E!&kaC=`E1=laYaemqCUhH!&|WEw#8rFRM5|FEoUcfq5z4
z;;3anTw1}+z{v6ys1B?>H^9;Fuz|oH<&W&Ap9^uh`_0)Apjao6d$%|F=*g&U&W&32
z$NS84yQ-ox)5_A){lAwxd2lz&IVMlge>7!cOX)S9S#8{t46ata+W1W(<IAcON4Hph
zj(^cSv;0Z$)~T%XKg}>p@?(0wCQx8<mh7^?(h|{BzMHD@&m2nmYtCjT+n9Zc{rV+)
zO>5VleWIJ+Ts@lh^3a?8#*(rNj`Qpl-+1F=@R4+*C>L9vWd{XbcON$nUOm5H_1@*l
z4)s^F`5Cj>H=YgDso3*#rQx<I<xh8MPiE&iB`v=5=+7&6B2Atgjs7|LhrzDiZ|TQ&
zL~waK)(3bqGRZOH3N;A^5CAe6mNbG`Xko|-2}88-3-D%TgJ@%92nNz7ApHyg6&jfk
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_langpack.js
@@ -0,0 +1,56 @@
+
+const PREF_SIGNATURES_GENERAL = "xpinstall.signatures.required";
+const PREF_SIGNATURES_LANGPACKS = "extensions.langpacks.signatures.required";
+
+// Try to install the given XPI file, and assert that the install
+// succeeds.  Uninstalls before returning.
+async function installShouldSucceed(file) {
+  let install = await promiseInstallFile(file);
+  Assert.equal(install.state, AddonManager.STATE_INSTALLED);
+  Assert.notEqual(install.addon, null);
+  install.addon.uninstall();
+}
+
+// Try to install the given XPI file, assert that the install fails
+// due to lack of signing.
+async function installShouldFail(file) {
+  let install;
+  try {
+    install = await AddonManager.getInstallForFile(file);
+  } catch (err) {}
+  Assert.equal(install.state, AddonManager.STATE_DOWNLOAD_FAILED);
+  Assert.equal(install.error, AddonManager.ERROR_SIGNEDSTATE_REQUIRED);
+  Assert.equal(install.addon, null);
+}
+
+// Test that the preference controlling langpack signing works properly
+// (and that the general preference for addon signing does not affect
+// language packs).
+add_task(async function() {
+  AddonTestUtils.useRealCertChecks = true;
+
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9");
+  await promiseStartupManager();
+
+  Services.prefs.setBoolPref(PREF_SIGNATURES_GENERAL, true);
+  Services.prefs.setBoolPref(PREF_SIGNATURES_LANGPACKS, true);
+
+  // The signed langpack should always install.
+  let signedXPI = do_get_file("data/signing_checks/langpack_signed.xpi");
+  await installShouldSucceed(signedXPI);
+
+  // With signatures required, unsigned langpack should not install.
+  let unsignedXPI = do_get_file("data/signing_checks/langpack_unsigned.xpi");
+  await installShouldFail(unsignedXPI);
+
+  // Even with the general xpi signing pref off, an unsigned langapck
+  // should not install.
+  Services.prefs.setBoolPref(PREF_SIGNATURES_GENERAL, false);
+  await installShouldFail(unsignedXPI);
+
+  // But with the langpack signing pref off, unsigned langpack should isntall.
+  Services.prefs.setBoolPref(PREF_SIGNATURES_LANGPACKS, false);
+  await installShouldSucceed(unsignedXPI);
+
+  await promiseShutdownManager();
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -313,16 +313,18 @@ skip-if = require_signing || !allow_lega
 run-if = addon_signing
 [test_signed_inject.js]
 run-if = addon_signing
 # Bug 1394122
 skip-if = true
 [test_signed_install.js]
 run-if = addon_signing
 run-sequentially = Uses hardcoded ports in xpi files.
+[test_signed_langpack.js]
+run-if = addon_signing
 [test_signed_long.js]
 run-if = addon_signing
 [test_startup.js]
 # Bug 676992: test consistently fails on Android
 fail-if = os == "android"
 [test_syncGUID.js]
 [test_strictcompatibility.js]
 [test_targetPlatforms.js]