Chrome Extension - Uncaught DOMException: Blocked

2020-07-11 08:10发布

问题:

Before someone marks this post as a duplicate of another post, such as this: SecurityError: Blocked a frame with origin from accessing a cross-origin frame this post is different because it is about avoiding this error in the context of a Chrome web extension, which means there may be unique solutions.

I am porting a Firefox Quantum extension to Chrome. The extension injects an iFrame into the user's current web page. Right now, the extension works without problems in Firefox Quantum, you can find it here: https://addons.mozilla.org/en-US/firefox/addon/tl-dr-auto-summarizer/?src=search

The source of the iFrame is a HTML file called "inject.html" that is bundled within the extension.

Here is the shortened (to avoid making the post excessively long) code that injects the iFrame. This code is within a content script in the user's current tab:

var iFrame = document.createElement("iFrame");
iFrame.id = "contentFrame";
iFrame.classList.add("cleanslate");
iFrame.style.cssText = "width: 100% !important; height: 100% !important; border: none !important;";
iFrame.src = browser.extension.getURL("inject-content/inject.html");
document.body.appendChild(iFrame);

Here is the manifest.json

{
    "manifest_version": 2,
    "name": "TL;DR - Summarizer",
    "version": "3.0",

    "description": "Summarizes webpages",

    "permissions": [
        "activeTab",
        "tabs",
        "*://*.smmry.com/*"
    ],

    "icons":
    {
        "48": "icons/border-48.png"
    },

    "browser_action":
    {
        "browser_style": true,
        "default_popup": "popup/choose_length_page.html",
        "default_icon":
        {
            "16": "icons/summarizer-icon-16.png",
            "32": "icons/summarizer-icon-32.png"
        }
    },

    "web_accessible_resources": [
        "inject-content/inject.html",
        "inject-content/cleanslate.css"
    ],

    "content_security_policy": "script-src 'self' 'sha256-AeZmmPP/9ueCrodQPplotiV3Pw0YW4QqifjUL7NE248='; object-src 'self'"

}

After injecting the iFrame, I set the "click" listeners for the buttons within the iFrame, once the iFrame has loaded. I do this using the following code sample. However, while the following code works in Firefox Quantum, it throws an exception in Chrome.

iFrame.onload = () => {

                //The error occurs on the following line.

                var closeButton = iFrame.contentWindow.document.getElementById("close-btn");

                closeButton.addEventListener("click", () => {
                    //Do Stuff
                });

                var copyButton = iFrame.contentWindow.document.getElementById("copy-btn");

                copyButton.addEventListener("click", () => {
                    //Do stuff
                });

            }

I get the following exception:

Uncaught DOMException: Blocked a frame with origin "http://example.com" from accessing a cross-origin frame. at HTMLIFrameElement.iFrame.onload (file:///C:/Users/vroy1/Documents/Programming/web-extension-summarizer/src/inject-content/inject.js:58:56)

How can I avoid this error?

In case anyone is wondering, the reason I am able to use the Promise API and the browser namespace inside of a Chrome extension is because I am using a polyfill provided by Mozilla that allows me to use promises and the browser namespace.

Here is the code for the popup that the extension displays when its toolbar icon is clicked:

//Enable the polyfill for the content script and execute it in the current tab

browser.tabs.executeScript({ file: "/polyfills/browser-polyfill.js" }).then(loadContentScript).catch((error) => logError(error));

function loadContentScript() {
    browser.tabs.executeScript({ file: "/inject-content/inject.js" }).then(listenForClicks).catch((error) => logError(error));
}

function listenForClicks() {
    document.addEventListener('click', e => {
        if (!e.target.classList.contains('btn')) {
            return;
        } else {
            browser.tabs.query({ active: true, currentWindow: true })
                .then(tabs => {
                    browser.tabs.sendMessage(tabs[0].id, { summaryLength: e.target.id, targetURL: tabs[0].url });
                });
        }
    });
}

function logError(error) {
    console.log(error);
}

Lastly, here is the full code of the content script:

https://pastebin.com/Yrs68zAB

回答1:

You can try uploading that code, what you want on your iframe, to a web server, and setting the header.

'Access-Control-Allow-Origin: *'

Firefox usually works better with local files, that could explain your error

origin "http://example.com" from accessing a cross-origin frame. at file:///C:/Users/vroy1/Documents/Programming/web-extension-summarizer/src/inject-content/inject.js


回答2:

For Chrome--I included a script tag in my iframe. I then could use <button element>.addEventListener("click", function() {} inside of the script loaded by the iframe. For frame to host communication, I used window.parent.postMessage and other such methods. In order to load the iframe, I added the following to my manifest.json:

  "web_accessible_resources": [
    "inject-content/inject.html",
    "inject-content/cleanslate.css"
  ]