google-chrome third - Loading external javascript in google chrome extension




file security (3)

I'm writing a Google Chrome extension which manipulates the current page (basically adds a button).

In my content script, I want to load the Facebook Graph API:

$fbDiv = $(document.createElement('div')).attr('id', 'fb-root');
$fbScript = $(document.createElement('script')).attr('src', 'https://connect.facebook.net/en_US/all.js');
$(body).append($fbDiv);
$(body).append($fbScript);

console.log("fbScript: " + typeof $fbScript.get(0));
console.log("fbScript parent: " + typeof $fbScript.parent().get(0));
console.log("find through body: " + typeof $(body).find($fbScript.get(0)).get(0));

However, the script doesn't seem to added to body. Here's the console log:

fbScript: object
fbScript parent: undefined
find through body: undefined

Any ideas on what I'm doing wrong?


Answers

Google Chrome extensions no longer allow injecting external code directly, however you can still download the code with an Ajax call and feed it to the injector as if it was a code block.

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    $.get("http://127.0.0.1:8000/static/plugin/somesite.js", function(result) {
        chrome.tabs.executeScript(tabs[0].id, {code: result});
    }, "text");
});

source: https://stackoverflow.com/a/36645710/720665


The issue is that the JavaScript inside the content scripts runs in its own sandboxed environment and only has access to other JavaScript that was loaded in one of two ways:

Via the manifest:

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "js": ["https://connect.facebook.net/en_US/all.js"]
    }
  ],
  ...
}

Or using Programmatic injection:

/* in background.html */
chrome.browserAction.onClicked.addListener(function(tab) {
    chrome.tabs.executeScript(null,
                       {file:"https://connect.facebook.net/en_US/all.js"});
});

Be sure to update your manifest permissions:

/* in manifest.json */
"permissions": [
    "tabs", "https://connect.facebook.net"
 ], 

Appending a script tag will in effect evaluate the JavaScript in the context of the containing page, outside of the JavaScript sandbox that your JavaScript has access to.

Also, since the FB script requires the "fb-root" to be in the DOM, you will probably need to use the programmatic approach so that you can first update the DOM with the element, then pass a message back to the background page to load the Facebook script so it is accessible to the JavaScript that is loaded in the content scripts.


I came to this question because I was looking for a simple way to maintain a collection of useful JavaScript plugins. After seeing some of the solutions here, I came up with this:

  1. Set up a file called "plugins.js" (or extensions.js or what have you). Keep your plugin files together with that one master file.

  2. plugins.js will have an array called "pluginNames[]" that we will iterate over each(), then append a tag to the head for each plugin

    //set array to be updated when we add or remove plugin files var pluginNames = ["lettering", "fittext", "butterjam", etc.]; //one script tag for each plugin $.each(pluginNames, function(){ $('head').append(''); });

  3. manually call just the one file in your head:
    <script src="js/plugins/plugins.js"></script>

I found that even though all of the plugins were getting dropped into the head tag the way they ought to, they weren't always being run by the browser when you click into the page or refresh.

I found it's more reliable to just write the script tags in a PHP include. You only have to write it once and that's just as much work as calling the plugin using JavaScript.





javascript google-chrome facebook-graph-api google-chrome-extension