samrum / vite-plugin-web-extension

A vite plugin for generating cross browser platform, ES module based web extensions.
MIT License
331 stars 32 forks source link

Popup & Options pages inlude inline JS from HMR violating CSP #85

Closed romanzipp closed 1 year ago

romanzipp commented 1 year ago

I ran into an issue where the extension popup & options page could not be loaded by Chromium (110.0.5481.77) or Google Chrome (110.0.5481.177) with the following error message:

Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' http://localhost:5173". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.

Screenshot 2023-03-07 at 19 53 53

The output popup index.html file contains some inline JS from react-refresh (HMR?)

<!DOCTYPE html>
<html lang="en">
  <head>
    <script type="module">
import RefreshRuntime from "http://localhost:5173/@react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>

    <script type="module" src="http://localhost:5173/@vite/client"></script>

    <meta charset="UTF-8" />
    <title>Popup</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="http://localhost:5173/src/entries/options/main.jsx"></script>
  </body>
</html>
manifest.json ```json { "author": "Roman Zipp", "description": "redacted", "name": "redacted", "version": "0.0.1", "content_scripts": [ { "js": [ "src/entries/contentScript/primary/main.js" ], "matches": [ "redacted" ] }, { "js": [ "src/entries/contentScript/handshake/main.js" ], "matches": [ "redacted" ] } ], "icons": { "16": "icons/16.png", "19": "icons/19.png", "32": "icons/32.png", "38": "icons/38.png", "48": "icons/48.png", "64": "icons/64.png", "96": "icons/96.png", "128": "icons/128.png", "256": "icons/256.png", "512": "icons/512.png" }, "options_ui": { "page": "src/entries/options/index.html", "open_in_tab": true }, "permissions": [ "storage" ], "content_security_policy": { "extension_pages": "script-src 'self' http://localhost:5173; object-src 'self'" }, "action": { "default_icon": { "16": "icons/16.png", "19": "icons/19.png", "32": "icons/32.png", "38": "icons/38.png" }, "default_popup": "src/entries/popup/index.html" }, "background": { "service_worker": "serviceWorker.js", "type": "module" }, "host_permissions": [ "redacted" ], "manifest_version": 3 } ```

According to the CSP docs there's no way to loosen the security policy in MV 2 & 3 for Chromium based browsers.

The @samrum/vite-plugin-web-extension package is up-to-date with version 3.1.1

I've generated the extension code base via your create-vite-plugin-web-extension utility for React.

Let me know if you need any further information. Thanks for your great work so far!

samrum commented 1 year ago

Hmm, yeah, this is a Manifest V3 issue. In Manifest V2, this plugin automatically adds the hash for the inline script to the CSP and it works fine, but hashes are no longer supported in V3.

Because of the HMR code added in https://github.com/samrum/create-vite-plugin-web-extension's react templates, it seems like supporting that inline script in HTML isn't actually all that necessary.

Preventing viteDevServer!.transformIndexHtml from being called in devBuilder's writeManifestHtmlFile would be one way of fixing it. Probably via an option.

maltoze commented 1 year ago

still have this issue in version 5.0.0

image

romanzipp commented 7 months ago

@maltoze A bit late, but requiring the enableDevHmr file in your Popup entry script resolves the isse.

animber0 commented 7 months ago

@maltoze A bit late, but requiring the enableDevHmr file in your Popup entry script resolves the issue.

Hi, I'm getting the same issue but for content scripts calling inline iframe code, how do I fix that if you would be so kind? I've tried importing the enableDevHmr, but that's not working either.

chengfengfengwang commented 7 months ago

@maltoze A bit late, but requiring the enableDevHmr file in your Popup entry script resolves the issue.

Hi, I'm getting the same issue but for content scripts calling inline iframe code, how do I fix that if you would be so kind? I've tried importing the enableDevHmr, but that's not working either.

the same to me

image

the inline sccript cause csp error

alecmarcus commented 5 months ago

A bit late, but requiring the enableDevHmr file in your Popup entry script resolves the isse.

@romanzipp Sorry for the basic question but, from where, and how does it stop the plugin from injecting this?

Manually extracting the script into a file and including it in either my entry script (Popup.tsx) or popup.html doesn't fix — the script is still getting injected.

I have found that including the script in my popup.html and deleting the injected tag from the generated popup.html does "work". But is obviously not maintainable.

ie:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <noscript>You need to enable Javascript to run this application.</noscript>
    <div id="root">
      <!-- Your react app will be rendered here -->
    </div>
    <script type="module" src="./src/enableDevHmr.js"></script>
    <script type="module" src="./src/Popup.tsx"></script>
  </body>
</html>
import RefreshRuntime from "react-refresh";

if (import.meta.hot) {
  RefreshRuntime.injectIntoGlobalHook(window);
  window.$RefreshReg$ = () => {};
  window.$RefreshSig$ = () => type => type;
  window.__vite_plugin_react_preamble_installed__ = true;
}
romanzipp commented 5 months ago

@alecmarcus I added an import statement import '~/enableDevHmr.js in the same file that is setting up the react root (createRoot(...).render(...)). Maybe this helps - currently replying from mobile so I don't have any exact code snippets. Let me know if this works for you, otherwise i'll explain it in detail.

pivanov commented 1 week ago
image
import RefreshRuntime from '/@react-refresh';

if (import.meta.hot) {
  RefreshRuntime.injectIntoGlobalHook(window);
  window.$RefreshReg$ = () => {};
  window.$RefreshSig$ = () => (type) => type;
  window.__vite_plugin_react_preamble_installed__ = true;
}
// popup/main.ts
import './enableDevHmr';

... and the error still exist when I open the popup. I've try to add directly a import enableDevHmr.js to the html but this one still exist in my html:

<script type="module">
  import RefreshRuntime from "/@react-refresh"
  RefreshRuntime.injectIntoGlobalHook(window)
  window.$RefreshReg$ = () => {}
  window.$RefreshSig$ = () => (type) => type
  window.__vite_plugin_react_preamble_installed__ = true
</script>