Bug 1255562 Allow applications property to be in mozilla.json r?mossop
MozReview-Commit-ID: 8w6s4bVgbxE
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -665,26 +665,44 @@ ExtensionData.prototype = {
resolve(JSON.parse(text));
} catch (e) {
reject(e);
}
});
});
},
- // Reads the extension's |manifest.json| file, and stores its
- // parsed contents in |this.manifest|.
+ // Reads the extension's |manifest.json| file and optional |mozilla.json|,
+ // and stores the parsed and merged contents in |this.manifest|.
readManifest() {
return Promise.all([
this.readJSON("manifest.json"),
+ this.readJSON("mozilla.json").catch(err => null),
Management.lazyInit(),
- ]).then(([manifest]) => {
+ ]).then(([manifest, mozManifest]) => {
this.manifest = manifest;
this.rawManifest = manifest;
+ if (mozManifest) {
+ if (typeof mozManifest != "object") {
+ this.logger.warn(`Loading extension '${this.id}': mozilla.json has unexpected type ${typeof mozManifest}`);
+ } else {
+ Object.keys(mozManifest).forEach(key => {
+ if (key != "applications") {
+ throw new Error(`Illegal property "${key}" in mozilla.json`);
+ }
+ if (key in manifest) {
+ this.logger.warn(`Ignoring property "${key}" from mozilla.json`);
+ } else {
+ manifest[key] = mozManifest[key];
+ }
+ });
+ }
+ }
+
if (manifest && manifest.default_locale) {
return this.initLocale();
}
}).then(() => {
let context = {
url: this.baseURI && this.baseURI.spec,
principal: this.principal,
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -268,43 +268,44 @@ function createAppInfo(ID, name, version
crashReporter: true,
extraProps: {
browserTabsRemoteAutostart: false,
},
});
gAppInfo = tmp.getAppInfo();
}
-function getManifestURIForBundle(file) {
+function getManifestURIForBundle(file, manifest="manifest.json") {
if (file.isDirectory()) {
- file.append("install.rdf");
- if (file.exists()) {
- return NetUtil.newURI(file);
+ let path = file.clone();
+ path.append("install.rdf");
+ if (path.exists()) {
+ return NetUtil.newURI(path);
}
- file.leafName = "manifest.json";
- if (file.exists()) {
- return NetUtil.newURI(file);
+ path.leafName = manifest;
+ if (path.exists()) {
+ return NetUtil.newURI(path);
}
throw new Error("No manifest file present");
}
let zip = AM_Cc["@mozilla.org/libjar/zip-reader;1"].
createInstance(AM_Ci.nsIZipReader);
zip.open(file);
try {
let uri = NetUtil.newURI(file);
if (zip.hasEntry("install.rdf")) {
return NetUtil.newURI("jar:" + uri.spec + "!/" + "install.rdf");
}
- if (zip.hasEntry("manifest.json")) {
- return NetUtil.newURI("jar:" + uri.spec + "!/" + "manifest.json");
+ if (zip.hasEntry(manifest)) {
+ return NetUtil.newURI("jar:" + uri.spec + "!/" + manifest);
}
throw new Error("No manifest file present");
}
finally {
zip.close();
}
}
@@ -336,18 +337,22 @@ let getIDForManifest = Task.async(functi
getService(AM_Ci.nsIRDFService);
let rdfID = ds.GetTarget(rdfService.GetResource("urn:mozilla:install-manifest"),
rdfService.GetResource("http://www.mozilla.org/2004/em-rdf#id"),
true);
return rdfID.QueryInterface(AM_Ci.nsIRDFLiteral).Value;
}
else {
- let manifest = JSON.parse(data);
- return manifest.applications.gecko.id;
+ try {
+ let manifest = JSON.parse(data);
+ return manifest.applications.gecko.id;
+ } catch (err) {
+ return null;
+ }
}
});
let gUseRealCertChecks = false;
function overrideCertDB(handler) {
// Unregister the real database. This only works because the add-ons manager
// hasn't started up and grabbed the certificate database yet.
let registrar = Components.manager.QueryInterface(AM_Ci.nsIComponentRegistrar);
@@ -375,16 +380,25 @@ function overrideCertDB(handler) {
return;
}
try {
let manifestURI = getManifestURIForBundle(file);
let id = yield getIDForManifest(manifestURI);
+ if (!id) {
+ manifestURI = getManifestURIForBundle(file, "mozilla.json");
+ id = yield getIDForManifest(manifestURI);
+ }
+
+ if (!id) {
+ throw new Error("Cannot find addon ID");
+ }
+
// Make sure to close the open zip file or it will be locked.
if (file.isFile()) {
Services.obs.notifyObservers(file, "flush-cache-entry", "cert-override");
}
let fakeCert = {
commonName: id
}
@@ -1107,54 +1121,68 @@ function writeInstallRDFForExtension(aDa
* @param aManifest
* The data to write
* @param aDir
* The install directory to add the extension to
* @param aId
* An optional string to override the default installation aId
* @return A file pointing to where the extension was installed
*/
-function writeWebManifestForExtension(aData, aDir, aId = undefined) {
+function writeWebManifestForExtension(aData, aDir, aId = undefined, aMozData = undefined) {
if (!aId)
aId = aData.applications.gecko.id;
if (TEST_UNPACKED) {
let dir = aDir.clone();
dir.append(aId);
if (!dir.exists())
dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
- let file = dir.clone();
- file.append("manifest.json");
- if (file.exists())
- file.remove(true);
+ function writeOne(filename, raw) {
+ let file = dir.clone();
+ file.append(filename);
+ if (file.exists())
+ file.remove(true);
- let data = JSON.stringify(aData);
- let fos = AM_Cc["@mozilla.org/network/file-output-stream;1"].
- createInstance(AM_Ci.nsIFileOutputStream);
- fos.init(file,
- FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
- FileUtils.PERMS_FILE, 0);
- fos.write(data, data.length);
- fos.close();
+ let data = JSON.stringify(raw);
+ let fos = AM_Cc["@mozilla.org/network/file-output-stream;1"].
+ createInstance(AM_Ci.nsIFileOutputStream);
+ fos.init(file,
+ FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
+ FileUtils.PERMS_FILE, 0);
+ fos.write(data, data.length);
+ fos.close();
+ }
+
+ writeOne("manifest.json", aData);
+ if (aMozData) {
+ writeOne("mozilla.json", aMozData);
+ }
return dir;
}
else {
let file = aDir.clone();
file.append(aId + ".xpi");
let stream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
createInstance(AM_Ci.nsIStringInputStream);
stream.setData(JSON.stringify(aData), -1);
let zipW = AM_Cc["@mozilla.org/zipwriter;1"].
createInstance(AM_Ci.nsIZipWriter);
zipW.open(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);
zipW.addEntryStream("manifest.json", 0, AM_Ci.nsIZipWriter.COMPRESSION_NONE,
stream, false);
+ if (aMozData) {
+ let mozStream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
+ createInstance(AM_Ci.nsIStringInputStream);
+ mozStream.setData(JSON.stringify(aMozData), -1);
+ zipW.addEntryStream("mozilla.json", 0, AM_Ci.nsIZipWriter.COMPRESSION_NONE,
+ mozStream, false);
+ }
zipW.close();
return file;
}
}
/**
* Writes an install.rdf manifest into a packed extension using the properties passed
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
@@ -154,16 +154,51 @@ add_task(function*() {
let file = getFileForAddon(profileDir, ID);
do_check_true(file.exists());
addon.uninstall();
yield promiseRestartManager();
});
+// applications.gecko.id may be in mozilla.json
+add_task(function* test_mozilla_json() {
+ writeWebManifestForExtension({
+ name: "Web Extension Name",
+ version: "1.0",
+ manifest_version: 2,
+ }, profileDir, ID, {
+ applications: {
+ gecko: {
+ id: ID
+ }
+ }
+ });
+
+ yield promiseRestartManager();
+
+ let addon = yield promiseAddonByID(ID);
+ do_check_neq(addon, null);
+ do_check_eq(addon.version, "1.0");
+ do_check_eq(addon.name, "Web Extension Name");
+ do_check_true(addon.isCompatible);
+ do_check_false(addon.appDisabled);
+ do_check_true(addon.isActive);
+ do_check_false(addon.isSystem);
+ do_check_eq(addon.type, "extension");
+ do_check_eq(addon.signedState, mozinfo.addon_signing ? AddonManager.SIGNEDSTATE_SIGNED : AddonManager.SIGNEDSTATE_NOT_REQUIRED);
+
+ let file = getFileForAddon(profileDir, ID);
+ do_check_true(file.exists());
+
+ addon.uninstall();
+
+ yield promiseRestartManager();
+});
+
add_task(function* test_manifest_localization() {
const ID = "webextension3@tests.mozilla.org";
yield promiseInstallAllFiles([do_get_addon("webextension_3")], true);
yield promiseAddonStartup();
let addon = yield promiseAddonByID(ID);
addon.userDisabled = true;