Strange network bug on the extension page

Yeah, I know I have content scripts. The thing is that I want a single code base for “web version” (shich of course needs setting CORS headers on the remote) and the extension. And of course content scripts are available only in the extensions API, not in the basic web app.

I could replace eval with injecting script tags, I guess, but I see absolutely no difference here in terms of security.

DOM manipulation can be too heavy in terms of code when you need to create large nested structures of elements, such as table rows with cells inside them and links and icons inside that cells, for example, no? :slight_smile:

Here is the manifest contents:

{
  "manifest_version": 2,
  "name": "Lightning",
  "version": "1.0.0j",

  "icons": {
      "128": "icons/icon128.png",
      "16": "icons/icon16.png",
      "48": "icons/icon48.png"
  },
  "content_scripts": [
    {
      "matches": [ "<all_urls>" ],
	  "css": [ "styles/baloon.css" ],
      "js": [ "includes/script.js" ]
    }
  ],
  "options_ui": {
      "open_in_tab": true,
      "page": "options.html"
  },
  "background": {
    "scripts": ["js/background.js"]
  },
  "permissions": [
    "storage",
    "tabs"
  ],
  "web_accessible_resources": [
    "<all_urls>",
	"icons/*"
  ],
  "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
  "browser_action": {
      "default_title": "Lightning",
      "default_icon": "icons/icon.png",
      "default_popup": "popup.html"
  }

}

So as you can see, you are indeed missing "<all_urls>" permission in the "permissions" list :slight_smile:.

So yes, injecting script tags is not better if you again concatenating code :slight_smile:.

And yes, building DOM is not easy, but doable once you create some helper functions. If you need complex DOM, you should use some library for that, like Vue or React.

Why use heavy and slow libraries like Vue or React if this can be easily done using innerHTML (and in fact it is not much slower than building DOM “by hand” with createElement and appendChild)? HTML parsers built into modern browsers are good and optimized enough to perform this not so difficult task like parsing an HTML markup fragment. Why use Vue/React templates and parse them with Vue/React (it is slower anyway because this parsing is made with JS, not with C/C++)? It’s a really strange solution.

Also I brought up in memory that I am using eval in order to let users of my extensions use eval on their pages in test scripts: it can be extremely useful to evaluate some random expression rather than only get elements’ content and attributes :slight_smile:

So as you can see, you are indeed missing "<all_urls>" permission in the "permissions" list

Sorry, I don’t get it quite right, this manifest was taken from Chrome version. Is Firefox syntax different? Should I right the following:

{
  "manifest_version": 2,
  "name": "Lightning",
  "version": "1.0.0j",
  ...
  "permissions": [
    "storage",
    "tabs",
    "<all_urls>"
  ],
  ...
}

?

Because I already have this line in “web_accessible_resources” list. Is it doing nothing in Firefox?

I’ve mentioned Vue and React for when you need complex DOM. Because doing complicated things with vanilla javascript is never easy and frameworks like this makes it almost a piece of cake. And the performance impact is often negligible for the end user (even if it would take additional 100ms to load the page).

Anyhow, I’m just trying to help you avoid awkward situation when you get email from reviewer saying that you have 10 days to remove your innerHTML and eval :slight_smile:. It happened to me a long time ago with some other forbidden features I was not aware of.

Regarding eval for users - there is a special API for Firefox for this that should help: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/userScripts

And regarding the permissions - it’s the same in Firefox and Chrome, so I don’t really understand how it could ever work in Chrome without that permission. Something is fishy here…

The “web_accessible_resources” is for when you want to allow the target page use your own resources (like icons), see the docs: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/web_accessible_resources

(even if it would take additional 100ms to load the page

Sometimes it is much, much worse. See this article, for example: https://timkadlec.com/remembers/2020-04-21-the-cost-of-javascript-frameworks/

Ah, I got it finally. In Chrome it works the same way: I had to add this permission to use my local icons in my local CSS file for (otherwise no images were loaded and shown). But they were not shown on external pages (where I added something using content scripts). So I think I had no idea why I needed to write this and just did it automatically, so thanks for clarification.

It finally works, thanks in advance for your help! :smiley:

I tried to explore the link you have given about user scripts, but I don’t find it convenient and appropriate here :frowning:

First of all, its support starts with Firefox 68, whereas my approach can work anywhere since Firefox 45 or so (from the first version that implemented the WebExtensions API).

Second, I see that there is a lot of “fine tuning” options available (i.e. when exactly to run the script and so on), but for my purpose of “execute a short line of code and return the result immediately” it is not suitable at all, like shooting birds with cannon or something like that :smiley:

Thirdly, I still don’t understand at which point using this new API is better than injecting <script> in the contentScript code (if the code is coming from the user directly then security is the same, the “one-way” nature of execution without the possibility to pass data simply to the extension is also the same, but the difficulty of implementation is much greater in the userScript scenario). Well, maybe in the second case I can use extension APIs like sendMessage to pass the data to the background page, but they did not show the selective providing of Extension APIs to the userScript in the example…

Finally, I told you I have 2 different execution engines: the second one (“fullscreen” or “tabbed”) does not use eval, instead it injects <script> tags into target page, and in that script a special custom function call is attached which populates the hidden <div> with the data the user wants to receive. This works synchronously and quite well; no eval 's are used there. But the first engine (which is needed for use case outside the extension realm, i.e. in web version), really needs to use eval, because there is no other option available there. And as I already said, I would like to keep a single codebase for the project :wink:

UPD: Now I realize that the idea of data exchange with injecting <script> tags and reading back from a special hidden element can work equally good in web version, too. I will think about rewriting maybe. The only problem is that it makes the code larger and more complicated. But now, thanks to our discussion, I will have a “plan B” solution if they require me to delete eval 's completely from code.

1 Like

I guess the critical line (without which everything breaks in Chrome) is this one:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

Or maybe I am wrong and this only breaks my eval 's. Need to check once more.

Ah yes, I didn’t noticed that. That’s also very special feature that’s in the gray zone :slight_smile:.

Note from the MDN:

  1. Note: Valid examples display the correct use of keys in CSP. However, extensions with ‘unsafe-eval’, ‘unsafe-inline’, remote script, blob, or remote sources in their CSP are not allowed for extensions listed on addons.mozilla.org due to major security issues.

See more info here: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/content_security_policy