Chrome Extension: Accessing `window` works on remote websites, but not possible in localhost

Viewed 48

I have a very simple Chrome Extension that defines a constant on the window object.

It works on online websites but fails on tabs that display local files with

Blocked script execution in 'file:...mht' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

I would somehow understand if it was the opposite way for security but this way it feels like I can do something in the extensions to fix this in a way that it also works for local offline files.

manifest.json

{
  "name": "Extension Expose",
  "description": "Extension.",
  "version": "1.0",
  "manifest_version": 3,
  "content_scripts": [
    {
      "matches": ["http://*/*", "https://*/*", "http://localhost/*", "https://localhost/*"],
      "js": ["content.js"]
    }
  ],
  "web_accessible_resources": [{ 
    "resources": ["write.js"],
    "matches": ["http://*/*", "https://*/*", "http://localhost/*", "https://localhost/*"]
  }]
}

content.js

console.log("content.js")

var s = document.createElement('script');
s.src = chrome.runtime.getURL('write.js');
s.onload = function() {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);

write.js

console.log("write.js")
window.ee = "abc"
console.log("successfully written to window")

On any live website it does its job perfectly

enter image description here

However if I open a local .mht I get the following

enter image description here

Adding to this, I have now set the matches to ["http://*/*", "https://*/*", "http://localhost/*", "https://localhost/*", "file://*", "file://*/*", "http://127.0.0.1/*", "https://127.0.0.1/*"] just to be extra safe, that didn't change anything.

In a pure html file the console throws

content.js:8 GET chrome-extension://abcdef/write.js net::ERR_BLOCKED_BY_CLIENT,

which has probably something to do with a cross-domain http request but I don't understand why the same error won't trigger on mht files

Alternatives

I found this answer https://stackoverflow.com/a/9517879 that lists a lot of different ways to do similar things. What I am doing primarily here is Method 1. What's interesting is that Method 3 (defining a script inline) does work for online html as well as offline html, but this still fails on .mht unfortunately. I suppose it's because of the way the .mht works internally.

1 Answers

There's a bug with web_accessible_resources on file:// pages, fixed only in Chrome 106.

A better solution is to use chrome.scripting instead anyway because it can set the variable before the page starts loading reliably and we don't make our extension detectable by web sites.

  1. Remove content_scripts and web_accessible_resources from manifest.json.
  2. Remove content.js
  3. Add to manifest.json:
  "background": {"service_worker": "bg.js"},
  "permissions": ["scripting"],
  "host_permissions": ["<all_urls>"]
  1. Add background.js:
chrome.runtime.onInstalled.addListener(async () => {
  const old = await chrome.scripting.getRegisteredContentScripts();
  if (old[0]) await chrome.scripting.unregisterContentScripts({ids: old.map(s => s.id)});
  await chrome.scripting.registerContentScripts([{
    id: 'write',
    js: ['write.js'],
    matches: ['<all_urls>'],
    runAt: 'document_start',
    world: 'MAIN',
  }]);
});
Related