简体   繁体   中英

Fire Keydown event in Google Chrome extension

I'm doing a Google Chrome extension that interacts with Gmail chat and can send the same message to all open chat, the functional part is done, but I can not send the keydown event to the textareas.

What I am doing is using a page_action to show the extension icon when the user visit Gmail. When the user click the extension icon, it is going to prompt a popup with a textarea, when the user have opened chat and write something to the textarea and then press Enter key, the textarea of each opened chat are going to fill the same message and suppused to fire keydown event.

Here is the essential code:

popup.js

chrome.tabs.executeScript(null, {file: 'send.js'}, function () {
  // 'message' is the textarea inside the popup.html
  var message = document.getElementById('message');

  message.onkeydown = function (e) {
    if (13 == e.keyCode) {
      chrome.tabs.executeScript(null, {code: 'send("' + message.value + '");'}, function () {
        message.value = '';
      });
      return false;
    }
  };
});

send.js

function send(message) {
  if (message) {
    for (var i = 0, textareas = document.getElementsByTagName("TEXTAREA"), length = textareas.length; i < length; ++i) {
      textarea = textareas[i];
      textarea.value = message;

      var evt = document.createEvent('KeyboardEvent');

      evt.initKeyboardEvent('keydown', true, true, null, false, false, false, false, 13, 13);

      Object.defineProperty(evt, 'keyCode', {
        get : function() {
            return 13;
        }
      });

      Object.defineProperty(evt, 'which', {
        get : function() {
            return 13;
        }
      });

      Object.defineProperty(evt, 'keyIdentifier', {
        get : function() {
            return 'Enter';
        }
      });

      Object.defineProperty(evt, 'shiftKey', {
        get : function() {
            return false;
        }
      });

      textarea.dispatchEvent(evt);
    }
  }
}

The code did not have problem filling the textareas, so all textareas is reconized, but the keydown event did not fire after the script filled textareas. The strange part, is when I tried the send.js code into the Google Chrome console, the keydown event fire normally and the messages were send, but I can't do samething with the extension.

So, how can I fire the keydown event into the extension?

Gmail is composed of frames.
By default, chrome.tabs.executeScript only injects code in the main (top-window) frame. To also inject the code in the subframes, add allFrames: true to your details.

Also, do NOT use 'send("' + USER_INPUT_HERE + '");' to trigger your function. This makes your application vulnerable to script injections. Use JSON.stringify(USER_INPUT_HERE) to correctly escape the string.

chrome.tabs.executeScript(null, {
    file: 'send.js',
    allFrames: true
}, function () {
    chrome.tabs.executeScript(null, {
        code: 'send(' + JSON.stringify(message.value) + ');',
        allFrames: true
    });
    message.value = '';
});

Example of the vulnerability:
User input: " + (function(){while(1)chrome.tabs.create({url:"http://evil.com"})}()) + "


Objects created by the extension are never passed to a page. Properties and property descriptors added to an event are lost when passed to the page. Instead of a content script, I advise to use an injected script What is the difference between an injected script, Content script and extension code? to get the desired effect:

// Script to be injected
var code = '(' + function(message) {
    /* .. "function send"'s body from send.js .. */
} + ')(' + JSON.stringify(message.value) + ');';
// Content script which *injects* the script
chrome.tabs.executeScript(null, {
    code: 'var s = document.createElement("script");' +
          's.textContent = ' + JSON.stringify(code) + ';' + 
          '(document.head||document.documentElement).appendChild(s);' + 
          's.parentNode.removeChild(s);' /*<--Clean-up*/
});

For clarification, the previous snippet results in the following code to be injected in the page:

(function(message) { /* logic of send */ })("user input");

The Event object is constructed and passed within Gmail's page, so that all properties are preserved, as if you used the console to execute the script. It does not run in the context of your extension any more .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM