Bug 1162952 - Return true from document.queryCommandEnabled('cut'/'copy') when in privileged or user-initiated code. r=ehsan
authorMichael Layzell <michael@thelayzells.com>
Mon, 25 May 2015 10:09:00 +0200
changeset 245650 0431f570160df1497943b8d7039b5f70c4b45e74
parent 245649 f4dcd8361800b3d83c4448de0684fbc5c07ea93e
child 245651 1921222e708e8b070b8ef5db215d5bec2217d375
push id13177
push userkwierso@gmail.com
push dateTue, 26 May 2015 23:26:28 +0000
treeherderfx-team@b991cd5a0ad1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1162952
milestone41.0a1
Bug 1162952 - Return true from document.queryCommandEnabled('cut'/'copy') when in privileged or user-initiated code. r=ehsan
dom/base/nsContentUtils.cpp
dom/base/nsContentUtils.h
dom/html/nsHTMLDocument.cpp
editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
editor/libeditor/tests/mochitest.ini
editor/libeditor/tests/test_bug1162952.html
editor/libeditor/tests/test_bug408231.html
editor/libeditor/tests/test_bug676401.html
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -6625,16 +6625,24 @@ nsContentUtils::IsRequestFullScreenAllow
 {
   return !sTrustedFullScreenOnly ||
          EventStateManager::IsHandlingUserInput() ||
          IsCallerChrome();
 }
 
 /* static */
 bool
+nsContentUtils::IsCutCopyAllowed()
+{
+  return EventStateManager::IsHandlingUserInput() ||
+         IsCallerChrome();
+}
+
+/* static */
+bool
 nsContentUtils::HaveEqualPrincipals(nsIDocument* aDoc1, nsIDocument* aDoc2)
 {
   if (!aDoc1 || !aDoc2) {
     return false;
   }
   bool principalsEqual = false;
   aDoc1->NodePrincipal()->Equals(aDoc2->NodePrincipal(), &principalsEqual);
   return principalsEqual;
--- a/dom/base/nsContentUtils.h
+++ b/dom/base/nsContentUtils.h
@@ -1858,16 +1858,23 @@ public:
   /**
    * Returns true if requests for full-screen are allowed in the current
    * context. Requests are only allowed if the user initiated them (like with
    * a mouse-click or key press), unless this check has been disabled by
    * setting the pref "full-screen-api.allow-trusted-requests-only" to false.
    */
   static bool IsRequestFullScreenAllowed();
 
+  /**
+   * Returns true if calling execCommand with 'cut' or 'copy' arguments is
+   * allowed in the current context. These are only allowed if the user initiated
+   * them (like with a mouse-click or key press).
+   */
+  static bool IsCutCopyAllowed();
+
   /*
    * Returns true if the performance timing APIs are enabled.
    */
   static bool IsPerformanceTimingEnabled()
   {
     return sIsPerformanceTimingEnabled;
   }
   
--- a/dom/html/nsHTMLDocument.cpp
+++ b/dom/html/nsHTMLDocument.cpp
@@ -3348,16 +3348,29 @@ nsHTMLDocument::QueryCommandEnabled(cons
 bool
 nsHTMLDocument::QueryCommandEnabled(const nsAString& commandID, ErrorResult& rv)
 {
   nsAutoCString cmdToDispatch;
   if (!ConvertToMidasInternalCommand(commandID, cmdToDispatch)) {
     return false;
   }
 
+  // cut & copy are always allowed
+  bool isCutCopy = commandID.LowerCaseEqualsLiteral("cut") ||
+                   commandID.LowerCaseEqualsLiteral("copy");
+  if (isCutCopy) {
+    return nsContentUtils::IsCutCopyAllowed();
+  }
+
+  // Report false for restricted commands
+  bool restricted = commandID.LowerCaseEqualsLiteral("paste");
+  if (restricted && !nsContentUtils::IsCallerChrome()) {
+    return false;
+  }
+
   // if editing is not on, bail
   if (!IsEditingOnAfterFlush()) {
     rv.Throw(NS_ERROR_FAILURE);
     return false;
   }
 
   // get command manager and dispatch command to our window if it's acceptable
   nsCOMPtr<nsICommandManager> cmdMgr;
--- a/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
+++ b/editor/libeditor/tests/browserscope/lib/richtext2/currentStatus.js
@@ -302,16 +302,25 @@ const knownFailures = {
     "QE-Proposed-INSERTLINEBREAK_TEXT-1-body": true,
     "QE-Proposed-INSERTLINEBREAK_TEXT-1-div": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-dM": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-body": true,
     "QE-Proposed-CREATEBOOKMARK_TEXT-1-div": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-dM": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-body": true,
     "QE-Proposed-UNBOOKMARK_TEXT-1-div": true,
+    "QE-Proposed-COPY_TEXT-1-dM": true,
+    "QE-Proposed-COPY_TEXT-1-body": true,
+    "QE-Proposed-COPY_TEXT-1-div": true,
+    "QE-Proposed-CUT_TEXT-1-dM": true,
+    "QE-Proposed-CUT_TEXT-1-body": true,
+    "QE-Proposed-CUT_TEXT-1-div": true,
+    "QE-Proposed-PASTE_TEXT-1-dM": true,
+    "QE-Proposed-PASTE_TEXT-1-body": true,
+    "QE-Proposed-PASTE_TEXT-1-div": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-dM": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-body": true,
     "QS-Proposed-SUB_SPAN.sub-1-SI-div": true,
     "QS-Proposed-SUB_MYSUB-1-SI-dM": true,
     "QS-Proposed-SUB_MYSUB-1-SI-body": true,
     "QS-Proposed-SUB_MYSUB-1-SI-div": true,
     "QS-Proposed-SUP_SPAN.sup-1-SI-dM": true,
     "QS-Proposed-SUP_SPAN.sup-1-SI-body": true,
--- a/editor/libeditor/tests/mochitest.ini
+++ b/editor/libeditor/tests/mochitest.ini
@@ -157,9 +157,10 @@ skip-if = toolkit == 'android' # bug 105
 [test_dom_input_event_on_texteditor.html]
 [test_keypress_untrusted_event.html]
 [test_root_element_replacement.html]
 [test_select_all_without_body.html]
 skip-if = e10s
 [test_spellcheck_pref.html]
 skip-if = toolkit == 'android'
 [test_bug1068979.html]
-[test_bug1109465.html]
\ No newline at end of file
+[test_bug1109465.html]
+[test_bug1162952.html]
new file mode 100644
--- /dev/null
+++ b/editor/libeditor/tests/test_bug1162952.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1162952
+-->
+<head>
+  <title>Test for Bug 1162952</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1162952">Mozilla Bug 1162952</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 1162952 **/
+var userCallbackRun = false;
+
+document.addEventListener('keydown', function() {
+    // During a user callback, the commands should be enabled
+    userCallbackRun = true;
+    is(true, document.queryCommandEnabled('cut'));
+    is(true, document.queryCommandEnabled('copy'));
+});
+
+// Otherwise, they should be disabled
+is(false, document.queryCommandEnabled('cut'));
+is(false, document.queryCommandEnabled('copy'));
+
+// Fire a user callback
+synthesizeKey('A', {});
+
+ok(userCallbackRun, "User callback should've been run");
+
+</script>
+</pre>
+</body>
+</html>
--- a/editor/libeditor/tests/test_bug408231.html
+++ b/editor/libeditor/tests/test_bug408231.html
@@ -40,17 +40,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       ["insertunorderedlist", "true"],
       ["insertparagraph", "true"],
       ["italic", "true"],
       ["justifycenter", "true"],
       ["justifyfull", "true"],
       ["justifyleft", "true"],
       ["justifyright", "true"],
       ["outdent", "true"],
-      //["paste", "true"],
+      ["paste", "false"],
       ["redo", "false"],
       ["removeformat", "true"],
       ["selectall", "true"],
       ["strikethrough", "true"],
       ["styleWithCSS", "true"],
       ["subscript", "true"],
       ["superscript", "true"],
       ["underline", "true"],
--- a/editor/libeditor/tests/test_bug676401.html
+++ b/editor/libeditor/tests/test_bug676401.html
@@ -30,16 +30,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 SimpleTest.waitForExplicitFinish();
 SimpleTest.waitForFocus(runTests);
 
 var gBlock1, gBlock2;
 
 var alwaysEnabledCommands = [
   "contentReadOnly",
   "copy",
+  "cut",
   "enableInlineTableEditing",
   "enableObjectResizing",
   "insertBrOnReturn",
   "selectAll",
   "styleWithCSS",
 ];
 
 function IsCommandEnabled(command) {
@@ -84,19 +85,22 @@ function runTests() {
     IsCommandEnabled(commands[i]);
 
   // Mozilla-specific stuff
   commands = ["enableInlineTableEditing", "enableObjectResizing", "insertBrOnReturn"];
   for (i = 0; i < commands.length; i++)
     IsCommandEnabled(commands[i]);
 
   // These are privileged, and available only to chrome.
-  commands = ["cut", "paste", "copy"];
+  commands = ["paste"];
   for (i = 0; i < commands.length; i++) {
-    IsCommandEnabled(commands[i]);
+    is(document.queryCommandEnabled(commands[i]), false,
+       "Command should not be enabled for non-privileged code");
+    is(SpecialPowers.wrap(document).queryCommandEnabled(commands[i]), true,
+       "Command should be enabled for privileged code");
     try {
       document.execCommand(commands[i], false, false);
       ok(false, "Thould have thrown: " + commands[i]);
     } catch (e) {
       ok(/insecure|denied/.test(e), "Threw correctly: " + commands[i] + " - " + e);
     }
     SpecialPowers.wrap(document).execCommand(commands[i], false, false);
   }