Bug 816406 - Disallow dragging a private tab into a non-private window and vice versa; r=dao
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 02 Dec 2012 15:57:06 -0500
changeset 115150 d1fba48c7253db66bdca75e049a239f49d168303
parent 115149 5acd87d0cf3398132377949d4b701f2c4d4d9316
child 115151 c7d448fde422b0034e7625ce59926bb25afc7145
push id23973
push useremorley@mozilla.com
push dateThu, 06 Dec 2012 10:04:18 +0000
treeherdermozilla-central@ddda5400c826 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdao
bugs816406
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 816406 - Disallow dragging a private tab into a non-private window and vice versa; r=dao
browser/base/content/tabbrowser.xml
browser/base/content/test/Makefile.in
browser/base/content/test/browser_tab_drag_drop_perwindow.js
testing/mochitest/tests/SimpleTest/ChromeUtils.js
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1891,16 +1891,24 @@
         </body>
       </method>
 
       <method name="swapBrowsersAndCloseOther">
         <parameter name="aOurTab"/>
         <parameter name="aOtherTab"/>
         <body>
           <![CDATA[
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+            // Do not allow transfering a private tab to a non-private window
+            // and vice versa.
+            if (PrivateBrowsingUtils.isWindowPrivate(window) !=
+                PrivateBrowsingUtils.isWindowPrivate(aOtherTab.ownerDocument.defaultView))
+              return;
+#endif
+
             // That's gBrowser for the other window, not the tab's browser!
             var remoteBrowser = aOtherTab.ownerDocument.defaultView.gBrowser;
 
             // First, start teardown of the other browser.  Make sure to not
             // fire the beforeunload event in the process.  Close the other
             // window if this was its last tab.
             if (!remoteBrowser._beginRemoveTab(aOtherTab, true, true))
               return;
@@ -3417,16 +3425,24 @@
           // tabs are always added as the first type
           if (types[0] == TAB_DROP_TYPE) {
             var sourceNode = dt.mozGetDataAt(TAB_DROP_TYPE, 0);
             if (sourceNode instanceof XULElement &&
                 sourceNode.localName == "tab" &&
                 sourceNode.ownerDocument.defaultView instanceof ChromeWindow &&
                 sourceNode.ownerDocument.documentElement.getAttribute("windowtype") == "navigator:browser" &&
                 sourceNode.ownerDocument.defaultView.gBrowser.tabContainer == sourceNode.parentNode) {
+#ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
+              // Do not allow transfering a private tab to a non-private window
+              // and vice versa.
+              if (PrivateBrowsingUtils.isWindowPrivate(window) !=
+                  PrivateBrowsingUtils.isWindowPrivate(sourceNode.ownerDocument.defaultView))
+                return dt.effectAllowed = "none";
+#endif
+
 #ifdef XP_MACOSX
               return dt.effectAllowed = event.altKey ? "copy" : "move";
 #else
               return dt.effectAllowed = event.ctrlKey ? "copy" : "move";
 #endif
             }
           }
 
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -315,16 +315,17 @@ ifdef MOZ_PER_WINDOW_PRIVATE_BROWSING
 _BROWSER_FILES += \
                 browser_bug763468_perwindowpb.js \
                 browser_bug767836_perwindowpb.js \
                 browser_bug816527.js \
                 browser_private_browsing_window.js \
                 browser_save_link-perwindowpb.js \
                 browser_save_private_link_perwindowpb.js \
                 browser_tabMatchesInAwesomebar_perwindowpb.js \
+                browser_tab_drag_drop_perwindow.js \
                 $(NULL)
 else
 _BROWSER_FILES += \
                 browser_bug763468.js \
                 browser_bug767836.js \
                 browser_save_link.js \
                 browser_save_private_link.js \
                 browser_tabMatchesInAwesomebar.js \
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_tab_drag_drop_perwindow.js
@@ -0,0 +1,50 @@
+/* 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/. */
+
+function test() {
+  //initialization
+  waitForExplicitFinish();
+
+  let scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
+                     getService(Ci.mozIJSSubScriptLoader);
+  let chromeUtils = {};
+  scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", chromeUtils);
+
+  function testOnWindow(aIsPrivate, aCallback) {
+    whenNewWindowLoaded({private: aIsPrivate}, function(win) {
+      executeSoon(function() aCallback(win));
+    });
+  }
+
+  testOnWindow(false, function(aNormalWindow) {
+    testOnWindow(true, function(aPrivateWindow) {
+      // Open a tab in each window
+      let normalTab = aNormalWindow.gBrowser.addTab("about:blank", {skipAnimation: true});
+      let privateTab = aPrivateWindow.gBrowser.addTab("about:blank", {skipAnimation: true});
+
+      let effect = chromeUtils.synthesizeDrop(normalTab, privateTab,
+        [[{type: TAB_DROP_TYPE, data: normalTab}]],
+        null, aNormalWindow, EventUtils, aPrivateWindow);
+      is(effect, "none", "Should not be able to drag a normal tab to a private window");
+
+      effect = chromeUtils.synthesizeDrop(privateTab, normalTab,
+        [[{type: TAB_DROP_TYPE, data: privateTab}]],
+        null, aPrivateWindow, EventUtils, aNormalWindow);
+      is(effect, "none", "Should not be able to drag a private tab to a normal window");
+
+      aNormalWindow.gBrowser.swapBrowsersAndCloseOther(normalTab, privateTab);
+      is(aNormalWindow.gBrowser.tabs.length, 2, "Prevent moving a normal tab to a private tabbrowser");
+      is(aPrivateWindow.gBrowser.tabs.length, 2, "Prevent accepting a normal tab in a private tabbrowser");
+
+      aPrivateWindow.gBrowser.swapBrowsersAndCloseOther(privateTab, normalTab);
+      is(aPrivateWindow.gBrowser.tabs.length, 2, "Prevent moving a private tab to a normal tabbrowser");
+      is(aNormalWindow.gBrowser.tabs.length, 2, "Prevent accepting a private tab in a normal tabbrowser");
+
+      aNormalWindow.close();
+      aPrivateWindow.close();
+      finish();
+    });
+  });
+}
+
--- a/testing/mochitest/tests/SimpleTest/ChromeUtils.js
+++ b/testing/mochitest/tests/SimpleTest/ChromeUtils.js
@@ -205,23 +205,27 @@ function synthesizeDragStart(element, ex
  *  dragData - the data to supply for the data transfer
  *                     This data is in the format:
  *                       [ [ {type: value, data: value}, ...], ... ]
  *  dropEffect - the drop effect to set during the dragstart event, or 'move' if null
  *  aWindow - optional; defaults to the current window object.
  *  eventUtils - optional; allows you to pass in a reference to EventUtils.js. 
  *               If the eventUtils parameter is not passed in, we assume EventUtils.js is 
  *               in the scope. Used by browser-chrome tests.
+ *  aDestWindow - optional; defaults to aWindow.
+ *                Used when destElement is in a different window than srcElement.
  *
  * Returns the drop effect that was desired.
  */
-function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, eventUtils)
+function synthesizeDrop(srcElement, destElement, dragData, dropEffect, aWindow, eventUtils, aDestWindow)
 {
   if (!aWindow)
     aWindow = window;
+  if (!aDestWindow)
+    aDestWindow = aWindow;
 
   var synthesizeMouseAtCenter = (eventUtils || window).synthesizeMouseAtCenter;
   var synthesizeMouse = (eventUtils || window).synthesizeMouse;
 
   var gWindowUtils  = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor).
                              getInterface(Components.interfaces.nsIDOMWindowUtils);
   var ds = Components.classes["@mozilla.org/widget/dragservice;1"].
            getService(Components.interfaces.nsIDragService);
@@ -249,34 +253,34 @@ function synthesizeDrop(srcElement, dest
 
     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");
-    event.initDragEvent("dragenter", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
+    event = aDestWindow.document.createEvent("DragEvents");
+    event.initDragEvent("dragenter", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
     gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
 
-    var event = aWindow.document.createEvent("DragEvents");
-    event.initDragEvent("dragover", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
+    var event = aDestWindow.document.createEvent("DragEvents");
+    event.initDragEvent("dragover", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
     if (gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true)) {
-      synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow);
+      synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow);
       return "none";
     }
 
     if (dataTransfer.dropEffect != "none") {
-      event = aWindow.document.createEvent("DragEvents");
-      event.initDragEvent("drop", true, true, aWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
+      event = aDestWindow.document.createEvent("DragEvents");
+      event.initDragEvent("drop", true, true, aDestWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer);
       gWindowUtils.dispatchDOMEventViaPresShell(destElement, event, true);
     }
 
-    synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aWindow);
+    synthesizeMouseAtCenter(destElement, { type: "mouseup" }, aDestWindow);
 
     return dataTransfer.dropEffect;
   } finally {
     ds.endDragSession(true);
   }
 };
 
 var PluginUtils =