mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-06 09:05:45 +00:00
0d398a243a
MozReview-Commit-ID: G5UuAh2RiZZ --HG-- rename : toolkit/modules/Task.jsm => devtools/shared/task.js extra : transplant_source : %B8h%8A%8C%BD%91%8A%81%1D%F4%F5%2Ap%CFv%BC%963u0
293 lines
9.2 KiB
JavaScript
293 lines
9.2 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
"use strict";
|
|
|
|
var {Ci, Cu, CC} = require("chrome");
|
|
const promise = require("promise");
|
|
|
|
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", {});
|
|
const Services = require("Services");
|
|
const {Task} = require("devtools/shared/task");
|
|
var XMLHttpRequest = CC("@mozilla.org/xmlextras/xmlhttprequest;1");
|
|
var strings = Services.strings.createBundle("chrome://devtools/locale/app-manager.properties");
|
|
|
|
function AppValidator({ type, location }) {
|
|
this.type = type;
|
|
this.location = location;
|
|
this.errors = [];
|
|
this.warnings = [];
|
|
}
|
|
|
|
AppValidator.prototype.error = function (message) {
|
|
this.errors.push(message);
|
|
};
|
|
|
|
AppValidator.prototype.warning = function (message) {
|
|
this.warnings.push(message);
|
|
};
|
|
|
|
AppValidator.prototype._getPackagedManifestFile = function () {
|
|
let manifestFile = FileUtils.File(this.location);
|
|
if (!manifestFile.exists()) {
|
|
this.error(strings.GetStringFromName("validator.nonExistingFolder"));
|
|
return null;
|
|
}
|
|
if (!manifestFile.isDirectory()) {
|
|
this.error(strings.GetStringFromName("validator.expectProjectFolder"));
|
|
return null;
|
|
}
|
|
|
|
let appManifestFile = manifestFile.clone();
|
|
appManifestFile.append("manifest.webapp");
|
|
|
|
let jsonManifestFile = manifestFile.clone();
|
|
jsonManifestFile.append("manifest.json");
|
|
|
|
let hasAppManifest = appManifestFile.exists() && appManifestFile.isFile();
|
|
let hasJsonManifest = jsonManifestFile.exists() && jsonManifestFile.isFile();
|
|
|
|
if (!hasAppManifest && !hasJsonManifest) {
|
|
this.error(strings.GetStringFromName("validator.noManifestFile"));
|
|
return null;
|
|
}
|
|
|
|
return hasAppManifest ? appManifestFile : jsonManifestFile;
|
|
};
|
|
|
|
AppValidator.prototype._getPackagedManifestURL = function () {
|
|
let manifestFile = this._getPackagedManifestFile();
|
|
if (!manifestFile) {
|
|
return null;
|
|
}
|
|
return Services.io.newFileURI(manifestFile).spec;
|
|
};
|
|
|
|
AppValidator.checkManifest = function (manifestURL) {
|
|
let deferred = promise.defer();
|
|
let error;
|
|
|
|
let req = new XMLHttpRequest();
|
|
req.overrideMimeType("text/plain");
|
|
|
|
try {
|
|
req.open("GET", manifestURL, true);
|
|
} catch (e) {
|
|
error = strings.formatStringFromName("validator.invalidManifestURL", [manifestURL], 1);
|
|
deferred.reject(error);
|
|
return deferred.promise;
|
|
}
|
|
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
|
|
|
req.onload = function () {
|
|
let manifest = null;
|
|
try {
|
|
manifest = JSON.parse(req.responseText);
|
|
} catch (e) {
|
|
error = strings.formatStringFromName("validator.invalidManifestJSON", [e, manifestURL], 2);
|
|
deferred.reject(error);
|
|
}
|
|
|
|
deferred.resolve({manifest, manifestURL});
|
|
};
|
|
|
|
req.onerror = function () {
|
|
error = strings.formatStringFromName("validator.noAccessManifestURL", [req.statusText, manifestURL], 2);
|
|
deferred.reject(error);
|
|
};
|
|
|
|
try {
|
|
req.send(null);
|
|
} catch (e) {
|
|
error = strings.formatStringFromName("validator.noAccessManifestURL", [e, manifestURL], 2);
|
|
deferred.reject(error);
|
|
}
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
AppValidator.findManifestAtOrigin = function (manifestURL) {
|
|
let fixedManifest = Services.io.newURI(manifestURL, null, null).prePath + "/manifest.webapp";
|
|
return AppValidator.checkManifest(fixedManifest);
|
|
};
|
|
|
|
AppValidator.findManifestPath = function (manifestURL) {
|
|
let deferred = promise.defer();
|
|
|
|
if (manifestURL.endsWith("manifest.webapp")) {
|
|
deferred.reject();
|
|
} else {
|
|
let fixedManifest = manifestURL + "/manifest.webapp";
|
|
deferred.resolve(AppValidator.checkManifest(fixedManifest));
|
|
}
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
AppValidator.checkAlternateManifest = function (manifestURL) {
|
|
return Task.spawn(function* () {
|
|
let result;
|
|
try {
|
|
result = yield AppValidator.findManifestPath(manifestURL);
|
|
} catch (e) {
|
|
result = yield AppValidator.findManifestAtOrigin(manifestURL);
|
|
}
|
|
|
|
return result;
|
|
});
|
|
};
|
|
|
|
AppValidator.prototype._fetchManifest = function (manifestURL) {
|
|
let deferred = promise.defer();
|
|
this.manifestURL = manifestURL;
|
|
|
|
AppValidator.checkManifest(manifestURL)
|
|
.then(({manifest, manifestURL}) => {
|
|
deferred.resolve(manifest);
|
|
}, error => {
|
|
AppValidator.checkAlternateManifest(manifestURL)
|
|
.then(({manifest, manifestURL}) => {
|
|
this.manifestURL = manifestURL;
|
|
deferred.resolve(manifest);
|
|
}, () => {
|
|
this.error(error);
|
|
deferred.resolve(null);
|
|
});
|
|
});
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
AppValidator.prototype._getManifest = function () {
|
|
let manifestURL;
|
|
if (this.type == "packaged") {
|
|
manifestURL = this._getPackagedManifestURL();
|
|
if (!manifestURL)
|
|
return promise.resolve(null);
|
|
} else if (this.type == "hosted") {
|
|
manifestURL = this.location;
|
|
try {
|
|
Services.io.newURI(manifestURL, null, null);
|
|
} catch (e) {
|
|
this.error(strings.formatStringFromName("validator.invalidHostedManifestURL", [manifestURL, e.message], 2));
|
|
return promise.resolve(null);
|
|
}
|
|
} else {
|
|
this.error(strings.formatStringFromName("validator.invalidProjectType", [this.type], 1));
|
|
return promise.resolve(null);
|
|
}
|
|
return this._fetchManifest(manifestURL);
|
|
};
|
|
|
|
AppValidator.prototype.validateManifest = function (manifest) {
|
|
if (!manifest.name) {
|
|
this.error(strings.GetStringFromName("validator.missNameManifestProperty"));
|
|
}
|
|
|
|
if (!manifest.icons || Object.keys(manifest.icons).length === 0) {
|
|
this.warning(strings.GetStringFromName("validator.missIconsManifestProperty"));
|
|
} else if (!manifest.icons["128"]) {
|
|
this.warning(strings.GetStringFromName("validator.missIconMarketplace2"));
|
|
}
|
|
};
|
|
|
|
AppValidator.prototype._getOriginURL = function () {
|
|
if (this.type == "packaged") {
|
|
let manifestURL = Services.io.newURI(this.manifestURL, null, null);
|
|
return Services.io.newURI(".", null, manifestURL).spec;
|
|
} else if (this.type == "hosted") {
|
|
return Services.io.newURI(this.location, null, null).prePath;
|
|
}
|
|
};
|
|
|
|
AppValidator.prototype.validateLaunchPath = function (manifest) {
|
|
let deferred = promise.defer();
|
|
// The launch_path field has to start with a `/`
|
|
if (manifest.launch_path && manifest.launch_path[0] !== "/") {
|
|
this.error(strings.formatStringFromName("validator.nonAbsoluteLaunchPath", [manifest.launch_path], 1));
|
|
deferred.resolve();
|
|
return deferred.promise;
|
|
}
|
|
let origin = this._getOriginURL();
|
|
let path;
|
|
if (this.type == "packaged") {
|
|
path = "." + (manifest.launch_path || "/index.html");
|
|
} else if (this.type == "hosted") {
|
|
path = manifest.launch_path || "/";
|
|
}
|
|
let indexURL;
|
|
try {
|
|
indexURL = Services.io.newURI(path, null, Services.io.newURI(origin, null, null)).spec;
|
|
} catch (e) {
|
|
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [origin + path], 1));
|
|
deferred.resolve();
|
|
return deferred.promise;
|
|
}
|
|
|
|
let req = new XMLHttpRequest();
|
|
req.overrideMimeType("text/plain");
|
|
try {
|
|
req.open("HEAD", indexURL, true);
|
|
} catch (e) {
|
|
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
|
deferred.resolve();
|
|
return deferred.promise;
|
|
}
|
|
req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_CACHING;
|
|
req.onload = () => {
|
|
if (req.status >= 400)
|
|
this.error(strings.formatStringFromName("validator.accessFailedLaunchPathBadHttpCode", [indexURL, req.status], 2));
|
|
deferred.resolve();
|
|
};
|
|
req.onerror = () => {
|
|
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
|
deferred.resolve();
|
|
};
|
|
|
|
try {
|
|
req.send(null);
|
|
} catch (e) {
|
|
this.error(strings.formatStringFromName("validator.accessFailedLaunchPath", [indexURL], 1));
|
|
deferred.resolve();
|
|
}
|
|
|
|
return deferred.promise;
|
|
};
|
|
|
|
AppValidator.prototype.validateType = function (manifest) {
|
|
let appType = manifest.type || "web";
|
|
if (["web", "privileged", "certified"].indexOf(appType) === -1) {
|
|
this.error(strings.formatStringFromName("validator.invalidAppType", [appType], 1));
|
|
} else if (this.type == "hosted" &&
|
|
["certified", "privileged"].indexOf(appType) !== -1) {
|
|
this.error(strings.formatStringFromName("validator.invalidHostedPriviledges", [appType], 1));
|
|
}
|
|
|
|
// certified app are not fully supported on the simulator
|
|
if (appType === "certified") {
|
|
this.warning(strings.GetStringFromName("validator.noCertifiedSupport"));
|
|
}
|
|
};
|
|
|
|
AppValidator.prototype.validate = function () {
|
|
this.errors = [];
|
|
this.warnings = [];
|
|
return this._getManifest().
|
|
then((manifest) => {
|
|
if (manifest) {
|
|
this.manifest = manifest;
|
|
|
|
// Skip validations for add-ons
|
|
if (manifest.role === "addon" || manifest.manifest_version) {
|
|
return promise.resolve();
|
|
}
|
|
|
|
this.validateManifest(manifest);
|
|
this.validateType(manifest);
|
|
return this.validateLaunchPath(manifest);
|
|
}
|
|
});
|
|
};
|
|
|
|
exports.AppValidator = AppValidator;
|