0

Main Question

I'm building a Chrome extension that involves appending an iframe to the page. The extension makes an AJAX call in the background page to retrieve the URLs of the external CSS / JS to include and so I need to dynamically add these resources to the iframe. The iframe code is an HTML page that's included in the extension's web_accessible_resources (it has a URL of chrome-extension://...)

This is what I do in the iframe:

window.onload = function() {
  chrome.runtime.sendMessage({action: "getResources"}, function(response) {
    // get urls of css / js files
    let { css, js } = response; // css and js are arrays of urls retrieved

    let head = document.getElementsByTagName('head')[0];
    for (let i = 0; i < css.length; i++) {
      let link = document.createElement('link');
      link.href = css[i];
      link.type = "text/css";
      link.rel = "stylesheet";

      head.appendChild(link);
    }

    for (let i = 0; i < js.length; i++) {
      let script = document.createElement('script');
      script.src = js[i];
      script.type = "text/javascript";
      script.onload = function() {
        window.alert('loaded script');
      }
      head.appendChild(script);
    }
  }
}

After this, I can log the stylesheets and scripts from the head so they are appended successfully. However, the callback in the script.onload is not called and I tried using getComputedStyle like in this answer to check the CSS and that didn't work. So both the stylesheets and scripts are not actually being executed.

I'm wondering if Chrome extensions just don't allow dynamic injections into iframes.


Additional Info

Here are some things I tried:

  • Adding the URLs to the permissions

    Mentioned here. All the scripts I load are from sites outlined in the permissions field of the manifest.json file so CORS shouldn't be a problem.
  • Trying hacky ways to load the script

    I tried script.innerHTML = "console.log('success')" and also tried head.innerHTML = '<scr' + 'ipt type="text/javascript" src="[URL_TO_LOAD]"></scr' + 'ipt>'. Neither worked. I didn't try any solutions with document.write or eval just because I would never use those even if they worked for security reasons.
  • SetTimeout

    I tried setting a timeout after loading the script in case it took a while to execute but even after 10 seconds, global variables that should've been there are still undefined.
  • HTTPS

    Requesting scripts served over HTTPS also did not work.

Any help would be appreciated.

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
cheng
  • 1,264
  • 2
  • 18
  • 41
  • Please [edit] the question to be on-topic: include a [mcve] that duplicates the problem. For Chrome extensions or Firefox WebExtensions this almost always means including your *manifest.json* and some of the background, content, and/or popup scripts/HTML. Questions seeking debugging help ("why isn't this code working the way I want?") must include: (1) the desired behavior, (2) a specific problem or error and (3) the shortest code necessary to reproduce it *in the question itself*. Please also see: [What topics can I ask about here?](http://stackoverflow.com/help/on-topic), and [ask]. – Makyen Aug 09 '17 at 23:04

1 Answers1

2

Turns out it's due to Chrome's Content Security Policy. I found the answer here. However the scripts that can be dynamically injected into the iframe must be either local files or served over HTTPS.

cheng
  • 1,264
  • 2
  • 18
  • 41