awesome-webextension / webpack-target-webextension

WebExtension Target for Webpack 5. Supports code-splitting and HMR.
MIT License
44 stars 5 forks source link

It appears to fail on sandboxed frames without `allow-scripts` #41

Closed fregante closed 7 months ago

fregante commented 8 months ago

I'm still looking into it, but it seems that the first chunk runs correctly, but then anything import()'d fails with this error:

contentScript.js:18475 Uncaught (in promise) ChunkLoadError: Loading chunk vendors-node_modules_emotion_react_dist_emotion-react_browser_esm_js failed.
(undefined: undefined)
    at __webpack_require__.f.j (contentScript.js:18475:29)
    at contentScript.js:18249:40
    at Array.reduce (<anonymous>)
    at __webpack_require__.e (contentScript.js:18248:67)
    at initContentScript (contentScript.js:18610:229)
    at contentScript.js:18630:10
    at contentScript.js:18638:3
    at contentScript.js:18640:12

It looks like import works fine though, I can run this in the console for that frame:

const code = 'export const foo = 123'
const imported = await import(`data:text/javascript;charset=utf-8,${encodeURIComponent(code)}`)
console.log(imported.foo) // Should print 123
fregante commented 8 months ago

The repro should look something like:

<html>
<body>
  <!-- srcdoc or src, same issue-->
  <iframe srcdoc="<p>Hello world!</p>" sandbox>
</body>
</html>
console.log('contentscript.js')
import('./secondary.js')
console.log('secondary.js')
{
  "name": "sandbox iframe",
  "version": "1.0.7",
  "manifest_version": 2,
  "description": "Demo extension",
  "content_scripts": [
    {
      "matches": ["*://*/*"],
      "js": ["contentscript.js"],
      "all_frames": true,
      "match_about_blank": true
    }
  ]
}

Using

    "webpack": "^5.89.0",
    "webpack-target-webextension": "^1.1.0",
Jack-Works commented 8 months ago

I'll investigate this next week, thanks for your report!

fregante commented 8 months ago

Thank you! By the way this is the actual error produced:

image

It seems that the modules are loaded, but they are not registered in the global chunk list, so after the import() is completed, the chunk can't be found on that line.

Does the chunk loader inject script tags in order to work? Even after using import() to load them? Because that's how the content script might end up running in the "unsafe world" and be blocked.

Jack-Works commented 8 months ago

@fregante according to the error message, the execution failed because the "document's frame is sandboxed and the 'allow-scripts' permission is not set."

did you try <iframe sandbox="allow-scripts" ...?

fregante commented 8 months ago

The point is that the script is running, regardless of the sandbox, because that error comes from webpack.

The main chunk runs, the imports don't.

Imports should run too, as shown in the import() example, without altering/losing the sandbox.

Jack-Works commented 8 months ago

hello, I found it is a Chrome bug. See https://bugs.chromium.org/p/chromium/issues/detail?id=816121 and please state your use case to let it fixed.

I'll try to make a workaround.

Jack-Works commented 8 months ago

@fregante plz try this https://github.com/awesome-webextension/webpack-target-webextension/pull/42

fregante commented 8 months ago

I found a way via fetch:

async function init() {
  console.log('Hello from content script')
  const inner = await fetch(chrome.runtime.getURL('./inner.js'))
  const innerText = await res.text()
  import(`data:text/javascript;charset=utf-8,${encodeURIComponent(innerText)}`).then(console.log)
}

init()
// inner.js
export const foo = 123;
console.log('Hello from inner script')
Screenshot
fregante commented 8 months ago

…but that's gonna break sourcemaps so it's not a great solution to this. Maybe this already works:

https://github.com/awesome-webextension/webpack-target-webextension#optionsbackground

fregante commented 8 months ago

hello, I found it is a Chrome bug. See https://bugs.chromium.org/p/chromium/issues/detail?id=816121 and please state your use case to let it fixed.

I don’t think that's quite the same issue, although it's certainly related. The issue mentions <iframe sandbox src="chrome-extension://"> rather than content scripts and import() specifically.

It's a different context entirely: "main world on extension page" vs "isolated world on web page".

In our case, scripts do run, but import() fails. It's a dejavu to the times when import() did not work in content scripts because the script was being interpreted in the wrong context. I think the sandbox is escaping/breaking the fix that was implemented at that time.

Related discussions:

Jack-Works commented 7 months ago

hi, 1.1.1 has been released @fregante

https://github.com/awesome-webextension/webpack-target-webextension/blob/master/CHANGELOG.md#111