Chrome extension: writing content into a dynamic iframe created in a sandboxed environment

google-chrome, google-chrome-extension, iframe, javascript, postmessage

Solution

Sorry, this is awkward. Apparently `postMessage` is the only way, and I can't manage to get it work previously because my iframe is not loaded yet. Also, accessing the dom document in the iframe is a big no under CSP, but it's possible to access `contentWindow` to do a `postMessage`.

This is what I did to solve this issue. Hope someone would benefit from this:

Create a `preview.html` in your extension root

Under `manifest.json`, add it as part of the `sandbox` attribute

Inside the `preview.html`, add the following code. Note that my snippet is a full html, so I used `document.write` instead.

<!DOCTYPE html>
<html>
    <head>
        <script>
        window.addEventListener("message", function(e) {
            if (e.data.content) {
                document.write(e.data.content);
            }
        });
        </script>
    </head>
    <body></body>
</html>

Create the iframe in your code as usual, point it to your `preview.html`, and attach it to the parent div or `Ext.Panel`.

Use the following code to `postMessage` after the element has been drawn/created/appended.

var content = '<!DOCTYPE html><html><body>Hello World!</body></html>';
var iframe = p.body.down('iframe').dom; //or the iframe node

iframe.onload = function() {
    iframe.contentWindow.postMessage({content: content}, '*');
};

Enjoy ;)

Edit

As pointed by Mike in Chromium forum, this issue can be solved by `srcdoc` as well. Simply set the iframe's srcdoc and problem is solved.

Just not sure of the status of `srcdoc`

Problem

I can't overcome this issue. Can someone give some advice? I have this application that uses ExtJS library that I will need to run in Chrome extension. I have successfully created my messaging bridge (`postMessage`), and sandboxed the whole application in it, and everything works as usual. ExtJS loaded, application is running. Then I have this piece of logic where I need to preview a piece of HTML snippets in my ExtJS viewport. I created an `iframe` in the `Panel` itself and on `afterrender` I tried to write the snippet in it. This is the code I use: ``` html: '<iframe src="about:blank" style="width:100%;height:100%;border:none;"></iframe>'; ...... //p is the panel found in afterrender p.body.down('iframe').dom.contentDocument.write(content); ``` Then the error: Unsafe JavaScript attempt to access frame with URL about:blank from frame with URL chrome-extension://fcnpmlgapilgclcelfanblpbglmkghbc/core/themes/default/app.html. Domains, protocols and ports must match. I have tried with `postMessage` within sandbox to this dynamic iframe but nothing happens. Setting the `sandbox` attribute in manifest doesn't work either. This is the only way and it works. See my answer below. Question: - How should one set the manifest to support this kind of use case? - Or is there any better way to preview HTML snippet without using an `iframe`? Afaik previewing with `iframe` is the best as it sandboxed the snippet without being messed with parent css. Note This piece of code was working fine in manifest v1 but I planned to migrate it to manifest v2. I didn't realize Content Security Policy (CSP) has became that strict. A screen to describe the problem ;)

Original source