Firefox WebExtension, Isolated HTML Overlay

I am looking for a way to display an isolated overlay on some websites using WebExtensions.
The IFrame will look like a way to do this, as it provides a whole separate area for css, js and DOM. And another neat thing is that the target site will not be able to read or modify content.

In the Chrome extensions, which seem to be possible without any problems, but using WebExtensions in Firefox, although they have the same syntax, I get security warnings / errors and this does not work.

I tried two different things:

  • Create an iframe without the src attribute and enter it into the body of the website. This method failed because I get CSP errors / warnings when I do iframe.contentWindow.document.open() .
    Relevant content - script code:

     let html = ` <!DOCTYPE html> <html> <head></head> <body> <h1>TEST</h1> </body> </html> ` let iframe = document.createElement('iframe') document.body.appendChild(iframe) iframe.contentWindow.document.open() iframe.contentWindow.document.write(html) iframe.contentWindow.document.close() 
  • The other thing I tried (which would make overlay.html even worse, since the website did not allow access to content) was to put my iframe code in a file ( overlay.html ) in my WebExtension and make an iframe load it by setting src on browser.extension.getURL('overlay.html') .
    Relevant content - script code:

     let iframe = document.createElement('iframe') iframe.src = browser.extension.getURL('overlay.html') document.body.appendChild(iframe) 

    In the manifest, I defined overlay.html as web_accessible_resources for this:

     "web_accessible_resources": [ "overlay.html" ], 

    The fact is that iframe just does not load the overlay.html file. But it is definitely accessible, otherwise location.href = browser.extension.getURL('overlay.html') will not work. It would be very convenient if this worked, since I could store the entire overlay (html, css, js) as separate files in my extension. As if it would be a separate website. And with a content-script I could access it to add new data or something else.

Edit:

I am currently using the srcdoc attribute of my iframe to set the source code that should contain (thanks to wOxxOm for this). So at least I have something that works now. But what I really dislike about this approach is that I cannot interact with the iframe content from my script content. Interestingly, however, I can interact with the parent page from iframe js code, but again not with the contents of the script. It is also very dirty, inconvenient and difficult to maintain in order to put all your html, css, js code in one line instead of several files, such as a regular website.

+7
javascript google-chrome-extension iframe content-security-policy firefox-webextensions
source share
2 answers

Problem

First, we know that the problem is a security problem, what exactly is the problem? Well, when you try to load an extension resource in an iframe by installing iframe src, the browser complains about security and does not allow the iframe to connect to another protocol, in this case "moz-extension: //".

Decision

Download html etc. from the extension context and enter as a string.

Nitty gritty

To get around this, we can set the src iframe attribute to data:text/html;charset=utf8,${markup} .

This directly tells iframe that the content is html, it uses utf8 encoding, followed by raw markup. We completely circumvent the need for an iframe to load any resources over the network.

The execution context of the contents of the Firefox script is separate from the page to which it was loaded. This means that you can make an xhr request without breaking the CSP.

If you make an xhr request for your markup, you can get the contents of the response as a string and directly insert it into the iframe src attribute.

So the contents of the script:

  function loaded (evt) { if (this.readyState === 4 && this.status === 200) { var html = this.responseText; console.log(html); var iframe = document.createElement('iframe'); iframe.src = 'data:text/html;charset=utf-8,' + html; document.body.appendChild(iframe); console.log('iframe.contentWindow =', iframe.contentWindow); } else { console.log('problem loading'); } } var xhr = new XMLHttpRequest(); xhr.overrideMimeType("text/html"); xhr.open("GET", browser.extension.getURL('test.html'), false); xhr.addEventListener("readystatechange", loaded); xhr.send(null); 

Using a simple HTML file

 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Test</title> <meta charset="utf8" /> </head> <body> <h1>Hello World</h1> </body> </html> 

So now you have successfully entered the html template in the target iframe.

If you need images, scripts, css files, etc., you will need to write a loader based on the method described above, introducing new script tags, etc. directly into the iframe document.

+3
source share

By the way, sometimes people use the IFRAME URL in different protocols, i.e.
https:// (for now the current page is http:// ).

So the IFRAME URL must be relative, for example src="//example.com"

0
source share

All Articles