2012-03-06 11:50:58 -08:00
|
|
|
/* 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/. */
|
2011-11-28 12:13:26 -08:00
|
|
|
|
|
|
|
const Cc = Components.classes;
|
|
|
|
const Ci = Components.interfaces;
|
|
|
|
const Cu = Components.utils;
|
|
|
|
const Cr = Components.results;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
2012-03-06 11:50:58 -08:00
|
|
|
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyGetter(Services, "rs", function() {
|
|
|
|
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
|
|
|
|
});
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyGetter(this, "cpmm", function() {
|
|
|
|
return Cc["@mozilla.org/childprocessmessagemanager;1"].getService(Ci.nsIFrameMessageManager);
|
|
|
|
});
|
|
|
|
|
|
|
|
function convertAppsArray(aApps, aWindow) {
|
|
|
|
let apps = new Array();
|
|
|
|
for (let i = 0; i < aApps.length; i++) {
|
|
|
|
let app = aApps[i];
|
|
|
|
apps.push(new WebappsApplication(aWindow, app.origin, app.manifest, app.manifestURL,
|
|
|
|
app.receipts, app.installOrigin, app.installTime));
|
|
|
|
}
|
|
|
|
return apps;
|
|
|
|
}
|
2011-11-28 12:13:26 -08:00
|
|
|
|
|
|
|
function WebappsRegistry() {
|
|
|
|
}
|
|
|
|
|
|
|
|
WebappsRegistry.prototype = {
|
2012-03-06 11:50:58 -08:00
|
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
2011-11-28 12:13:26 -08:00
|
|
|
|
|
|
|
/** from https://developer.mozilla.org/en/OpenWebApps/The_Manifest
|
|
|
|
* only the name property is mandatory
|
|
|
|
*/
|
|
|
|
checkManifest: function(aManifest, aInstallOrigin) {
|
|
|
|
// TODO : check for install_allowed_from
|
|
|
|
if (aManifest.name == undefined)
|
|
|
|
return false;
|
2012-03-06 11:50:58 -08:00
|
|
|
|
2011-11-28 12:13:26 -08:00
|
|
|
if (aManifest.installs_allowed_from) {
|
|
|
|
ok = false;
|
|
|
|
aManifest.installs_allowed_from.forEach(function(aOrigin) {
|
|
|
|
if (aOrigin == "*" || aOrigin == aInstallOrigin)
|
|
|
|
ok = true;
|
|
|
|
});
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
|
|
|
|
receiveMessage: function(aMessage) {
|
|
|
|
let msg = aMessage.json;
|
2012-03-06 11:50:58 -08:00
|
|
|
if (msg.oid != this._id)
|
2011-11-28 12:13:26 -08:00
|
|
|
return
|
2012-03-06 11:50:58 -08:00
|
|
|
let req = this.getRequest(msg.requestID);
|
|
|
|
if (!req)
|
|
|
|
return;
|
2011-11-28 12:13:26 -08:00
|
|
|
let app = msg.app;
|
|
|
|
switch (aMessage.name) {
|
|
|
|
case "Webapps:Install:Return:OK":
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
2011-11-28 12:13:26 -08:00
|
|
|
app.installOrigin, app.installTime));
|
|
|
|
break;
|
|
|
|
case "Webapps:Install:Return:KO":
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireError(req, "DENIED");
|
2011-11-28 12:13:26 -08:00
|
|
|
break;
|
2012-03-06 11:50:58 -08:00
|
|
|
case "Webapps:GetSelf:Return:OK":
|
|
|
|
if (msg.apps.length) {
|
|
|
|
app = msg.apps[0];
|
|
|
|
Services.rs.fireSuccess(req, new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
|
|
|
app.installOrigin, app.installTime));
|
|
|
|
} else {
|
|
|
|
Services.rs.fireSuccess(req, null);
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
break;
|
2012-03-06 11:50:58 -08:00
|
|
|
case "Webapps:GetInstalled:Return:OK":
|
|
|
|
Services.rs.fireSuccess(req, convertAppsArray(msg.apps, this._window));
|
|
|
|
break;
|
|
|
|
case "Webapps:GetSelf:Return:KO":
|
|
|
|
case "Webapps:GetInstalled:Return:KO":
|
|
|
|
Services.rs.fireError(req, "ERROR");
|
2011-11-28 12:13:26 -08:00
|
|
|
break;
|
|
|
|
}
|
2012-03-06 11:50:58 -08:00
|
|
|
this.removeRequest(msg.requestID);
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
_getOrigin: function(aURL) {
|
|
|
|
let uri = Services.io.newURI(aURL, null, null);
|
|
|
|
return uri.prePath;
|
|
|
|
},
|
|
|
|
|
|
|
|
// mozIDOMApplicationRegistry implementation
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
install: function(aURL, aParams) {
|
|
|
|
let request = this.createRequest();
|
|
|
|
let requestID = this.getRequestId(request);
|
2011-11-28 12:13:26 -08:00
|
|
|
let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
|
|
|
|
xhr.open("GET", aURL, true);
|
|
|
|
|
|
|
|
xhr.addEventListener("load", (function() {
|
|
|
|
if (xhr.status == 200) {
|
|
|
|
try {
|
|
|
|
let installOrigin = this._getOrigin(this._window.location.href);
|
|
|
|
let manifest = JSON.parse(xhr.responseText, installOrigin);
|
|
|
|
if (!this.checkManifest(manifest, installOrigin)) {
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireError(request, "INVALID_MANIFEST");
|
2011-11-28 12:13:26 -08:00
|
|
|
} else {
|
2012-03-06 11:50:58 -08:00
|
|
|
let receipts = (aParams && aParams.receipts && Array.isArray(aParams.receipts)) ? aParams.receipts : [];
|
|
|
|
cpmm.sendAsyncMessage("Webapps:Install", { app: { installOrigin: installOrigin,
|
|
|
|
origin: this._getOrigin(aURL),
|
|
|
|
manifestURL: aURL,
|
|
|
|
manifest: manifest,
|
|
|
|
receipts: receipts },
|
|
|
|
from: this._window.location.href,
|
|
|
|
oid: this._id,
|
|
|
|
requestID: requestID });
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
} catch(e) {
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireError(request, "MANIFEST_PARSE_ERROR");
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireError(request, "MANIFEST_URL_ERROR");
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
}).bind(this), false);
|
|
|
|
|
|
|
|
xhr.addEventListener("error", (function() {
|
2012-03-06 11:50:58 -08:00
|
|
|
Services.rs.fireError(request, "NETWORK_ERROR");
|
2011-11-28 12:13:26 -08:00
|
|
|
}).bind(this), false);
|
|
|
|
|
|
|
|
xhr.send(null);
|
2012-03-06 11:50:58 -08:00
|
|
|
return request;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
getSelf: function() {
|
|
|
|
let request = this.createRequest();
|
|
|
|
cpmm.sendAsyncMessage("Webapps:GetSelf", { origin: this._getOrigin(this._window.location.href),
|
|
|
|
oid: this._id,
|
|
|
|
requestID: this.getRequestId(request) });
|
|
|
|
return request;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
getInstalled: function() {
|
|
|
|
let request = this.createRequest();
|
|
|
|
cpmm.sendAsyncMessage("Webapps:GetInstalled", { origin: this._getOrigin(this._window.location.href),
|
2011-11-28 12:13:26 -08:00
|
|
|
oid: this._id,
|
2012-03-06 11:50:58 -08:00
|
|
|
requestID: this.getRequestId(request) });
|
|
|
|
return request;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
get mgmt() {
|
|
|
|
if (!this._mgmt)
|
|
|
|
this._mgmt = new WebappsApplicationMgmt(this._window);
|
|
|
|
return this._mgmt;
|
2011-12-15 09:20:57 -08:00
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
uninit: function() {
|
|
|
|
this._mgmt = null;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
2011-12-07 18:15:42 -08:00
|
|
|
|
2011-11-28 12:13:26 -08:00
|
|
|
// nsIDOMGlobalPropertyInitializer implementation
|
|
|
|
init: function(aWindow) {
|
2012-03-06 11:50:58 -08:00
|
|
|
this.initHelper(aWindow, ["Webapps:Install:Return:OK", "Webapps:Install:Return:KO",
|
|
|
|
"Webapps:GetInstalled:Return:OK", "Webapps:GetInstalled:Return:KO",
|
|
|
|
"Webapps:GetSelf:Return:OK", "Webapps:GetSelf:Return:KO"]);
|
2011-12-07 18:15:42 -08:00
|
|
|
|
|
|
|
Services.obs.addObserver(this, "inner-window-destroyed", false);
|
|
|
|
let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
2012-03-06 11:50:58 -08:00
|
|
|
this._id = util.outerWindowID;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationRegistry, Ci.nsIDOMGlobalPropertyInitializer]),
|
|
|
|
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{fff440b3-fae2-45c1-bf03-3b5a2e432270}"),
|
|
|
|
contractID: "@mozilla.org/webapps;1",
|
|
|
|
interfaces: [Ci.mozIDOMApplicationRegistry],
|
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
|
|
classDescription: "Webapps Registry"})
|
|
|
|
}
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
/**
|
|
|
|
* mozIDOMApplication object
|
|
|
|
*/
|
|
|
|
function WebappsApplication(aWindow, aOrigin, aManifest, aManifestURL, aReceipts, aInstallOrigin, aInstallTime) {
|
2011-11-28 12:13:26 -08:00
|
|
|
this._origin = aOrigin;
|
|
|
|
this._manifest = aManifest;
|
2012-03-06 11:50:58 -08:00
|
|
|
this._manifestURL = aManifestURL;
|
|
|
|
this._receipts = aReceipts;
|
2011-11-28 12:13:26 -08:00
|
|
|
this._installOrigin = aInstallOrigin;
|
|
|
|
this._installTime = aInstallTime;
|
2012-03-06 11:50:58 -08:00
|
|
|
|
|
|
|
this.initHelper(aWindow, ["Webapps:Uninstall:Return:OK", "Webapps:Uninstall:Return:KO"]);
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
WebappsApplication.prototype = {
|
2012-03-06 11:50:58 -08:00
|
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
2011-11-28 12:13:26 -08:00
|
|
|
_origin: null,
|
|
|
|
_manifest: null,
|
2012-03-06 11:50:58 -08:00
|
|
|
_manifestURL: null,
|
|
|
|
_receipts: [],
|
2011-11-28 12:13:26 -08:00
|
|
|
_installOrigin: null,
|
|
|
|
_installTime: 0,
|
|
|
|
|
|
|
|
get origin() {
|
|
|
|
return this._origin;
|
|
|
|
},
|
|
|
|
|
|
|
|
get manifest() {
|
|
|
|
return this._manifest;
|
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
get manifestURL() {
|
|
|
|
return this._manifestURL;
|
|
|
|
},
|
|
|
|
|
|
|
|
get receipts() {
|
|
|
|
return this._receipts;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
get installOrigin() {
|
|
|
|
return this._installOrigin;
|
|
|
|
},
|
|
|
|
|
|
|
|
get installTime() {
|
|
|
|
return this._installTime;
|
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
launch: function(aStartPoint) {
|
|
|
|
let request = this.createRequest();
|
|
|
|
cpmm.sendAsyncMessage("Webapps:Launch", { origin: this._origin,
|
|
|
|
startPoint: aStartPoint,
|
|
|
|
oid: this._id,
|
|
|
|
requestID: this.getRequestId(request) });
|
|
|
|
return request;
|
|
|
|
},
|
|
|
|
|
|
|
|
uninstall: function() {
|
|
|
|
let request = this.createRequest();
|
|
|
|
cpmm.sendAsyncMessage("Webapps:Uninstall", { origin: this._origin,
|
|
|
|
oid: this._id,
|
|
|
|
requestID: this.getRequestId(request) });
|
|
|
|
return request;
|
|
|
|
},
|
|
|
|
|
|
|
|
receiveMessage: function(aMessage) {
|
|
|
|
var msg = aMessage.json;
|
|
|
|
let req = this.getRequest(msg.requestID);
|
|
|
|
if (msg.oid != this._id || !req)
|
|
|
|
return;
|
|
|
|
switch (aMessage.name) {
|
|
|
|
case "Webapps:Uninstall:Return:OK":
|
|
|
|
Services.rs.fireSuccess(req, msg.origin);
|
|
|
|
break;
|
|
|
|
case "Webapps:Uninstall:Return:KO":
|
|
|
|
Services.rs.fireError(req, msg.origin);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.removeRequest(msg.requestID);
|
|
|
|
},
|
|
|
|
|
2011-11-28 12:13:26 -08:00
|
|
|
classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplication]),
|
|
|
|
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{723ed303-7757-4fb0-b261-4f78b1f6bd22}"),
|
|
|
|
contractID: "@mozilla.org/webapps/application;1",
|
|
|
|
interfaces: [Ci.mozIDOMApplication],
|
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
|
|
classDescription: "Webapps Application"})
|
|
|
|
}
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
/**
|
|
|
|
* mozIDOMApplicationMgmt object
|
|
|
|
*/
|
|
|
|
function WebappsApplicationMgmt(aWindow) {
|
|
|
|
let principal = aWindow.document.nodePrincipal;
|
|
|
|
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
|
|
|
|
|
|
|
|
let perm = principal == secMan.getSystemPrincipal() ?
|
|
|
|
Ci.nsIPermissionManager.ALLOW_ACTION :
|
|
|
|
Services.perms.testExactPermission(principal.URI, "webapps-manage");
|
|
|
|
|
|
|
|
//only pages with perm set can use some functions
|
|
|
|
this.hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
|
|
|
|
|
|
|
this.initHelper(aWindow, ["Webapps:GetAll:Return:OK", "Webapps:GetAll:Return:KO",
|
|
|
|
"Webapps:Install:Return:OK", "Webapps:Uninstall:Return:OK"]);
|
|
|
|
|
|
|
|
this._oninstall = null;
|
|
|
|
this._onuninstall = null;
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
WebappsApplicationMgmt.prototype = {
|
|
|
|
__proto__: DOMRequestIpcHelper.prototype,
|
|
|
|
|
|
|
|
uninit: function() {
|
|
|
|
this._oninstall = null;
|
|
|
|
this._onuninstall = null;
|
2011-11-28 12:13:26 -08:00
|
|
|
},
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
getAll: function() {
|
|
|
|
let request = this.createRequest();
|
|
|
|
cpmm.sendAsyncMessage("Webapps:GetAll", { oid: this._id,
|
|
|
|
requestID: this.getRequestId(request),
|
|
|
|
hasPrivileges: this.hasPrivileges });
|
|
|
|
return request;
|
|
|
|
},
|
|
|
|
|
|
|
|
get oninstall() {
|
|
|
|
return this._oninstall;
|
|
|
|
},
|
|
|
|
|
|
|
|
get onuninstall() {
|
|
|
|
this._onuninstall;
|
|
|
|
},
|
|
|
|
|
|
|
|
set oninstall(aCallback) {
|
|
|
|
if (this.hasPrivileges)
|
|
|
|
this._oninstall = aCallback;
|
|
|
|
else
|
2012-03-14 13:39:15 -07:00
|
|
|
throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
|
2012-03-06 11:50:58 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
set onuninstall(aCallback) {
|
|
|
|
if (this.hasPrivileges)
|
|
|
|
this._onuninstall = aCallback;
|
|
|
|
else
|
2012-03-14 13:39:15 -07:00
|
|
|
throw new Components.Exception("Denied", Cr.NS_ERROR_FAILURE);
|
2012-03-06 11:50:58 -08:00
|
|
|
},
|
|
|
|
|
|
|
|
receiveMessage: function(aMessage) {
|
|
|
|
var msg = aMessage.json;
|
|
|
|
let req = this.getRequest(msg.requestID);
|
|
|
|
// We want Webapps:Install:Return:OK and Webapps:Uninstall:Return:OK to be boradcasted
|
|
|
|
// to all instances of mozApps.mgmt
|
|
|
|
if (!((msg.oid == this._id && req)
|
|
|
|
|| aMessage.name == "Webapps:Install:Return:OK" || aMessage.name == "Webapps:Uninstall:Return:OK"))
|
|
|
|
return;
|
|
|
|
switch (aMessage.name) {
|
|
|
|
case "Webapps:GetAll:Return:OK":
|
|
|
|
Services.rs.fireSuccess(req, convertAppsArray(msg.apps, this._window));
|
|
|
|
break;
|
|
|
|
case "Webapps:GetAll:Return:KO":
|
|
|
|
Services.rs.fireError(req, "DENIED");
|
|
|
|
break;
|
|
|
|
case "Webapps:Install:Return:OK":
|
|
|
|
if (this._oninstall) {
|
|
|
|
let app = msg.app;
|
|
|
|
let event = new WebappsApplicationEvent(new WebappsApplication(this._window, app.origin, app.manifest, app.manifestURL, app.receipts,
|
|
|
|
app.installOrigin, app.installTime));
|
|
|
|
this._oninstall.handleEvent(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case "Webapps:Uninstall:Return:OK":
|
|
|
|
if (this._onuninstall) {
|
|
|
|
let event = new WebappsApplicationEvent(new WebappsApplication(this._window, msg.origin, null, null, null, null, 0));
|
|
|
|
this._onuninstall.handleEvent(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.removeRequest(msg.requestID);
|
|
|
|
},
|
|
|
|
|
|
|
|
classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationMgmt]),
|
|
|
|
|
|
|
|
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
|
|
|
|
contractID: "@mozilla.org/webapps/application-mgmt;1",
|
|
|
|
interfaces: [Ci.mozIDOMApplicationMgmt],
|
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
|
|
|
classDescription: "Webapps Application Mgmt"})
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* mozIDOMApplicationEvent object
|
|
|
|
*/
|
|
|
|
function WebappsApplicationEvent(aApp) {
|
|
|
|
this._app = aApp;
|
|
|
|
}
|
|
|
|
|
|
|
|
WebappsApplicationEvent.prototype = {
|
|
|
|
get application() {
|
|
|
|
return this._app;
|
|
|
|
},
|
|
|
|
|
|
|
|
classID: Components.ID("{5bc42b2a-9acc-49d5-a336-c353c8125e48}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.mozIDOMApplicationEvent]),
|
2011-11-28 12:13:26 -08:00
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
classInfo: XPCOMUtils.generateCI({classID: Components.ID("{8c1bca96-266f-493a-8d57-ec7a95098c15}"),
|
|
|
|
contractID: "@mozilla.org/webapps/application-event;1",
|
|
|
|
interfaces: [Ci.mozIDOMApplicationEvent],
|
2011-11-28 12:13:26 -08:00
|
|
|
flags: Ci.nsIClassInfo.DOM_OBJECT,
|
2012-03-06 11:50:58 -08:00
|
|
|
classDescription: "Webapps Application Event"})
|
2011-11-28 12:13:26 -08:00
|
|
|
}
|
|
|
|
|
2012-03-06 11:50:58 -08:00
|
|
|
const NSGetFactory = XPCOMUtils.generateNSGetFactory([WebappsRegistry, WebappsApplication]);
|