Bug 1454820 - Add support for system addon signing for web extension bundling. r=johannh,kmag
☠☠ backed out by 822936017145 ☠ ☠
authorJonathan Kingston <jkt@mozilla.com>
Wed, 18 Apr 2018 00:43:39 +0100
changeset 472019 8141b60030b908c1f291979d72e0f21db8206c5c
parent 472018 ab26e8e09fe50465702fd4f08fee67edf16a0e6b
child 472020 bea414aba9b9e74cd5e1feecf63b1cf0bc240279
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjohannh, kmag
bugs1454820
milestone61.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 1454820 - Add support for system addon signing for web extension bundling. r=johannh,kmag MozReview-Commit-ID: 3dpQKGHOgLa
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionTestCommon.jsm
toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
toolkit/components/extensions/test/xpcshell/test_ext_schemas_interactive.js
toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -624,17 +624,17 @@ class ExtensionData {
         scopes: data.scopes,
       });
 
       let computeModuleInit = (scope, modules) => {
         let manager = new ExtensionCommon.SchemaAPIManager(scope);
         return manager.initModuleJSON([modules]);
       };
 
-      if (manifest.experiment_apis) {
+      if (this.experimentsAllowed && manifest.experiment_apis) {
         let parentModules = {};
         let childModules = {};
 
         for (let [name, data] of Object.entries(manifest.experiment_apis)) {
           let schema = this.getURL(data.schema);
 
           if (!schemaPromises.has(schema)) {
             schemaPromises.set(schema, this.readJSON(data.schema).then(json => Schemas.processSchema(json)));
@@ -1343,16 +1343,18 @@ class Extension extends ExtensionData {
   }
 
   get manifestCacheKey() {
     return [this.id, this.version, Services.locale.getAppLocaleAsLangTag()];
   }
 
   get isPrivileged() {
     return (this.addonData.signedState === AddonManager.SIGNEDSTATE_PRIVILEGED ||
+            this.addonData.signedState === AddonManager.SIGNEDSTATE_SYSTEM ||
+            this.addonData.builtIn ||
             (AppConstants.MOZ_ALLOW_LEGACY_EXTENSIONS &&
              this.addonData.temporarilyInstalled));
   }
 
   get experimentsAllowed() {
     return (AddonSettings.ALLOW_LEGACY_EXTENSIONS ||
             this.isPrivileged);
   }
--- a/toolkit/components/extensions/ExtensionTestCommon.jsm
+++ b/toolkit/components/extensions/ExtensionTestCommon.jsm
@@ -368,18 +368,25 @@ var ExtensionTestCommon = class Extensio
       } else if (data.manifest.browser_specific_settings && data.manifest.browser_specific_settings.gecko) {
         id = data.manifest.browser_specific_settings.gecko.id;
       }
     }
     if (!id) {
       id = uuidGen.generateUUID().number;
     }
 
+    let signedState = AddonManager.SIGNEDSTATE_SIGNED;
+    if (data.isPrivileged) {
+      signedState = AddonManager.SIGNEDSTATE_PRIVILEGED;
+    }
+    if (data.isSystem) {
+      signedState = AddonManager.SIGNEDSTATE_SYSTEM;
+    }
+
     return new Extension({
       id,
       resourceURI: jarURI,
       cleanupFile: file,
-      signedState: data.isPrivileged ? AddonManager.SIGNEDSTATE_PRIVILEGED
-                                     : AddonManager.SIGNEDSTATE_SIGNED,
+      signedState,
       temporarilyInstalled: !!data.temporarilyInstalled,
     });
   }
 };
--- a/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
@@ -102,46 +102,71 @@ async function testFooExperiment() {
 
   browser.test.assertEq("child", browser.experiments.foo.child(),
                         "foo.child()");
 
   browser.test.assertEq("parent", await browser.experiments.foo.parent(),
                         "await foo.parent()");
 }
 
+async function testFooFailExperiment() {
+  browser.test.assertEq("object", typeof browser.experiments,
+                        "typeof browser.experiments");
+
+  browser.test.assertEq("undefined", typeof browser.experiments.foo,
+                        "typeof browser.experiments.foo");
+}
+
 add_task(async function test_bundled_experiments() {
-  async function background() {
-    await testFooExperiment();
+  let testCases = [
+    {isSystem: true, temporarilyInstalled: true, shouldHaveExperiments: true},
+    {isSystem: true, temporarilyInstalled: false, shouldHaveExperiments: true},
+    {isPrivileged: true, temporarilyInstalled: true, shouldHaveExperiments: true},
+    {isPrivileged: true, temporarilyInstalled: false, shouldHaveExperiments: true},
+    {isPrivileged: false, temporarilyInstalled: true, shouldHaveExperiments: true},
+    {isPrivileged: false, temporarilyInstalled: false, shouldHaveExperiments: false},
+  ];
+
+  async function background(shouldHaveExperiments) {
+    if (shouldHaveExperiments) {
+      await testFooExperiment();
+    } else {
+      await testFooFailExperiment();
+    }
 
     browser.test.notifyPass("background.experiments.foo");
   }
 
-  let extension = ExtensionTestUtils.loadExtension({
-    isPrivileged: true,
+  for (let testCase of testCases) {
+    let extension = ExtensionTestUtils.loadExtension({
+      isPrivileged: testCase.isPrivileged,
+      isSystem: testCase.isSystem,
+      temporarilyInstalled: testCase.temporarilyInstalled,
 
-    manifest: {
-      experiment_apis: fooExperimentAPIs,
-    },
+      manifest: {
+        experiment_apis: fooExperimentAPIs,
+      },
 
-    background: `
-      ${testFooExperiment}
-      (${background})();
-    `,
-
-    files: fooExperimentFiles,
-  });
+      background: `
+        ${testFooExperiment}
+        ${testFooFailExperiment}
+        (${background})(${testCase.shouldHaveExperiments});
+      `,
 
-  await extension.startup();
+      files: fooExperimentFiles,
+    });
 
-  await extension.awaitFinish("background.experiments.foo");
+    await extension.startup();
 
-  await extension.unload();
+    await extension.awaitFinish("background.experiments.foo");
+
+    await extension.unload();
+  }
 });
 
-
 add_task(async function test_unbundled_experiments() {
   async function background() {
     await testFooExperiment();
 
     browser.test.assertEq("object", typeof browser.experiments.crunk,
                           "typeof browser.experiments.crunk");
 
     browser.test.assertEq("function", typeof browser.experiments.crunk.child,
--- a/toolkit/components/extensions/test/xpcshell/test_ext_schemas_interactive.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_schemas_interactive.js
@@ -86,16 +86,17 @@ function setHandlingUserInput(extension)
                       .getInterface(Ci.nsIDOMWindowUtils);
   return winutils.setHandlingUserInput(true);
 }
 
 // Test that the schema requireUserInput flag works correctly for
 // proxied api implementations.
 add_task(async function test_proxy() {
   let extension = ExtensionTestUtils.loadExtension({
+    isPrivileged: true,
     background() {
       browser.test.onMessage.addListener(async () => {
         try {
           await browser.userinputtest.test();
           browser.test.sendMessage("result", null);
         } catch (err) {
           browser.test.sendMessage("result", err.message);
         }
@@ -123,16 +124,17 @@ add_task(async function test_proxy() {
 
   await extension.unload();
 });
 
 // Test that the schema requireUserInput flag works correctly for
 // non-proxied api implementations.
 add_task(async function test_local() {
   let extension = ExtensionTestUtils.loadExtension({
+    isPrivileged: true,
     background() {
       browser.test.onMessage.addListener(async () => {
         try {
           await browser.userinputtest.child();
           browser.test.sendMessage("result", null);
         } catch (err) {
           browser.test.sendMessage("result", err.message);
         }
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -2705,16 +2705,17 @@ var XPIProvider = {
       let installLocation = aAddon._installLocation || null;
       let params = {
         id: aAddon.id,
         version: aAddon.version,
         installPath: aFile.clone(),
         resourceURI: getURIForResourceInFile(aFile, ""),
         signedState: aAddon.signedState,
         temporarilyInstalled: installLocation == TemporaryInstallLocation,
+        builtIn: installLocation instanceof BuiltInInstallLocation,
       };
 
       if (aMethod == "startup" && aAddon.startupData) {
         params.startupData = aAddon.startupData;
       }
 
       if (aExtraParams) {
         for (let key in aExtraParams) {