Bug 1454820 - Add support for system addon signing for web extension bundling. r=johannh,kmag
☠☠ backed out by b2c04559e167 ☠ ☠
authorJonathan Kingston <jkt@mozilla.com>
Wed, 18 Apr 2018 00:43:39 +0100
changeset 469606 7e3aa63ae7529cc0b48c106cbc918e937872c273
parent 469577 9c70604962648780c82ae1a4773b0f249b26863f
child 469607 b2c04559e167b863e9aaf74481b63179868495aa
push id9174
push userarchaeopteryx@coole-files.de
push dateMon, 30 Apr 2018 15:33:30 +0000
treeherdermozilla-beta@1b1a8ab75f1f [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
@@ -640,17 +640,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)));
@@ -1399,16 +1399,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
@@ -2709,16 +2709,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) {