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 ;)