From 5ed770e1dd715da0187e562c8247019557e4b390 Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Mon, 30 Jan 2012 17:58:30 -0800 Subject: [PATCH] Bug 718203: don't allow drops of javascript: URIs on the home button, r=enndeakin, sr=bz --HG-- extra : transplant_source : %ADP%C0%F8%8D%C4%A2v%BC%E5ZM%FC%D6BB%B7A%1E%07 --- browser/base/content/browser.js | 8 +- browser/base/content/test/Makefile.in | 3 +- browser/base/content/test/browser_homeDrop.js | 77 +++++++++++++++++++ .../test/browser_locationBarCommand.js | 5 +- content/base/public/nsIDroppedLinkHandler.idl | 19 +++-- content/base/src/contentAreaDropListener.js | 14 ++-- .../webBrowser/nsDocShellTreeOwner.cpp | 2 +- .../mochitest/tests/SimpleTest/ChromeUtils.js | 8 +- 8 files changed, 117 insertions(+), 19 deletions(-) create mode 100644 browser/base/content/test/browser_homeDrop.js diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 99fddd32702..411dd375d8c 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3136,13 +3136,17 @@ var browserDragAndDrop = { } }, - drop: function (aEvent, aName) Services.droppedLinkHandler.dropLink(aEvent, aName) + drop: function (aEvent, aName, aDisallowInherit) { + return Services.droppedLinkHandler.dropLink(aEvent, aName, aDisallowInherit); + } }; var homeButtonObserver = { onDrop: function (aEvent) { - setTimeout(openHomeDialog, 0, browserDragAndDrop.drop(aEvent, { })); + // disallow setting home pages that inherit the principal + let url = browserDragAndDrop.drop(aEvent, {}, true); + setTimeout(openHomeDialog, 0, url); }, onDragOver: function (aEvent) diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index e91dc2be696..ee7dea94f8d 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -182,6 +182,7 @@ _BROWSER_FILES = \ browser_bug719271.js \ browser_canonizeURL.js \ browser_findbarClose.js \ + browser_homeDrop.js \ browser_keywordBookmarklets.js \ browser_contextSearchTabPosition.js \ browser_ctrlTab.js \ @@ -263,7 +264,7 @@ _BROWSER_FILES = \ test_wyciwyg_copying.html \ authenticate.sjs \ browser_minimize.js \ - browser_aboutSyncProgress.js \ + browser_aboutSyncProgress.js \ browser_middleMouse_inherit.js \ redirect_bug623155.sjs \ $(NULL) diff --git a/browser/base/content/test/browser_homeDrop.js b/browser/base/content/test/browser_homeDrop.js new file mode 100644 index 00000000000..a6cb961ae21 --- /dev/null +++ b/browser/base/content/test/browser_homeDrop.js @@ -0,0 +1,77 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + // Open a new tab, since starting a drag from the home button activates it and + // we don't want to interfere with future tests by loading the home page. + let newTab = gBrowser.selectedTab = gBrowser.addTab(); + registerCleanupFunction(function () { + gBrowser.removeTab(newTab); + }); + + let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"]. + getService(Ci.mozIJSSubScriptLoader); + let chromeUtils = {}; + scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", chromeUtils); + + let homeButton = document.getElementById("home-button"); + ok(homeButton, "home button present"); + + let dialogListener = new WindowListener("chrome://global/content/commonDialog.xul", function (domwindow) { + ok(true, "dialog appeared in response to home button drop"); + domwindow.document.documentElement.cancelDialog(); + Services.wm.removeListener(dialogListener); + + // Now trigger the invalid URI test + executeSoon(function () { + let consoleListener = { + observe: function (m) { + if (m.message.indexOf("NS_ERROR_DOM_BAD_URI") > -1) { + Services.console.unregisterListener(consoleListener); + ok(true, "drop was blocked"); + executeSoon(finish); + } + } + } + Services.console.registerListener(consoleListener); + + // The drop handler throws an exception when dragging URIs that inherit + // principal, e.g. javascript: + expectUncaughtException(); + chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "javascript:8888"}]], "copy", window, EventUtils); + }) + }); + + Services.wm.addListener(dialogListener); + + chromeUtils.synthesizeDrop(homeButton, homeButton, [[{type: "text/plain", data: "http://mochi.test:8888/"}]], "copy", window, EventUtils); +} + +function WindowListener(aURL, aCallback) { + this.callback = aCallback; + this.url = aURL; +} +WindowListener.prototype = { + onOpenWindow: function(aXULWindow) { + var domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + var self = this; + domwindow.addEventListener("load", function() { + domwindow.removeEventListener("load", arguments.callee, false); + + ok(true, "domwindow.document.location.href: " + domwindow.document.location.href); + if (domwindow.document.location.href != self.url) + return; + + // Allow other window load listeners to execute before passing to callback + executeSoon(function() { + self.callback(domwindow); + }); + }, false); + }, + onCloseWindow: function(aXULWindow) {}, + onWindowTitleChange: function(aXULWindow, aNewTitle) {} +} + diff --git a/browser/base/content/test/browser_locationBarCommand.js b/browser/base/content/test/browser_locationBarCommand.js index 794d15d73d0..6426d067a7c 100644 --- a/browser/base/content/test/browser_locationBarCommand.js +++ b/browser/base/content/test/browser_locationBarCommand.js @@ -130,8 +130,11 @@ function triggerCommand(aClick, aEvent) { gURLBar.value = TEST_VALUE; gURLBar.focus(); - if (aClick) + if (aClick) { + is(gURLBar.getAttribute("pageproxystate"), "invalid", + "page proxy state must be invalid for go button to be visible"); EventUtils.synthesizeMouseAtCenter(gGoButton, aEvent); + } else EventUtils.synthesizeKey("VK_RETURN", aEvent); } diff --git a/content/base/public/nsIDroppedLinkHandler.idl b/content/base/public/nsIDroppedLinkHandler.idl index 3dd2f8769e4..747074e97ab 100644 --- a/content/base/public/nsIDroppedLinkHandler.idl +++ b/content/base/public/nsIDroppedLinkHandler.idl @@ -39,7 +39,7 @@ interface nsIDOMDragEvent; interface nsIURI; -[scriptable, uuid(F266B79B-7026-4D2D-B4BD-4F2C6B6C59B4)] +[scriptable, uuid(6B58A5A7-76D0-4E93-AB2E-4DE108683FF8)] interface nsIDroppedLinkHandler : nsISupports { /** @@ -56,15 +56,20 @@ interface nsIDroppedLinkHandler : nsISupports /** * Given a drop event aEvent, determines the link being dragged and returns * it. If a uri is returned the caller can, for instance, load it. If null - * is returned, there is no valid link to be dropped. A - * NS_ERROR_DOM_SECURITY_ERR error will be thrown and the event cancelled if + * is returned, there is no valid link to be dropped. + * + * A NS_ERROR_DOM_SECURITY_ERR error will be thrown and the event cancelled if * the receiving target should not load the uri for security reasons. This - * will occur if the source of the drag initiated a link for dragging that - * it itself cannot access. This prevents a source document from tricking - * the user into a dragging a chrome url for example. + * will occur if any of the following conditions are true: + * - the source of the drag initiated a link for dragging that + * it itself cannot access. This prevents a source document from tricking + * the user into a dragging a chrome url, for example. + * - aDisallowInherit is true, and the URI being dropped would inherit the + * current document's security context (URI_INHERITS_SECURITY_CONTEXT). * * aName is filled in with the link title if it exists, or an empty string * otherwise. */ - AString dropLink(in nsIDOMDragEvent aEvent, out AString aName); + AString dropLink(in nsIDOMDragEvent aEvent, out AString aName, + [optional] in boolean aDisallowInherit); }; diff --git a/content/base/src/contentAreaDropListener.js b/content/base/src/contentAreaDropListener.js index 504a9dc51e8..1ca96a885ca 100644 --- a/content/base/src/contentAreaDropListener.js +++ b/content/base/src/contentAreaDropListener.js @@ -50,7 +50,7 @@ ContentAreaDropListener.prototype = return [ ]; }, - _validateURI: function(dataTransfer, uriString) + _validateURI: function(dataTransfer, uriString, disallowInherit) { if (!uriString) return ""; @@ -76,11 +76,15 @@ ContentAreaDropListener.prototype = let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]. getService(Ci.nsIScriptSecurityManager); let sourceNode = dataTransfer.mozSourceNode; + let flags = secMan.STANDARD; + if (disallowInherit) + flags |= secMan.DISALLOW_INHERIT_PRINCIPAL; + // Use file:/// as the default uri so that drops of file URIs are always allowed if (sourceNode) - secMan.checkLoadURIStrWithPrincipal(sourceNode.nodePrincipal, uriString, secMan.STANDARD); + secMan.checkLoadURIStrWithPrincipal(sourceNode.nodePrincipal, uriString, flags); else - secMan.checkLoadURIStr("file:///", uriString, secMan.STANDARD); + secMan.checkLoadURIStr("file:///", uriString, flags); return uriString; }, @@ -120,7 +124,7 @@ ContentAreaDropListener.prototype = return true; }, - dropLink: function(aEvent, aName) + dropLink: function(aEvent, aName, aDisallowInherit) { aName.value = ""; @@ -128,7 +132,7 @@ ContentAreaDropListener.prototype = let [url, name] = this._getDropURL(dataTransfer); try { - url = this._validateURI(dataTransfer, url); + url = this._validateURI(dataTransfer, url, aDisallowInherit); } catch (ex) { aEvent.stopPropagation(); aEvent.preventDefault(); diff --git a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp index b715779b7d2..aff4b17045e 100644 --- a/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp +++ b/embedding/browser/webBrowser/nsDocShellTreeOwner.cpp @@ -950,7 +950,7 @@ nsDocShellTreeOwner::HandleEvent(nsIDOMEvent* aEvent) nsIWebNavigation* webnav = static_cast(mWebBrowser); nsAutoString link, name; - if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, name))) { + if (webnav && NS_SUCCEEDED(handler->DropLink(dragEvent, link, false, name))) { if (!link.IsEmpty()) { webnav->LoadURI(link.get(), 0, nsnull, nsnull, nsnull); } diff --git a/testing/mochitest/tests/SimpleTest/ChromeUtils.js b/testing/mochitest/tests/SimpleTest/ChromeUtils.js index 6f73d067c10..61539dc0145 100644 --- a/testing/mochitest/tests/SimpleTest/ChromeUtils.js +++ b/testing/mochitest/tests/SimpleTest/ChromeUtils.js @@ -246,8 +246,12 @@ function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, // need to use real mouse action aWindow.addEventListener("dragstart", trapDrag, true); synthesizeMouseAtCenter(srcElement, { type: "mousedown" }, aWindow); - synthesizeMouse(srcElement, 11, 11, { type: "mousemove" }, aWindow); - synthesizeMouse(srcElement, 20, 20, { type: "mousemove" }, aWindow); + + var rect = srcElement.getBoundingClientRect(); + var x = rect.width / 2; + var y = rect.height / 2; + synthesizeMouse(srcElement, x, y, { type: "mousemove" }, aWindow); + synthesizeMouse(srcElement, x+10, y+10, { type: "mousemove" }, aWindow); aWindow.removeEventListener("dragstart", trapDrag, true); event = aWindow.document.createEvent("DragEvents");