Commit 088fac1b authored by Rob Wu's avatar Rob Wu
Browse files

Bug 1766047 - Reject updates that have a mismatching version r=rpl,geckoview-reviewers,agi

parent 763746d9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2145,6 +2145,7 @@ package org.mozilla.geckoview {
    field public static final int ERROR_POSTPONED = -101;
    field public static final int ERROR_SIGNEDSTATE_REQUIRED = -5;
    field public static final int ERROR_UNEXPECTED_ADDON_TYPE = -6;
    field public static final int ERROR_UNEXPECTED_ADDON_VERSION = -9;
    field public static final int ERROR_USER_CANCELED = -100;
  }

+3 −0
Original line number Diff line number Diff line
@@ -1525,6 +1525,8 @@ public class WebExtension {
      public static final int ERROR_SIGNEDSTATE_REQUIRED = -5;
      /** The downloaded extension had a different type than expected. */
      public static final int ERROR_UNEXPECTED_ADDON_TYPE = -6;
      /** The downloaded extension had a different version than expected */
      public static final int ERROR_UNEXPECTED_ADDON_VERSION = -9;
      /** The extension did not have the expected ID. */
      public static final int ERROR_INCORRECT_ID = -7;
      /** The extension did not have the expected ID. */
@@ -1572,6 +1574,7 @@ public class WebExtension {
          ErrorCodes.ERROR_FILE_ACCESS,
          ErrorCodes.ERROR_SIGNEDSTATE_REQUIRED,
          ErrorCodes.ERROR_UNEXPECTED_ADDON_TYPE,
          ErrorCodes.ERROR_UNEXPECTED_ADDON_VERSION,
          ErrorCodes.ERROR_INCORRECT_ID,
          ErrorCodes.ERROR_INVALID_DOMAIN,
          ErrorCodes.ERROR_USER_CANCELED,
+2 −0
Original line number Diff line number Diff line
@@ -3819,6 +3819,8 @@ var AddonManager = {
    ["ERROR_INCORRECT_ID", -7],
    // The addon install_origins does not list the 3rd party domain.
    ["ERROR_INVALID_DOMAIN", -8],
    // Updates only: The downloaded add-on had a different version than expected.
    ["ERROR_UNEXPECTED_ADDON_VERSION", -9],
  ]),
  // The update check timed out
  ERROR_TIMEOUT: -1,
+11 −2
Original line number Diff line number Diff line
@@ -1277,7 +1277,8 @@ class AddonInstall {
   * @param {object} [options.icons]
   *        Optional icons for the add-on
   * @param {string} [options.version]
   *        An optional version for the add-on
   *        The expected version for the add-on.
   *        Required for updates, i.e. when existingAddon is set.
   * @param {Object?} [options.telemetryInfo]
   *        An optional object which provides details about the installation source
   *        included in the addon manager telemetry events.
@@ -1613,6 +1614,13 @@ class AddonInstall {
            `Refusing to change addon type from ${this.existingAddon.type} to ${this.addon.type}`,
          ]);
        }

        if (this.version !== this.addon.version) {
          return Promise.reject([
            AddonManager.ERROR_UNEXPECTED_ADDON_VERSION,
            `Expected addon version ${this.version} instead of ${this.addon.version}`
          ]);
        }
      }

      if (XPIDatabase.mustSign(this.addon.type)) {
@@ -2210,7 +2218,8 @@ var DownloadAddonInstall = class extends AddonInstall {
   * @param {Object} [options.icons]
   *        Optional icons for the add-on
   * @param {string} [options.version]
   *        An optional version for the add-on
   *        The expected version for the add-on.
   *        Required for updates, i.e. when existingAddon is set.
   * @param {function(string) : Promise<void>} [options.promptHandler]
   *        A callback to prompt the user before installing.
   * @param {boolean} [options.sendCookies]
+101 −0
Original line number Diff line number Diff line
/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

// The test extension uses an insecure update url.
Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false);

let server = AddonTestUtils.createHttpServer({ hosts: ["example.com"] });

async function serverRegisterUpdate({ id, version, actualVersion }) {
  let xpi = await createTempWebExtensionFile({
    manifest: {
      version: actualVersion,
      applications: { gecko: { id } },
    },
  });

  server.registerFile("/addon.xpi", xpi);
  AddonTestUtils.registerJSON(server, "/update.json", {
    addons: {
      [id]: {
        updates: [{ version, update_link: "http://example.com/addon.xpi" }],
      },
    },
  });
}

add_task(async function setup() {
  await ExtensionTestUtils.startAddonManager();
});

add_task(async function test_update_version_mismatch() {
  const ID = "updateversion@tests.mozilla.org";
  await promiseInstallWebExtension({
    manifest: {
      version: "1.0",
      applications: {
        gecko: {
          id: ID,
          update_url: "http://example.com/update.json",
        },
      },
    },
  });

  await serverRegisterUpdate({
    id: ID,
    version: "2.00",
    actualVersion: "2.000",
  });

  let addon = await promiseAddonByID(ID);
  Assert.notEqual(addon, null);
  Assert.equal(addon.version, "1.0");

  let update = await promiseFindAddonUpdates(
    addon,
    AddonManager.UPDATE_WHEN_USER_REQUESTED
  );
  let install = update.updateAvailable;
  Assert.notEqual(install, false, "Found available update");
  Assert.equal(install.version, "2.00");
  Assert.equal(install.state, AddonManager.STATE_AVAILABLE);
  Assert.equal(install.existingAddon, addon);

  await Assert.rejects(
    install.install(),
    err => install.error == AddonManager.ERROR_UNEXPECTED_ADDON_VERSION,
    "Should refuse installation when downloaded version does not match"
  );

  await addon.uninstall();
});

add_task(async function test_update_version_empty() {
  const ID = "updateversionempty@tests.mozilla.org";
  await serverRegisterUpdate({ id: ID, version: "", actualVersion: "1.0" });

  await promiseInstallWebExtension({
    manifest: {
      version: "0",
      applications: {
        gecko: {
          id: ID,
          update_url: "http://example.com/update.json",
        },
      },
    },
  });
  let addon = await promiseAddonByID(ID);
  Assert.notEqual(addon, null);
  Assert.equal(addon.version, "0");
  let update = await promiseFindAddonUpdates(
    addon,
    AddonManager.UPDATE_WHEN_USER_REQUESTED
  );
  // The only item in the updates array has version "" (empty). This should not
  // be offered as an available update because it is certainly not newer.
  Assert.equal(update.updateAvailable, false, "No update found");
  await addon.uninstall();
});
Loading