diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index 46bd9af1ac4a..e96dc5453c0d 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -989,9 +989,8 @@ var loadManifestFromWebManifest = Task.async(function*(aUri) { addon.targetApplications = [{ id: TOOLKIT_ID, - minVersion: (bss.strict_min_version || - AddonManagerPrivate.webExtensionsMinPlatformVersion), - maxVersion: bss.strict_max_version || "*", + minVersion: bss.strict_min_version, + maxVersion: bss.strict_max_version, }]; addon.targetPlatforms = []; @@ -3995,6 +3994,13 @@ this.XPIProvider = { } let addon = yield loadManifestFromFile(aFile, TemporaryInstallLocation); + if (!addon.isCompatible) { + let app = addon.matchingTargetApplication; + throw new Error(`Add-on ${addon.id} is not compatible with application version. ` + + `add-on minVersion: ${app.minVersion}, ` + + `add-on maxVersion: ${app.maxVersion}`); + } + if (!addon.bootstrap) { throw new Error("Only restartless (bootstrap) add-ons" + " can be temporarily installed:", addon.id); @@ -7014,6 +7020,10 @@ AddonInternal.prototype = { if (!app) return false; + // set reasonable defaults for minVersion and maxVersion + let minVersion = app.minVersion || "0"; + let maxVersion = app.maxVersion || "*"; + if (!aAppVersion) aAppVersion = Services.appinfo.version; if (!aPlatformVersion) @@ -7050,14 +7060,14 @@ AddonInternal.prototype = { minCompatVersion = XPIProvider.minCompatiblePlatformVersion; if (minCompatVersion && - Services.vc.compare(minCompatVersion, app.maxVersion) > 0) + Services.vc.compare(minCompatVersion, maxVersion) > 0) return false; - return Services.vc.compare(version, app.minVersion) >= 0; + return Services.vc.compare(version, minVersion) >= 0; } - return (Services.vc.compare(version, app.minVersion) >= 0) && - (Services.vc.compare(version, app.maxVersion) <= 0) + return (Services.vc.compare(version, minVersion) >= 0) && + (Services.vc.compare(version, maxVersion) <= 0) }, get matchingTargetApplication() { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js index 1bb0cb603ddc..cafe8560e554 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js @@ -90,38 +90,57 @@ add_task(function* test_cannot_reload_permanent_addon() { yield tearDownAddon(addon); }); -add_task(function* test_disabled_addon_can_be_enabled_after_reload() { +add_task(function* test_reload_to_invalid_version_fails() { yield promiseRestartManager(); let tempdir = gTmpD.clone(); - // Create an add-on with strictCompatibility which should cause it - // to be appDisabled. - const unpackedAddon = writeInstallRDFToDir( - Object.assign({}, manifestSample, { - strictCompatibility: true, - targetApplications: [{ - id: "xpcshell@tests.mozilla.org", - minVersion: "0.1", - maxVersion: "0.1" - }], - }), tempdir, manifestSample.id, "bootstrap.js"); + // The initial version of the add-on will be compatible, and will therefore load + const addonId = "invalid_version_cannot_be_reloaded@tests.mozilla.org"; + let manifest = { + name: "invalid_version_cannot_be_reloaded", + description: "test invalid_version_cannot_be_reloaded", + manifest_version: 2, + version: "1.0", + applications: { + gecko: { + id: addonId, + } + }, + }; + + let addonDir = writeWebManifestForExtension(manifest, tempdir, "invalid_version"); + + yield AddonManager.installTemporaryAddon(addonDir); + let addon = yield promiseAddonByID(addonId); - yield AddonManager.installTemporaryAddon(unpackedAddon); - const addon = yield promiseAddonByID(manifestSample.id); notEqual(addon, null); - equal(addon.appDisabled, true); + equal(addon.id, addonId); + equal(addon.version, "1.0"); + equal(addon.appDisabled, false); + equal(addon.userDisabled, false); - // Remove strictCompatibility from the manifest. - writeInstallRDFToDir(manifestSample, tempdir, manifestSample.id); + // update the manifest to make the add-on version incompatible, so the reload will reject + manifest.applications.gecko.strict_min_version = "1"; + manifest.applications.gecko.strict_max_version = "1"; + manifest.version = "2.0"; - yield addon.reload(); + addonDir = writeWebManifestForExtension(manifest, tempdir, "invalid_version"); - const reloadedAddon = yield promiseAddonByID(manifestSample.id); + let expectedMsg = new RegExp("Add-on invalid_version_cannot_be_reloaded@tests.mozilla.org is not compatible with application version. " + + "add-on minVersion: 1, add-on maxVersion: 1"); + yield Assert.rejects(addon.reload(), + expectedMsg, + "Reload rejects when application version does not fall between minVersion and maxVersion"); + + let reloadedAddon = yield promiseAddonByID(addonId); notEqual(reloadedAddon, null); + equal(reloadedAddon.id, addonId); + equal(reloadedAddon.version, "1.0"); equal(reloadedAddon.appDisabled, false); + equal(reloadedAddon.userDisabled, false); yield tearDownAddon(reloadedAddon); - unpackedAddon.remove(true); + addonDir.remove(true); }); add_task(function* test_manifest_changes_are_refreshed() { diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js index 9917d9bb68ff..b07ceb5cef99 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js @@ -199,3 +199,160 @@ add_task(function* test_two_ids() { addon.uninstall(); }); + +// Test that strict_min_version and strict_max_version are enforced for +// loading temporary extension. +add_task(function* test_strict_min_max() { + // the app version being compared to is 1.9.2 + const addonId = "strict_min_max@tests.mozilla.org"; + const MANIFEST = { + name: "strict min max test", + description: "test strict min and max with temporary loading", + manifest_version: 2, + version: "1.0", + }; + + // bad max good min + let apps = { + applications: { + gecko: { + id: addonId, + strict_min_version: "1", + strict_max_version: "1" + }, + }, + } + let testManifest = Object.assign(apps, MANIFEST); + + let addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "the-addon-sub-dir"); + + let expectedMsg = new RegExp("Add-on strict_min_max@tests.mozilla.org is not compatible with application version. " + + "add-on minVersion: 1, add-on maxVersion: 1"); + yield Assert.rejects(AddonManager.installTemporaryAddon(addonDir), + expectedMsg, + "Install rejects when specified maxVersion is not valid"); + + let addon = yield promiseAddonByID(addonId); + do_check_eq(addon, null); + + // bad min good max + apps = { + applications: { + gecko: { + id: addonId, + strict_min_version: "2", + strict_max_version: "2" + }, + }, + } + testManifest = Object.assign(apps, MANIFEST); + + addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "the-addon-sub-dir"); + + expectedMsg = new RegExp("Add-on strict_min_max@tests.mozilla.org is not compatible with application version. " + + "add-on minVersion: 2, add-on maxVersion: 2"); + yield Assert.rejects(AddonManager.installTemporaryAddon(addonDir), + expectedMsg, + "Install rejects when specified minVersion is not valid"); + + addon = yield promiseAddonByID(addonId); + do_check_eq(addon, null); + + // bad both + apps = { + applications: { + gecko: { + id: addonId, + strict_min_version: "2", + strict_max_version: "1" + }, + }, + } + testManifest = Object.assign(apps, MANIFEST); + + addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "the-addon-sub-dir"); + + expectedMsg = new RegExp("Add-on strict_min_max@tests.mozilla.org is not compatible with application version. " + + "add-on minVersion: 2, add-on maxVersion: 1"); + yield Assert.rejects(AddonManager.installTemporaryAddon(addonDir), + expectedMsg, + "Install rejects when specified minVersion and maxVersion are not valid"); + + addon = yield promiseAddonByID(addonId); + do_check_eq(addon, null); + addonDir.remove(true); + + // good both + apps = { + applications: { + gecko: { + id: addonId, + strict_min_version: "1", + strict_max_version: "2" + }, + }, + } + testManifest = Object.assign(apps, MANIFEST); + + addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "strict_min_max"); + + yield AddonManager.installTemporaryAddon(addonDir); + addon = yield promiseAddonByID(addonId); + + do_check_neq(addon, null); + do_check_eq(addon.id, addonId); + addon.uninstall(); + addonDir.remove(true); + + // good only min + let newId = "strict_min_only@tests.mozilla.org"; + apps = { + applications: { + gecko: { + id: newId, + strict_min_version: "1", + }, + }, + } + testManifest = Object.assign(apps, MANIFEST); + + addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "strict_min_only"); + + yield AddonManager.installTemporaryAddon(addonDir); + addon = yield promiseAddonByID(newId); + + do_check_neq(addon, null); + do_check_eq(addon.id, newId); + + addon.uninstall(); + addonDir.remove(true); + + // good only max + newId = "strict_max_only@tests.mozilla.org"; + apps = { + applications: { + gecko: { + id: newId, + strict_max_version: "2", + }, + }, + } + testManifest = Object.assign(apps, MANIFEST); + + addonDir = writeWebManifestForExtension(testManifest, gTmpD, + "strict_max_only"); + + yield AddonManager.installTemporaryAddon(addonDir); + addon = yield promiseAddonByID(newId); + + do_check_neq(addon, null); + do_check_eq(addon.id, newId); + + addon.uninstall(); + addonDir.remove(true); +});