hterm: restore native pasting as a fallback

In some environments (notably, "normal" websites), we don't have direct
access to read the clipboard (security!).  In those cases, our attempt
to directly paste ultimately fails breaking ctrl+v shortcuts.

Instead, let's plumb the return value of the paste command back up to
the callers so they can decide what mitigations to deploy.  For mouse
pasting, there's nothing we can do but whine.  For the keyboard, we can
fallback to letting the OS do its thing (and just hope for the best).

BUG=chromium:737299

Change-Id: I00847cc6f13132b8486a7e6b850ec790afa8d2e5
Reviewed-on: https://chromium-review.googlesource.com/578849
Reviewed-by: Brandon Gilmore <varz@google.com>
Tested-by: Mike Frysinger <vapier@chromium.org>
diff --git a/hterm/js/hterm.js b/hterm/js/hterm.js
index 58bcd66..db83cac 100644
--- a/hterm/js/hterm.js
+++ b/hterm/js/hterm.js
@@ -151,14 +151,20 @@
 /**
  * Paste the system clipboard into the element with focus.
  *
+ * Note: In Chrome/Firefox app/extension environments, you'll need the
+ * "clipboardRead" permission.  In other environments, this might always
+ * fail as the browser frequently blocks access for security reasons.
+ *
  * @param {HTMLDocument} The document to paste into.
+ * @return {boolean} True if the paste succeeded.
  */
 hterm.pasteFromClipboard = function(document) {
   try {
-    document.execCommand('paste');
+    return document.execCommand('paste');
   } catch (firefoxException) {
-    // Ignore this. FF throws an exception if there was an error, even though
-    // the spec says just return false.
+    // Ignore this.  FF 40 and older would incorrectly throw an exception if
+    // there was an error instead of returning false.
+    return false;
   }
 };
 
diff --git a/hterm/js/hterm_keyboard_keymap.js b/hterm/js/hterm_keyboard_keymap.js
index f17cb2c..8cc3c58 100644
--- a/hterm/js/hterm_keyboard_keymap.js
+++ b/hterm/js/hterm_keyboard_keymap.js
@@ -571,14 +571,18 @@
  * a ^V if the user presses Ctrl-V. This can be flipped with the
  * 'ctrl-v-paste' preference.
  *
- * We have to do the pasting ourselves as not all browsers/OSs bind Ctrl-V to
- * pasting.  Notably, on macOS, Ctrl-V/Ctrl-Shift-V do nothing.
  */
 hterm.Keyboard.KeyMap.prototype.onCtrlV_ = function(e, keyDef) {
   if ((!e.shiftKey && this.keyboard.ctrlVPaste) ||
       (e.shiftKey && !this.keyboard.ctrlVPaste)) {
-    this.keyboard.terminal.paste();
-    return hterm.Keyboard.KeyActions.CANCEL;
+    // We try to do the pasting ourselves as not all browsers/OSs bind Ctrl-V to
+    // pasting.  Notably, on macOS, Ctrl-V/Ctrl-Shift-V do nothing.
+    // However, this might run into web restrictions, so if it fails, we still
+    // fallback to the letting the native behavior (hopefully) save us.
+    if (this.keyboard.terminal.paste())
+      return hterm.Keyboard.KeyActions.CANCEL;
+    else
+      return hterm.Keyboard.KeyActions.PASS;
   }
 
   return '\x16';
diff --git a/hterm/js/hterm_terminal.js b/hterm/js/hterm_terminal.js
index 0d58231..31f56ef 100644
--- a/hterm/js/hterm_terminal.js
+++ b/hterm/js/hterm_terminal.js
@@ -2796,7 +2796,7 @@
  * Paste from the system clipboard to the terminal.
  */
 hterm.Terminal.prototype.paste = function() {
-  hterm.pasteFromClipboard(this.document_);
+  return hterm.pasteFromClipboard(this.document_);
 };
 
 /**
@@ -3062,7 +3062,8 @@
     if (e.type == 'mousedown') {
       if ((this.mouseRightClickPaste && e.button == 2 /* right button */) ||
           e.button == this.mousePasteButton) {
-        this.paste();
+        if (!this.paste())
+          console.warning('Could not paste manually due to web restrictions');;
       }
     }