Bug 1191619 - Support extensions with no packaged manifest.webapp r=ferjm

This commit is contained in:
Fabrice Desré 2015-08-14 16:55:14 -07:00
parent 6c5bfd7cca
commit 7500f65897
10 changed files with 130 additions and 12 deletions

View File

@ -14,6 +14,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ValueExtractor",
"resource://gre/modules/ValueExtractor.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "console",
"@mozilla.org/consoleservice;1",
@ -64,6 +66,79 @@ this.UserCustomizations = {
}
},
// Checks that this is a valid extension manifest.
// The format is documented at https://developer.chrome.com/extensions/manifest
checkExtensionManifest: function(aManifest) {
if (!aManifest) {
return false;
}
const extractor = new ValueExtractor(console);
const manifestVersionSpec = {
objectName: "extension manifest",
object: aManifest,
property: "manifest_version",
expectedType: "number",
trim: true
}
const nameSpec = {
objectName: "extension manifest",
object: aManifest,
property: "name",
expectedType: "string",
trim: true
}
const versionSpec = {
objectName: "extension manifest",
object: aManifest,
property: "version",
expectedType: "string",
trim: true
}
let res =
extractor.extractValue(manifestVersionSpec) !== undefined &&
extractor.extractValue(nameSpec) !== undefined &&
extractor.extractValue(versionSpec) !== undefined;
return res;
},
// Converts a chrome extension manifest into a webapp manifest.
convertManifest: function(aManifest) {
if (!aManifest) {
return null;
}
// Set the type to privileged to ensure we only allow signed addons.
let result = {
"type": "privileged",
"name": aManifest.name,
"role": "addon"
}
if (aManifest.description) {
result.description = aManifest.description;
}
if (aManifest.icons) {
result.icons = aManifest.icons;
}
// chrome extension manifests have a single 'author' property, that we
// map to 'developer.name'.
// Note that it has to match the one in the mini-manifest.
if (aManifest.author) {
result.developer = {
name: aManifest.author
}
}
return result;
},
init: function() {
this._enabled = false;
try {

View File

@ -3757,11 +3757,21 @@ this.DOMApplicationRegistry = {
aIsSigned) {
this._checkSignature(aNewApp, aIsSigned, aIsLocalFileInstall);
if (!aZipReader.hasEntry("manifest.webapp")) {
// Chrome-style extensions only have a manifest.json manifest.
// In this case we extract it, and convert it to a minimal
// manifest.webapp manifest.
// Packages that contain both manifest.webapp and manifest.json
// are considered as apps, not extensions.
let hasWebappManifest = aZipReader.hasEntry("manifest.webapp");
let hasJsonManifest = aZipReader.hasEntry("manifest.json");
if (!hasWebappManifest && !hasJsonManifest) {
throw "MISSING_MANIFEST";
}
let istream = aZipReader.getInputStream("manifest.webapp");
let istream =
aZipReader.getInputStream(hasWebappManifest ? "manifest.webapp"
: "manifest.json");
// Obtain a converter to read from a UTF-8 encoded input stream.
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
@ -3771,6 +3781,14 @@ this.DOMApplicationRegistry = {
let newManifest = JSON.parse(converter.ConvertToUnicode(
NetUtil.readInputStreamToString(istream, istream.available()) || ""));
if (!hasWebappManifest) {
// Validate the extension manifest, and convert it.
if (!UserCustomizations.checkExtensionManifest(newManifest)) {
throw "INVALID_MANIFEST";
}
newManifest = UserCustomizations.convertManifest(newManifest);
}
if (!AppsUtils.checkManifest(newManifest, aOldApp)) {
throw "INVALID_MANIFEST";
}
@ -3814,8 +3832,11 @@ this.DOMApplicationRegistry = {
let isLangPack = newManifest.role === "langpack" &&
(aIsSigned || allowUnsignedLangpack);
let isAddon = newManifest.role === "addon" &&
(aIsSigned || AppsUtils.allowUnsignedAddons);
let status = AppsUtils.getAppManifestStatus(newManifest);
if (status > maxStatus && !isLangPack) {
if (status > maxStatus && !isLangPack && !isAddon) {
throw "INVALID_SECURITY_LEVEL";
}

View File

@ -0,0 +1,6 @@
{
"name": "Addon app with an invalid name",
"description": "Let me inject script and css!",
"developer": { "name": "The Mozilla Community" },
"package_path" : "application.zip"
}

View File

@ -0,0 +1 @@
Content-Type: application/manifest+json

View File

@ -4,6 +4,7 @@
"manifest_version": 2,
"permissions": ["tabs"],
"description": "Let me inject script and css!",
"author": "The Mozilla Community",
"content_scripts": [
{"matches": ["http://mochi.test/tests/dom/apps/tests/addons/index.html"],
"js": ["script.js", "script2.js", "invalid.js", "script.js"],

View File

@ -1,5 +0,0 @@
{
"name": "Addon app",
"description": "Let me inject script and css!",
"role": "addon"
}

View File

@ -1,5 +1,6 @@
{
"name": "Addon app",
"description": "Let me inject script and css!",
"developer": { "name": "The Mozilla Community" },
"package_path" : "application.zip"
}

View File

@ -2,6 +2,8 @@
skip-if = e10s
support-files =
addons/application.zip
addons/invalid.webapp
addons/invalid.webapp^headers^
addons/update.webapp
addons/update.webapp^headers^
addons/index.html

View File

@ -20,7 +20,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1042881
SimpleTest.waitForExplicitFinish();
let appManifestURL = "http://mochi.test:8888/tests/dom/apps/tests/addons/update.webapp";
const baseURL = "http://mochi.test:8888/tests/dom/apps/tests/addons/";
const appManifestURL = baseURL + "update.webapp";
const invalidAppManifestURL = baseURL + "invalid.webapp";
let gGenerator = runTest();
@ -68,7 +71,7 @@ function openPage(pageURL, messages) {
let apps = [];
function installApp(manifestURL) {
function installApp(manifestURL, expectedError) {
info("About to install app at " + manifestURL);
let req = navigator.mozApps.installPackage(manifestURL);
req.onsuccess = function() {
@ -82,6 +85,15 @@ function installApp(manifestURL) {
is(req.result.installState, "installed", "app downloaded");
continueTest();
}
req.result.ondownloaderror = function() {
if (expectedError) {
ok(true, "expected installation error.");
} else {
ok(false, "unexpected installation error.");
}
continueTest();
}
}
}
req.onerror = mozAppsError;
@ -116,8 +128,12 @@ function runTest() {
"Uncustomized content", "rgb(0, 0, 0)"]);
yield undefined;
// Install addon app.
installApp(appManifestURL);
// Install addon app with an invalid manifest.
installApp(invalidAppManifestURL, true);
yield undefined;
// Install valid addon app.
installApp(appManifestURL, false);
yield undefined;
// Opens the iframe to the test page, customized.