36

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?

Gezim
  • 7,112
  • 10
  • 62
  • 98
  • Is there some reason you can't just include the Facebook JS as one of your content scripts? – sdleihssirhc Oct 16 '11 at 01:57
  • I tried that but I'm not able to even load the script in the extension window. It comes up with this error: Could not load extension from '/Users/.../extentionfolder/'. Could not load javascript 'https://connect.facebook.net/en_US/all.js' for content script. – Gezim Oct 16 '11 at 02:13
  • That's because you're providing an external reference, but Chrome expects the script to be local. I'm not too familiar with the Facebook Graph API; how feasible is it to save a local copy with your extension? – sdleihssirhc Oct 16 '11 at 02:17
  • Check my answer for using aws-sdk in chrome extensions https://stackoverflow.com/questions/57893562/chrome-extension-which-uses-aws-services/58598444#58598444 – arthas Oct 29 '19 at 06:02

3 Answers3

57

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.

Sam Hanley
  • 4,707
  • 7
  • 35
  • 63
Adam Ayres
  • 8,732
  • 1
  • 32
  • 25
  • 2
    hi, i was under impression that you need to do this or something... http://developer.chrome.com/extensions/contentSecurityPolicy.html ....but would this work to. Now. 2013. – Muhammad Umer Sep 02 '13 at 19:13
  • 1
    This is no longer correct as per https://developer.chrome.com/extensions/contentSecurityPolicy#resourceLoading – Vlas Bashynskyi Dec 17 '16 at 17:17
  • this loads a script on the content page, but I am looking to load a script in the extension – Alexander Mills Jan 25 '18 at 00:33
12

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

Community
  • 1
  • 1
David Salamon
  • 2,361
  • 25
  • 30
3

If you want to load it as content script:

fetch('https://example.com/content.js')
  .then(resp => resp.text())
  .then(eval)
  .catch(console.error)

If you want to load it as background script. Take https://example.com/bg.js for example.

  1. add the remote js script to the background page file, which is named background.html here
<!DOCTYPE html>
<html>
<head>
  <script src="https://example.com/bg.js"></script>
</head>
<body>
<div>Empty content</div>
</body>
</html>
  1. add https://example.com to the content_security_policy of the manifest.json:
"background": {
  "page": "background.html"
},
"content_security_policy": "script-src 'self' https://example.com ; object-src 'self'",

Requirements:

  1. The remote js script must be served via https instead of http.
  2. You should specify a page rather than a scripts array in the background section
Iceberg
  • 2,744
  • 19
  • 19