I have a firefox web extension that uses a content script to inject HTML into a webpage when a button is clicked. The HTML that is injected consists of an iFrame nested within several divs.
Here's the relevant portion of the content script:
var iFrame = document.createElement("iFrame");
iFrame.id = "contentFrame";
iFrame.style.cssText = "width: 100%; height: 100%; border: none;";
iFrame.src = browser.extension.getURL("inject-content/inject.html");
var boxDiv = document.createElement("div");
boxDiv.style.cssText = "left: calc(100% - 390px); position: fixed; top: 0px; width: 390px; z-index: 1;"
var zeroDiv = document.createElement("div");
zeroDiv.style.cssText = "position: fixed; width: 0px; height: 0px; top: 0px; left: 0px; z-index: 2147483647;";
var outerDiv = document.createElement("div");
outerDiv.id = outerDivID;
boxDiv.appendChild(iFrame);
zeroDiv.appendChild(boxDiv);
outerDiv.appendChild(zeroDiv);
document.body.appendChild(outerDiv);
As indicated by the code, the source of the iFrame is a file called "inject.html". Two important features of inject.html are:
1) A script tag (inside the header) that refers to the file for a javascript library in the same directory.
<script src="perfect-scrollbar.js"></script>
2) A piece of inline javascript that uses "perfect-scrollbar.js". Also, for reference, here is the library itself: https://github.com/utatti/perfect-scrollbar
<script>
console.log("Hello World");
var perfectScrollbar = new PerfectScrollbar("#container");
</script>
When I directly open the file from my computer (i.e - right-click, open with Chrome), it works fine. However, when I use my extension in Firefox, I get the following error:
Content Security Policy: The page’s settings blocked the loading of a resource at self (“script-src”).
Source: console.log("hello world");
va....
I read through the documentation and it seems like in-line javascript is not allowed by the default content security policy.
Relevant documentation:
The default content security policy for extensions is:
"script-src 'self'; object-src 'self';"
This will be applied to any extension that has not explicitly set its own content security policy using the
content_security_policy manifest.json
key. It has the following consequences:You may only load and resources that are local to the extension.
The extension is not allowed to evaluate strings as JavaScript.
Inline JavaScript is not executed.
I would solve the problem of inline javascript by using import statements, but according to Mozilla, those are not supported in Firefox right now: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
According to the documentation, it is possible to allow some inline Javascript by creating a sha-256 hash of your script.
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/content_security_policy
Allow the extension to execute inline scripts, by supplying the hash of the script in the "script-src" directive.
Allow the inline script:
<script>alert('Hello, world.');</script>
:
"content_security_policy": "script-src 'self' 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng='; object-src 'self'"
and this
Alternatively, you can create hashes from your inline scripts. CSP supports sha256, sha384 and sha512.
Content-Security-Policy: script-src 'sha256-B2yPHKaXnvFWtRChIbabYmUBFZdVfKKXHbWtWidDVF8='
When generating the hash, don't include the
<script>
tags and note that capitalization and whitespace matter, including leading or trailing whitespace.
So, I created a sha-256 hash of my script by highlighting the following text in "inject.html":
and using a SHA-256 calculator (I chose base-64 to remain consistent with the example): https://hash.online-convert.com/sha256-generator
and changing my "manifest.json" file to:
{
"manifest_version": 2,
"name": "Summarizer",
"version": "1.0",
"description": "Summarizes webpages",
"permissions": [
"activeTab",
"tabs",
"storage",
"downloads",
"*://*.smmry.com/*"
],
"icons":
{
"48": "icons/border-48.png"
},
"browser_action":
{
"browser_style": true,
"default_popup": "popup/choose_length_page.html",
"default_icon":
{
"16": "icons/summarizer-icon-16.png",
"32": "icons/summarizer-icon-32.png"
}
},
"web_accessible_resources": [
"inject-content/inject.html"
],
"content_security_policy": "script-src 'self' 'sha256-GdCLzZEX8DPwLRiIBZvv6ffymh4hz/9NgjmzyPv+lGM='; object-src 'self'"
}
Yet, my error still remained!
As such, my question is,
How can I allow my inline Javascript to execute without having this error? Is there a way to do this without having a hash?
Ideally, I'd like to avoid using inline javascript altogether, and instead move all of my inline javascript into the file of my content script. Since Firefox doesn't support import statements, is it possible for me to do that, and if so how? I have no experience with tools such as Babel.
Although the webpage says you can have trailing/leading whitespace, I was having issues with that. The solution turned out to be putting all my code on one line (and re-calculating the base 64 SHA-256 hash).
<script>console.log("Hello World");var perfectScrollbar = new PerfectScrollbar("#container",{suppressScrollX: true});</script>