mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1200027: Fix installing add-ons from the AMO discovery pane in the add-ons manager. r=dveditz
--HG-- extra : commitid : 94OiH0KUpNn extra : rebase_source : 5d51f94c1627b19bdc438fe05e5475bd3525070d extra : amend_source : 203756cbbab7f0f7dbda20ec003292081d96bb51
This commit is contained in:
parent
a530c7b60d
commit
d78b5ae798
@ -2184,6 +2184,19 @@ var AddonManagerInternal = {
|
||||
return;
|
||||
}
|
||||
|
||||
// When a chrome in-content UI has loaded a <browser> inside to host a
|
||||
// website we want to do our security checks on the inner-browser but
|
||||
// notify front-end that install events came from the outer-browser (the
|
||||
// main tab's browser). Check this by seeing if the browser we've been
|
||||
// passed is in a content type docshell and if so get the outer-browser.
|
||||
let topBrowser = aBrowser;
|
||||
let docShell = aBrowser.ownerDocument.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIDocShellTreeItem);
|
||||
if (docShell.itemType == Ci.nsIDocShellTreeItem.typeContent)
|
||||
topBrowser = docShell.chromeEventHandler;
|
||||
|
||||
try {
|
||||
let weblistener = Cc["@mozilla.org/addons/web-install-listener;1"].
|
||||
getService(Ci.amIWebInstallListener);
|
||||
@ -2192,7 +2205,7 @@ var AddonManagerInternal = {
|
||||
for (let install of aInstalls)
|
||||
install.cancel();
|
||||
|
||||
weblistener.onWebInstallDisabled(aBrowser, aInstallingPrincipal.URI,
|
||||
weblistener.onWebInstallDisabled(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstalls, aInstalls.length);
|
||||
return;
|
||||
}
|
||||
@ -2201,7 +2214,7 @@ var AddonManagerInternal = {
|
||||
install.cancel();
|
||||
|
||||
if (weblistener instanceof Ci.amIWebInstallListener2) {
|
||||
weblistener.onWebInstallOriginBlocked(aBrowser, aInstallingPrincipal.URI,
|
||||
weblistener.onWebInstallOriginBlocked(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstalls, aInstalls.length);
|
||||
}
|
||||
return;
|
||||
@ -2213,14 +2226,14 @@ var AddonManagerInternal = {
|
||||
new BrowserListener(aBrowser, aInstallingPrincipal, aInstalls);
|
||||
|
||||
if (!this.isInstallAllowed(aMimetype, aInstallingPrincipal)) {
|
||||
if (weblistener.onWebInstallBlocked(aBrowser, aInstallingPrincipal.URI,
|
||||
if (weblistener.onWebInstallBlocked(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstalls, aInstalls.length)) {
|
||||
aInstalls.forEach(function(aInstall) {
|
||||
aInstall.install();
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (weblistener.onWebInstallRequested(aBrowser, aInstallingPrincipal.URI,
|
||||
else if (weblistener.onWebInstallRequested(topBrowser, aInstallingPrincipal.URI,
|
||||
aInstalls, aInstalls.length)) {
|
||||
aInstalls.forEach(function(aInstall) {
|
||||
aInstall.install();
|
||||
|
@ -47,6 +47,9 @@ function amManager() {
|
||||
gParentMM = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
gParentMM.addMessageListener(MSG_INSTALL_ENABLED, this);
|
||||
|
||||
// Needed so receiveMessage can be called directly by JS callers
|
||||
this.wrappedJSObject = this;
|
||||
}
|
||||
|
||||
amManager.prototype = {
|
||||
|
@ -12,6 +12,7 @@ const XPI_CONTENT_TYPE = "application/x-xpinstall";
|
||||
const MSG_INSTALL_ADDONS = "WebInstallerInstallAddonsFromWebpage";
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function amContentHandler() {
|
||||
}
|
||||
@ -45,12 +46,7 @@ amContentHandler.prototype = {
|
||||
|
||||
aRequest.cancel(Cr.NS_BINDING_ABORTED);
|
||||
|
||||
let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
|
||||
messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, {
|
||||
let installs = {
|
||||
uris: [uri.spec],
|
||||
hashes: [null],
|
||||
names: [null],
|
||||
@ -58,7 +54,36 @@ amContentHandler.prototype = {
|
||||
mimetype: XPI_CONTENT_TYPE,
|
||||
triggeringPrincipal: aRequest.loadInfo.triggeringPrincipal,
|
||||
callbackID: -1
|
||||
});
|
||||
};
|
||||
|
||||
if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
// When running in the main process this might be a frame inside an
|
||||
// in-content UI page, walk up to find the first frame element in a chrome
|
||||
// privileged document
|
||||
let element = window.frameElement;
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal))
|
||||
element = element.ownerDocument.defaultView.frameElement;
|
||||
|
||||
if (element) {
|
||||
let listener = Cc["@mozilla.org/addons/integration;1"].
|
||||
getService(Ci.nsIMessageListener);
|
||||
listener.wrappedJSObject.receiveMessage({
|
||||
name: MSG_INSTALL_ADDONS,
|
||||
target: element,
|
||||
data: installs,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to sending through the message manager
|
||||
let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
|
||||
messageManager.sendAsyncMessage(MSG_INSTALL_ADDONS, installs);
|
||||
},
|
||||
|
||||
classID: Components.ID("{7beb3ba8-6ec3-41b4-b67c-da89b8518922}"),
|
||||
|
@ -67,18 +67,39 @@ RemoteMediator.prototype = {
|
||||
},
|
||||
|
||||
install: function(installs, principal, callback, window) {
|
||||
let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
|
||||
let callbackID = this._addCallback(callback, installs.uris);
|
||||
|
||||
installs.mimetype = XPINSTALL_MIMETYPE;
|
||||
installs.triggeringPrincipal = principal;
|
||||
installs.callbackID = callbackID;
|
||||
|
||||
if (Services.appinfo.processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
|
||||
// When running in the main process this might be a frame inside an
|
||||
// in-content UI page, walk up to find the first frame element in a chrome
|
||||
// privileged document
|
||||
let element = window.frameElement;
|
||||
let ssm = Services.scriptSecurityManager;
|
||||
while (element && !ssm.isSystemPrincipal(element.ownerDocument.nodePrincipal))
|
||||
element = element.ownerDocument.defaultView.frameElement;
|
||||
|
||||
if (element) {
|
||||
let listener = Cc["@mozilla.org/addons/integration;1"].
|
||||
getService(Ci.nsIMessageListener);
|
||||
return listener.wrappedJSObject.receiveMessage({
|
||||
name: MSG_INSTALL_ADDONS,
|
||||
target: element,
|
||||
data: installs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to sending through the message manager
|
||||
let messageManager = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIContentFrameMessageManager);
|
||||
|
||||
return messageManager.sendSyncMessage(MSG_INSTALL_ADDONS, installs)[0];
|
||||
},
|
||||
|
||||
|
@ -6,6 +6,8 @@ support-files =
|
||||
addon_prefs.xul
|
||||
cancelCompatCheck.sjs
|
||||
discovery.html
|
||||
discovery_frame.html
|
||||
discovery_install.html
|
||||
signed_hotfix.rdf
|
||||
signed_hotfix.xpi
|
||||
unsigned_hotfix.rdf
|
||||
@ -52,5 +54,6 @@ skip-if = e10s
|
||||
[browser_select_update.js]
|
||||
[browser_updatessl.js]
|
||||
[browser_task_next_test.js]
|
||||
[browser_discovery_install.js]
|
||||
|
||||
[include:browser-common.ini]
|
||||
|
@ -0,0 +1,130 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Tests that the discovery view can install add-ons correctly
|
||||
|
||||
const MAIN_URL = "https://example.com/" + RELATIVE_DIR + "discovery_install.html";
|
||||
const GOOD_FRAMED_URL = "https://example.com/" + RELATIVE_DIR + "discovery_frame.html";
|
||||
const BAD_FRAMED_URL = "https://example.org/" + RELATIVE_DIR + "discovery_frame.html";
|
||||
|
||||
// Temporarily enable caching
|
||||
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
|
||||
// Allow SSL from non-built-in certs
|
||||
Services.prefs.setBoolPref("extensions.install.requireBuiltInCerts", false);
|
||||
// Allow installs from the test site
|
||||
Services.perms.add(NetUtil.newURI("https://example.com/"), "install",
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
Services.perms.add(NetUtil.newURI("https://example.org/"), "install",
|
||||
Ci.nsIPermissionManager.ALLOW_ACTION);
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.perms.remove(NetUtil.newURI("https://example.com/"), "install");
|
||||
Services.perms.remove(NetUtil.newURI("https://example.org/"), "install");
|
||||
});
|
||||
|
||||
function clickLink(frameLoader, id) {
|
||||
let link = frameLoader.contentDocument.getElementById(id);
|
||||
EventUtils.sendMouseEvent({type: "click"}, link);
|
||||
}
|
||||
|
||||
function waitForInstall() {
|
||||
return new Promise(resolve => {
|
||||
wait_for_window_open((window) => {
|
||||
is(window.location, "chrome://mozapps/content/xpinstall/xpinstallConfirm.xul",
|
||||
"Should have seen the install window");
|
||||
window.document.documentElement.cancelDialog();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function waitForFail() {
|
||||
return new Promise(resolve => {
|
||||
let listener = (subject, topic, data) => {
|
||||
Services.obs.removeObserver(listener, topic);
|
||||
resolve();
|
||||
}
|
||||
Services.obs.addObserver(listener, "addon-install-origin-blocked", false);
|
||||
});
|
||||
}
|
||||
|
||||
// Tests that navigating to an XPI attempts to install correctly
|
||||
add_task(function* test_install_direct() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
|
||||
clickLink(browser, "install-direct");
|
||||
yield waitForInstall();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
||||
|
||||
// Tests that installing via JS works correctly
|
||||
add_task(function* test_install_js() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, MAIN_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
|
||||
clickLink(browser, "install-js");
|
||||
yield waitForInstall();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
||||
|
||||
// Installing from an inner-frame of the same origin should work
|
||||
add_task(function* test_install_inner_direct() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, GOOD_FRAMED_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
let frame = browser.contentDocument.getElementById("frame");
|
||||
|
||||
clickLink(frame, "install-direct");
|
||||
yield waitForInstall();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
||||
|
||||
add_task(function* test_install_inner_js() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, GOOD_FRAMED_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
let frame = browser.contentDocument.getElementById("frame");
|
||||
|
||||
clickLink(frame, "install-js");
|
||||
yield waitForInstall();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
||||
|
||||
// Installing from an inner-frame of a different origin should fail
|
||||
add_task(function* test_install_xorigin_direct() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, BAD_FRAMED_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
let frame = browser.contentDocument.getElementById("frame");
|
||||
|
||||
clickLink(frame, "install-direct");
|
||||
yield waitForFail();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
||||
|
||||
add_task(function* test_install_xorigin_js() {
|
||||
Services.prefs.setCharPref(PREF_DISCOVERURL, BAD_FRAMED_URL);
|
||||
|
||||
let managerWindow = yield open_manager("addons://discover/");
|
||||
let browser = managerWindow.document.getElementById("discover-browser");
|
||||
let frame = browser.contentDocument.getElementById("frame");
|
||||
|
||||
clickLink(frame, "install-js");
|
||||
yield waitForFail();
|
||||
|
||||
yield close_manager(managerWindow);
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<iframe id="frame" width="100%" height="100%" src="https://example.com/browser/toolkit/mozapps/extensions/test/browser/discovery_install.html"></iframe>
|
||||
</body>
|
@ -0,0 +1,18 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function install() {
|
||||
InstallTrigger.install({
|
||||
"Test Add-on": {
|
||||
URL: "https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi"
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test page for the discovery pane</h1>
|
||||
<p><a id="install-direct" href="https://example.com/browser/toolkit/mozapps/extensions/test/xpinstall/unsigned.xpi">Direct install</a></p>
|
||||
<p><a id="install-js" href="javascript:install()">JS install</a></p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user