Bug 1735812 - Copy metadata of staged add-on before checking compatibility. r=robwu

Differential Revision: https://phabricator.services.mozilla.com/D129650
This commit is contained in:
John Bieling 2021-11-04 21:15:28 +00:00
Родитель dfca79f9ba
Коммит c5eae7ab89
3 изменённых файлов: 217 добавлений и 8 удалений

Просмотреть файл

@ -3941,14 +3941,6 @@ var XPIInstall = {
let addon = await loadManifestFromFile(source, location);
// Ensure a staged addon is compatible with the current running version of
// Firefox. If a prior version of the addon is installed, it will remain.
if (!addon.isCompatible) {
throw new Error(
`Add-on ${addon.id} is not compatible with application version.`
);
}
if (
XPIDatabase.mustSign(addon.type) &&
addon.signedState <= AddonManager.SIGNEDSTATE_MISSING
@ -3958,8 +3950,17 @@ var XPIInstall = {
);
}
// Import saved metadata before checking for compatibility.
addon.importMetadata(metadata);
// Ensure a staged addon is compatible with the current running version of
// Firefox. If a prior version of the addon is installed, it will remain.
if (!addon.isCompatible) {
throw new Error(
`Add-on ${addon.id} is not compatible with application version.`
);
}
logger.debug(`Processing install of ${id} in ${location.name}`);
let existingAddon = XPIStates.findAddon(id);
// This part of the startup file changes is called from

Просмотреть файл

@ -0,0 +1,32 @@
{
"addons": {
"test_delay_update_staged_webext@tests.mozilla.org": {
"updates": [
{
"version": "2.0",
"update_link": "http://example.com/addons/test_delay_update_staged_webextension_v2.xpi",
"applications": {
"gecko": {
"strict_min_version": "1",
"strict_max_version": "43"
}
}
}
]
},
"test_delay_update_staged_webext_no_update_url@tests.mozilla.org": {
"updates": [
{
"version": "2.0",
"update_link": "http://example.com/addons/test_delay_update_staged_webextension_no_update_url_v2.xpi",
"applications": {
"gecko": {
"strict_min_version": "1",
"strict_max_version": "43"
}
}
}
]
}
}
}

Просмотреть файл

@ -28,6 +28,9 @@ stageDir.append("staged");
const IGNORE_ID = "test_delay_update_ignore_webext@tests.mozilla.org";
const COMPLETE_ID = "test_delay_update_complete_webext@tests.mozilla.org";
const DEFER_ID = "test_delay_update_defer_webext@tests.mozilla.org";
const STAGED_ID = "test_delay_update_staged_webext@tests.mozilla.org";
const STAGED_NO_UPDATE_URL_ID =
"test_delay_update_staged_webext_no_update_url@tests.mozilla.org";
const NOUPDATE_ID = "test_no_update_webext@tests.mozilla.org";
// Create and configure the HTTP server.
@ -58,6 +61,35 @@ const ADDONS = {
},
},
},
test_delay_update_staged_webextension_v2: {
"manifest.json": {
manifest_version: 2,
name: "Delay Upgrade",
version: "2.0",
applications: {
gecko: {
id: STAGED_ID,
update_url: `http://example.com/data/test_delay_updates_staged.json`,
strict_min_version: "1",
strict_max_version: "41",
},
},
},
},
test_delay_update_staged_webextension_no_update_url_v2: {
"manifest.json": {
manifest_version: 2,
name: "Delay Upgrade",
version: "2.0",
applications: {
gecko: {
id: STAGED_NO_UPDATE_URL_ID,
strict_min_version: "1",
strict_max_version: "41",
},
},
},
},
test_delay_update_ignore_webextension_v2: {
"manifest.json": {
manifest_version: 2,
@ -330,6 +362,150 @@ add_task(async function delay_updates_defer() {
await promiseShutdownManager();
});
// add-on registers upgrade listener to deny update, completes after restart,
// even though the updated XPI is incompatible - the information returned
// by the update server defined in its manifest returns a compatible range
add_task(async function delay_updates_staged() {
await promiseStartupManager();
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
version: "1.0",
applications: {
gecko: {
id: STAGED_ID,
update_url: `http://example.com/data/test_delay_updates_staged.json`,
},
},
},
background() {
browser.runtime.onUpdateAvailable.addListener(details => {
browser.test.sendMessage("denied");
});
browser.test.sendMessage("ready");
},
});
await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
let addon = await promiseAddonByID(STAGED_ID);
Assert.notEqual(addon, null);
Assert.equal(addon.version, "1.0");
Assert.equal(addon.name, "Generated extension");
Assert.ok(addon.isCompatible);
Assert.ok(!addon.appDisabled);
Assert.ok(addon.isActive);
Assert.equal(addon.type, "extension");
let update = await promiseFindAddonUpdates(addon);
let install = update.updateAvailable;
await promiseCompleteAllInstalls([install]);
Assert.equal(install.state, AddonManager.STATE_POSTPONED);
// upgrade is initially postponed
let addon_postponed = await promiseAddonByID(STAGED_ID);
Assert.notEqual(addon_postponed, null);
Assert.equal(addon_postponed.version, "1.0");
Assert.equal(addon_postponed.name, "Generated extension");
Assert.ok(addon_postponed.isCompatible);
Assert.ok(!addon_postponed.appDisabled);
Assert.ok(addon_postponed.isActive);
Assert.equal(addon_postponed.type, "extension");
// add-on reports an available upgrade, but denied it till next restart
await extension.awaitMessage("denied");
await promiseRestartManager();
await extension.awaitStartup();
// add-on should have been updated during restart
let addon_upgraded = await promiseAddonByID(STAGED_ID);
Assert.notEqual(addon_upgraded, null);
Assert.equal(addon_upgraded.version, "2.0");
Assert.equal(addon_upgraded.name, "Delay Upgrade");
Assert.ok(addon_upgraded.isCompatible);
Assert.ok(!addon_upgraded.appDisabled);
Assert.ok(addon_upgraded.isActive);
Assert.equal(addon_upgraded.type, "extension");
await extension.unload();
await promiseShutdownManager();
});
// add-on registers upgrade listener to deny update, does not complete after
// restart, because the updated XPI is incompatible - there is no update server
// defined in its manifest, which could return a compatible range
add_task(async function delay_updates_staged_no_update_url() {
await promiseStartupManager();
let extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
version: "1.0",
applications: {
gecko: {
id: STAGED_NO_UPDATE_URL_ID,
update_url: `http://example.com/data/test_delay_updates_staged.json`,
},
},
},
background() {
browser.runtime.onUpdateAvailable.addListener(details => {
browser.test.sendMessage("denied");
});
browser.test.sendMessage("ready");
},
});
await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
let addon = await promiseAddonByID(STAGED_NO_UPDATE_URL_ID);
Assert.notEqual(addon, null);
Assert.equal(addon.version, "1.0");
Assert.equal(addon.name, "Generated extension");
Assert.ok(addon.isCompatible);
Assert.ok(!addon.appDisabled);
Assert.ok(addon.isActive);
Assert.equal(addon.type, "extension");
let update = await promiseFindAddonUpdates(addon);
let install = update.updateAvailable;
await promiseCompleteAllInstalls([install]);
Assert.equal(install.state, AddonManager.STATE_POSTPONED);
// upgrade is initially postponed
let addon_postponed = await promiseAddonByID(STAGED_NO_UPDATE_URL_ID);
Assert.notEqual(addon_postponed, null);
Assert.equal(addon_postponed.version, "1.0");
Assert.equal(addon_postponed.name, "Generated extension");
Assert.ok(addon_postponed.isCompatible);
Assert.ok(!addon_postponed.appDisabled);
Assert.ok(addon_postponed.isActive);
Assert.equal(addon_postponed.type, "extension");
// add-on reports an available upgrade, but denied it till next restart
await extension.awaitMessage("denied");
await promiseRestartManager();
await extension.awaitStartup();
// add-on should not have been updated during restart
let addon_upgraded = await promiseAddonByID(STAGED_NO_UPDATE_URL_ID);
Assert.notEqual(addon_upgraded, null);
Assert.equal(addon_upgraded.version, "1.0");
Assert.equal(addon_upgraded.name, "Generated extension");
Assert.ok(addon_upgraded.isCompatible);
Assert.ok(!addon_upgraded.appDisabled);
Assert.ok(addon_upgraded.isActive);
Assert.equal(addon_upgraded.type, "extension");
await extension.unload();
await promiseShutdownManager();
});
// browser.runtime.reload() without a pending upgrade should just reload.
add_task(async function runtime_reload() {
await promiseStartupManager();