GoogleChrome / chrome-extensions-samples

Chrome Extensions Samples
https://developer.chrome.com/docs/extensions
Apache License 2.0
15.48k stars 8.23k forks source link

Sample: Calling element.click() on an element with an inline event handler #807

Open dotproto opened 1 year ago

dotproto commented 1 year ago

Overview

Starting with Manifest V3, Chrome introduced a strict content security policy (CSP) for content scripts run in the extension's isolated world (default behavior). This CSP does not allow the use of unsafe-inline. This prevents extensions from appending <script> tags with arbitrary payloads to a document, but it also prevents other extensions from calling the click() method on elements that have click handlers.

This issue request the creation of an extension sample that demonstrates how to click an element that has an inline event while still complying with the Chrome Web Store's policies forbidding "remotely hosted code" (executing code that is not bundled in the extension's package).

Proposed implementation

If a website contains inline event handlers, the page's CSP must allow unsafe-inline or those event handlers won't work. As such, we can work around extension CSP restrictions by performing the click() call inside a main world content script.

The user experience for this implementation is roughly as follows:

  1. The first time the user clicks the extension's action button, a new tab will open to a demo site with inline event handlers.
  2. When the user clicks the extensions' action button while the demo site is in the currently focused tab, the extension will perform a "click()" on an element with an inline event handler.

The extension will have 3 primary components: background.js; content-isolated.js, which will be injected into the extension's isolated world; and content-main.js (or equivalent function in background.js), which will be injected into the page's main world.

content-main.js will perform the click on behalf of the extension. It will receive a message from content-isolated.js

In order to communicate between the main world and isolated world content scripts, the extension will dispatch a custom event that uses a nonce name known to both the main and isolated worlds. This pattern helps ensure that the event's cross-world communication does not interfere with normal page operations.

Additional considerations

The README for this sample should highlight that the use of custom events with nonce names does not guarantee that a hostile page will not intercept the message, as the page could monkeypatch the JavaScript environment in a way that allows it to intercept object constructors or event listener registrations.

CustomElements can pass data across the world boundary by setting the detail property when instantiating a new custom element, but only if that data is cloneable with the structuredClone algorithm. If it cannot be cloned, the custom element's event.detail property in the receiving world will be null.

M-SAI-SOORYA commented 1 year ago

It is recommended to use external scripts. First, you need to add the "activeTab" permission to your extension's manifest.json file. Then, create a content script (content.js) that injects a script into the active tab's DOM.... ....the code selects an element with the ID "mybutton" and triggers a click event on it. At final instance, add the element with the inline event to the HTML file bundled in your extension.

With these steps, you should be able to click an element with an inline event while still complying with the Chrome Web Store's policies forbidding remotely hosted code.

dotproto commented 1 year ago

@M-SAI-SOORYA, it IS NOT recommended to use external scripts. Doing so in a Manifest V3 extension is a violation of the Chrome Web Store developer program policies.