209 lines
5.6 KiB
JavaScript
209 lines
5.6 KiB
JavaScript
"use strict";
|
|
|
|
// We don't have an easy way to serve update manifests from a secure URL.
|
|
Services.prefs.setBoolPref(PREF_EM_CHECK_UPDATE_SECURITY, false);
|
|
|
|
var testserver = createHttpServer();
|
|
gPort = testserver.identity.primaryPort;
|
|
|
|
const uuidGenerator = Services.uuid;
|
|
|
|
const extensionsDir = gProfD.clone();
|
|
extensionsDir.append("extensions");
|
|
|
|
const addonsDir = gTmpD.clone();
|
|
addonsDir.append("addons");
|
|
addonsDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
|
|
|
registerCleanupFunction(() => addonsDir.remove(true));
|
|
|
|
testserver.registerDirectory("/addons/", addonsDir);
|
|
|
|
let gUpdateManifests = {};
|
|
|
|
function mapManifest(aPath, aManifestData) {
|
|
gUpdateManifests[aPath] = aManifestData;
|
|
testserver.registerPathHandler(aPath, serveManifest);
|
|
}
|
|
|
|
function serveManifest(request, response) {
|
|
let manifest = gUpdateManifests[request.path];
|
|
|
|
response.setHeader("Content-Type", manifest.contentType, false);
|
|
response.write(manifest.data);
|
|
}
|
|
|
|
async function promiseInstallWebExtension(aData) {
|
|
let addonFile = createTempWebExtensionFile(aData);
|
|
|
|
let { addon } = await promiseInstallFile(addonFile);
|
|
Services.obs.notifyObservers(addonFile, "flush-cache-entry");
|
|
return addon;
|
|
}
|
|
|
|
var checkUpdates = async function (
|
|
aData,
|
|
aReason = AddonManager.UPDATE_WHEN_PERIODIC_UPDATE
|
|
) {
|
|
function provide(obj, path, value) {
|
|
path = path.split(".");
|
|
let prop = path.pop();
|
|
|
|
for (let key of path) {
|
|
if (!(key in obj)) {
|
|
obj[key] = {};
|
|
}
|
|
obj = obj[key];
|
|
}
|
|
|
|
if (!(prop in obj)) {
|
|
obj[prop] = value;
|
|
}
|
|
}
|
|
|
|
let id = uuidGenerator.generateUUID().number;
|
|
provide(aData, "addon.id", id);
|
|
provide(aData, "addon.manifest.browser_specific_settings.gecko.id", id);
|
|
|
|
let updatePath = `/updates/${id}.json`.replace(/[{}]/g, "");
|
|
let updateUrl = `http://localhost:${gPort}${updatePath}`;
|
|
|
|
let addonData = { updates: [] };
|
|
let manifestJSON = {
|
|
addons: { [id]: addonData },
|
|
};
|
|
|
|
provide(
|
|
aData,
|
|
"addon.manifest.browser_specific_settings.gecko.update_url",
|
|
updateUrl
|
|
);
|
|
let awaitInstall = promiseInstallWebExtension(aData.addon);
|
|
|
|
for (let version of Object.keys(aData.updates)) {
|
|
let update = aData.updates[version];
|
|
update.version = version;
|
|
|
|
// Create an add-on manifest based on what's in the current `update`.
|
|
provide(update, "addon.id", id);
|
|
provide(update, "addon.manifest.browser_specific_settings.gecko.id", id);
|
|
let addon = update.addon;
|
|
|
|
delete update.addon;
|
|
|
|
provide(addon, "manifest.version", version);
|
|
let file = createTempWebExtensionFile(addon);
|
|
file.moveTo(addonsDir, `${id}-${version}.xpi`.replace(/[{}]/g, ""));
|
|
|
|
let path = `/addons/${file.leafName}`;
|
|
provide(update, "update_link", `http://localhost:${gPort}${path}`);
|
|
|
|
addonData.updates.push(update);
|
|
}
|
|
|
|
mapManifest(updatePath, {
|
|
data: JSON.stringify(manifestJSON),
|
|
contentType: "application/json",
|
|
});
|
|
|
|
let addon = await awaitInstall;
|
|
|
|
let updates = await promiseFindAddonUpdates(addon, aReason);
|
|
updates.addon = addon;
|
|
|
|
return updates;
|
|
};
|
|
|
|
add_task(async function setup() {
|
|
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "42.0", "42.0");
|
|
|
|
await promiseStartupManager();
|
|
registerCleanupFunction(promiseShutdownManager);
|
|
});
|
|
|
|
// Check that compatibility updates are applied.
|
|
add_task(async function checkUpdateMetadata() {
|
|
let update = await checkUpdates({
|
|
addon: {
|
|
manifest: {
|
|
version: "1.0",
|
|
browser_specific_settings: { gecko: { strict_max_version: "45" } },
|
|
},
|
|
},
|
|
updates: {
|
|
"1.0": {
|
|
applications: {
|
|
gecko: { strict_min_version: "40", strict_max_version: "48" },
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
ok(update.compatibilityUpdate, "have compat update");
|
|
ok(!update.updateAvailable, "have no add-on update");
|
|
|
|
ok(update.addon.isCompatibleWith("40", "40"), "compatible min");
|
|
ok(update.addon.isCompatibleWith("48", "48"), "compatible max");
|
|
ok(!update.addon.isCompatibleWith("49", "49"), "not compatible max");
|
|
|
|
await update.addon.uninstall();
|
|
});
|
|
|
|
// Check that updates from web extensions to web extensions succeed.
|
|
add_task(async function checkUpdateToWebExt() {
|
|
let update = await checkUpdates({
|
|
addon: { manifest: { version: "1.0" } },
|
|
updates: {
|
|
1.1: {},
|
|
1.2: {},
|
|
1.3: { applications: { gecko: { strict_min_version: "48" } } },
|
|
},
|
|
});
|
|
|
|
ok(!update.compatibilityUpdate, "have no compat update");
|
|
ok(update.updateAvailable, "have add-on update");
|
|
|
|
equal(update.addon.version, "1.0", "add-on version");
|
|
|
|
await update.updateAvailable.install();
|
|
|
|
let addon = await promiseAddonByID(update.addon.id);
|
|
equal(addon.version, "1.2", "new add-on version");
|
|
|
|
await addon.uninstall();
|
|
});
|
|
|
|
// Check that illegal update URLs are rejected.
|
|
add_task(async function checkIllegalUpdateURL() {
|
|
const URLS = [
|
|
"chrome://browser/content/",
|
|
"data:text/json,...",
|
|
"javascript:;",
|
|
"/",
|
|
];
|
|
|
|
for (let url of URLS) {
|
|
let { messages } = await promiseConsoleOutput(() => {
|
|
let addonFile = createTempWebExtensionFile({
|
|
manifest: { browser_specific_settings: { gecko: { update_url: url } } },
|
|
});
|
|
|
|
return AddonManager.getInstallForFile(addonFile).then(install => {
|
|
Services.obs.notifyObservers(addonFile, "flush-cache-entry");
|
|
|
|
if (!install || install.state != AddonManager.STATE_DOWNLOAD_FAILED) {
|
|
throw new Error("Unexpected state: " + (install && install.state));
|
|
}
|
|
});
|
|
});
|
|
|
|
ok(
|
|
messages.some(msg =>
|
|
/Access denied for URL|may not load or link to|is not a valid URL/.test(
|
|
msg
|
|
)
|
|
),
|
|
"Got checkLoadURI error"
|
|
);
|
|
}
|
|
});
|