Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject javascript from content script with a chrome extension v3

I'm migration my extension from V2 to V3. Now all is working fine except for one thing. In my V2 version I did

const actualCode = '(' + function () { 'console.log("demo");' } + `)();`;
const script = document.createElement('script');
script.textContent = actualCode;
(document.head || document.documentElement).appendChild(script);
script.remove();

Note that the console.log("demo") is a simplification of what I need to inject :)

I need to inject some javascript for my chrome-extension-magic to take place.

Now, in V3 this doesn't work anymore. I get the following error in my devtools-console

content.js:23114 
    
   Refused to execute inline script because it violates the following 
   ContentSecurity Policy directive: "script-src 'self'". Either the 
   'unsafe-inline' keyword, a hash ('sha256-tN52+5...6d2I/Szq8='), or a nonce
   ('nonce-...') is required to enable inline execution.

In the migration guide I noticed this section

"content_security_policy": {
   "extension_pages": "...",
   "sandbox": "..."
}

but there is not much description there, so this is magic to me. So I hope someone know can help me with this?

like image 515
Jeanluca Scaljeri Avatar asked Mar 25 '26 11:03

Jeanluca Scaljeri


1 Answers

Refer to Access variables and functions defined in page context from an extension

Since content scripts are executed in an "isolated world" environment, we can't do some special dom operations in content_script js.

This example will show you how to inject injected-script.js to web page before "document start":

content-script.js

function injectScript (src) {
    const s = document.createElement('script');
    s.src = chrome.runtime.getURL(src);
    s.onload = () => s.remove();
    (document.head || document.documentElement).append(s);
}

injectScript('injected-script.js')

manifest.json (Manifest V3)

"content_scripts": [
    {
        "matches": ["<all_urls>"],
        "js": ["content-script.js"],
        "run_at": "document_start" // <-- Instead of the default "document_end"
    }
],
"web_accessible_resources": [{
    "resources": ["injected-script.js"], // <-- Don't forget to add this
    "matches": ["<all_urls>"]
}]

Updated: 2023-03-08

To support es6 module imports, just add s.type = "module"

content-script.js

function injectScript (src) {
    const s = document.createElement('script');
    s.src = chrome.runtime.getURL(src);
    s.type = "module" // <-- Add this line for ESM module support
    s.onload = () => s.remove();
    (document.head || document.documentElement).append(s);
}

injectScript('injected-script.js')

Then you could use the es6 import statement like this:

injected-script.js

import { doStuff } from './my-other-script.js';

doStuff();
like image 66
ahuigo Avatar answered Mar 28 '26 02:03

ahuigo