I am trying to load (inject) in page a javascript code. The javascript file is local to the extension. the filepath is ‘js/somefile.js’.
JavaScript
x
17
17
1
const basePath = chrome.runtime.getURL('');
2
fetch(chrome.runtime.getURL(filePath), { mode: 'same-origin' }) // <-- important
3
.then((_res) => _res.blob())
4
.then((_blob) => {
5
const reader = new FileReader();
6
reader.addEventListener('loadend', (data) => {
7
callback(data.currentTarget.result, basePath);
8
});
9
reader.readAsText(_blob);
10
});
11
12
const scriptTag = document.createElement('script');
13
scriptTag.innerHTML = scriptText;
14
scriptTag.type = 'text/javascript';
15
const scriptElement = document[injectLocation].appendChild(scriptTag);
16
if (removeImmediately) document[injectLocation].removeChild(scriptElement);
17
My web accessible resources are:
JavaScript
1
12
12
1
"web_accessible_resources": [{
2
"resources": [
3
"js/*.js",
4
],
5
"matches": ["<all_urls>"]
6
}],
7
8
"content_security_policy": {
9
"extension_pages": "script-src 'self'; object-src 'self'",
10
"sandbox": "sandbox allow-scripts; script-src 'self' 'https://apis.google.com/' 'https://www.gstatic.com/' 'https://*.firebaseio.com' 'https://www.googleapis.com' 'https://ajax.googleapis.com'; object-src 'self'"
11
},
12
The error that I get is:
JavaScript
1
2
1
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self'". Either the 'unsafe-inline' keyword, a hash ('sha256-Wq/CW2mxkri68TjkuaA0+LnU0capVpyiEuSA5NOVNfU='), or a nonce ('nonce-...') is required to enable inline execution.
2
Advertisement
Answer
You can resolve the inline execution error by changing scriptTag.innerHTML = scriptText;
to scriptTag.src = chrome.runtime.getURL(filePath);
, no need to fetch the script. Manifest v3 seems to only allow injecting static scripts into the page context.
If you want to run dynamically sourced scripts I think this can be achieved by having the static (already trusted) script fetch a remote script then eval it.
UPDATE: example extension, with manifest v3, that injects a script that operates in the page context.
JavaScript
1
3
1
# myscript.js
2
window.variableInMainContext = "hi"
3
JavaScript
1
22
22
1
# manifest.json
2
{
3
"name": "example",
4
"version": "1.0",
5
"description": "example extension",
6
"manifest_version": 3,
7
"content_scripts": [
8
{
9
"matches": ["https://*/*"],
10
"run_at": "document_start",
11
"js": ["inject.js"]
12
}
13
],
14
"web_accessible_resources": [
15
{
16
"resources": [ "myscript.js" ],
17
"matches": [ "https://*/*" ]
18
}
19
]
20
}
21
22
JavaScript
1
24
24
1
# inject.js
2
3
const nullthrows = (v) => {
4
if (v == null) throw new Error("it's a null");
5
return v;
6
}
7
8
function injectCode(src) {
9
const script = document.createElement('script');
10
// This is why it works!
11
script.src = src;
12
script.onload = function() {
13
console.log("script injected");
14
this.remove();
15
};
16
17
// This script runs before the <head> element is created,
18
// so we add the script to <html> instead.
19
nullthrows(document.head || document.documentElement).appendChild(script);
20
}
21
22
23
injectCode(chrome.runtime.getURL('/myscript.js'));
24