Search code examples
javascriptgoogle-chrome-extension

Chrome extension how to expose custom API to webpage?


My web application needs access to UDP sockets, something that the web does not support, presumably for security reasons. I have decided to create a chrome extension that users are required to install to use my web application, of course doing this at their own risk.

The idea is for my extension to expose custom UDP socket APIs by adding a global variable such as myExtension.udpSockets to webpages. The webpage can check that window.myExtension exists first (the extension is installed) before attempting to access my UDP socket API.

When a webpage accesses my UDP socket API, I will create a popup to ensure that the user would like to give this webpage access to UDP sockets and state the security implications.

I currently have my code in a content script, e.g.

function createUDPSocket() {
  // use chrome API
  console.log("Creating a UDP socket!");
}

I know I can inject JavaScript into the webpage by modifying the DOM.

document.createElement("script");
// etc.

But how can I expose my API to this webpage? They are in separate JS contexts, so this wouldn't work. Is there some way of communicating between them?


Edt: It seems I'm looking for something similar to exportFunction in Firefox extensions.


Solution

  • There's no exportFunction/cloneInto in Chrome so you'll have to use a DOM script element and messaging.

    You can use the secure extension API messaging via externally_connectable directly to the background script (in Chrome 107 and newer its matches descriptor allows <all_urls>). The message must be JSON-compatible (number, string, boolean, null, and objects/arrays consisting of these types).

    Otherwise, for DOM messaging I suggest using CustomEvent with a unique or even better a random event id, definitely not postMessage, so that no other code can eavesdrop on your channel (assuming you use a random event id which can be passed to the script element when created using textContent, see method 2). CustomEvent supports a lot of structured-cloneable types. To send DOM element use new MouseEvent('foo', {relatedTarget: domNode}) where foo is the unique id of your message for which the listener in the other script is listening to.