6

I'm in the process of updating my chrome extension from manifest v2 to v3. Here's the old manifest:

Manifest V2:

{
"manifest_version": 2,
"name": "Legacy Search Assistant",
"version": "0.1.1",
"content_scripts": [
    {
        "matches": [
            "https://*.legacysite.io/*","*://*/api*"
        ],
        "js": ["jquery-3.6.0.min.js","content.js"]
    }
],
"options_page": "options.html",
"background": {
    "scripts": ["jsencrypt.min.js", "jquery-3.6.0.min.js", "background.js"]
},
"browser_action": {
    "default_icon":  "icon.png",
    "default_popup": "popup.html",
    "default_title": "Legacy Search"
},
"permissions": [
    "storage"
]
}

Since jsencrypt.min.js was already loaded in the manifest I was able to call it's functions in background.js, but now that I've gone to manifest v3 I am having problems getting the service worker to access this library.

For example, when I make this call in background.js:

importScripts("/scripts/jsencrypt.min.js");

It throws the following error:

Error handling response: Error: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'chrome-extension://<extension ID>/scripts/jsencrypt.min.js' failed to load.

If I click the link in the error it takes me directly to the library I want loaded.

I've already tried all of the fixes in this answer. Please help if you can.

alcor8
  • 327
  • 2
  • 13
  • 1
    jsencrypt uses `window` which is absent in service worker so you should set it e.g. `self.window = self` before importing the script. If it doesn't help you should debug what happens: remove importScripts, reload the extension, open devtools for the background script, make a new snippet in Sources panel and paste the code of that library, save and run it. – wOxxOm Jan 19 '22 at 18:57
  • @wOxxOm If I have a listener event waiting for a message from the content script, would I need to call `self.window = self` prior to `importScripts(jsencrypt.min.js);`? This didn't work but maybe I'm doing it all wrong. – alcor8 Jan 19 '22 at 22:10
  • 1
    you could think to give a chance to "web crypto" api and its methods. It works in web\service worker. See here: https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/encrypt – Robbi Jan 21 '22 at 15:45

2 Answers2

5

importScripts() is old way to load scripts in workers.

Now we can use more modern, ES modules instead.

Starting from Chrome 91, we can use JavaScript modules in service workers.

Just set type property to module in the manifest.

{
"manifest_version": 3,
"background": {
  "service_worker": "background.js",
  "type": "module"
}

This loads the service worker as an ES module, which lets you use the import keyword in the service worker to import other modules. Ex-

// background.js
import * as module from './scripts/jsencrypt.min.js';

But make sure that the script you are importing like ./scripts/jsencrypt.min.js in this case, has exported the required code that you want to use.

Learn about ES modules

T Sohail
  • 51
  • 3
  • Would I place this at the top of the background.js or within the listener? I understand the service worker going to sleep can cause issues. – alcor8 Jan 26 '22 at 17:45
  • Yes, you should use **import** at the top of the script (in the global scope). So, you can access the modules from everywhere (every scope) in the service worker (background.js). – T Sohail Jan 27 '22 at 03:42
  • If I wanted to initialize an object from the module would I do something like this to initialize it for use ???: let RSAEncrypt = new module.JSEncrypt(); – alcor8 Aug 17 '22 at 22:24
0

The solution I ended up using was to move all usage of jsencrypt to the content.js. This allowed the module to function correctly and will not expose the public key in the environment we use our chrome extension in.

After creation and initializing of the jsencrypt object I pass it to the background script via a message.

alcor8
  • 327
  • 2
  • 13