Message transmis

�tant donn� que les scripts de contenu s'ex�cutent dans le contexte d'une page�Web, et non de l'extension qui les ex�cute, ils ont souvent besoin de moyens de communiquer avec le reste de l'extension. Par exemple, une extension de lecteur RSS peut utiliser des scripts de contenu pour d�tecter la pr�sence d'un flux�RSS sur une page, puis demander au service�worker d'afficher une ic�ne d'action pour cette page.

Cette communication utilise la transmission de messages, ce qui permet aux extensions et aux scripts de contenu d'�couter mutuellement leurs messages et de r�pondre sur le m�me canal. Un message peut contenir tout objet JSON valide (null, bool�en, nombre, cha�ne, tableau ou objet). Il existe deux API de transmission de messages: une pour les requ�tes ponctuelles et une plus complexe pour les connexions de longue dur�e qui permettent l'envoi de plusieurs messages. Pour en savoir plus sur l'envoi�de�messages entre les extensions, consultez la section Messages multi-extensions.

Requ�tes uniques

Pour envoyer un seul message � une autre partie de votre extension et �ventuellement obtenir une r�ponse, appelez runtime.sendMessage() ou tabs.sendMessage(). Ces m�thodes vous permettent d'envoyer un message s�rialisable JSON unique � partir d'un script de contenu vers l'extension, ou de l'extension vers un script de contenu. Pour g�rer la r�ponse, utilisez la promesse renvoy�e. Pour assurer la r�trocompatibilit� avec les extensions plus anciennes, vous pouvez transmettre un rappel en tant que dernier argument. Vous ne pouvez pas utiliser de promesse et de rappel dans le m�me appel.

Pour plus d'informations sur la conversion des rappels en promesses et sur leur utilisation dans les extensions, consultez le guide�de�migration vers Manifest V3.

Voici comment envoyer une requ�te � partir d'un script de contenu:

content-script.js:

(async () => {
  const response = await chrome.runtime.sendMessage({greeting: "hello"});
  // do something with response here, not outside the function
  console.log(response);
})();

Pour envoyer une requ�te � un script de contenu, sp�cifiez l'onglet auquel la requ�te s'applique, comme indiqu� ci-dessous. Cet exemple fonctionne dans les service workers, les fen�tres pop-up et les pages chrome-extension:// ouvertes dans un onglet.

(async () => {
  const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
  const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
  // do something with response here, not outside the function
  console.log(response);
})();

Pour recevoir le message, configurez un �couteur d'�v�nements runtime.onMessage. Celles-ci utilisent le m�me code dans les extensions et les scripts de contenu:

content-script.js ou service-worker.js:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting === "hello")
      sendResponse({farewell: "goodbye"});
  }
);

Dans l'exemple pr�c�dent, sendResponse() a �t� appel� de mani�re synchrone. Pour utiliser sendResponse() de mani�re asynchrone, ajoutez return true; au gestionnaire d'�v�nements onMessage.

Si plusieurs pages �coutent des �v�nements onMessage, seule la premi�re � appeler sendResponse() pour un �v�nement particulier r�ussira � envoyer la r�ponse. Toutes les autres r�ponses � cet �v�nement seront ignor�es.

Connexions de longue dur�e

Pour cr�er un canal de transmission de messages r�utilisables et � longue dur�e de vie, appelez runtime.connect() pour transmettre les messages d'un script de contenu vers une page d'extension, ou tabs.connect() pour transmettre les messages d'une page d'extension � un script de contenu. Vous pouvez nommer votre cha�ne pour distinguer les diff�rents types de connexions.

L'extension de remplissage automatique de formulaire est un cas d'utilisation potentiel d'une connexion longue dur�e. Le script de contenu peut ouvrir un canal vers la page de l'extension pour une connexion sp�cifique et envoyer un message � l'extension pour chaque �l�ment d'entr�e de la page afin de demander les donn�es de formulaire � remplir. La connexion partag�e permet � l'extension de partager l'�tat entre les composants d'extension.

Lors de l'�tablissement d'une connexion, un objet runtime.Port est attribu� � chaque extr�mit� pour envoyer et recevoir des messages via cette connexion.

Utilisez le code suivant pour ouvrir un canal � partir d'un script de contenu, puis envoyer et �couter des messages:

content-script.js:

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question === "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question === "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

Pour envoyer une requ�te de l'extension � un script de contenu, remplacez l'appel � runtime.connect() dans l'exemple pr�c�dent par tabs.connect().

Pour g�rer les connexions entrantes pour un script de contenu ou une page d'extension, configurez un �couteur d'�v�nements runtime.onConnect. Lorsqu'une autre partie de votre extension appelle connect(), elle active cet �v�nement et l'objet runtime.Port. Le code permettant de r�pondre aux connexions entrantes se pr�sente comme suit:

service-worker.js :

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name === "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke === "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer === "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer === "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

Dur�e de vie du port

Les ports sont con�us comme un moyen de communication bidirectionnel entre diff�rentes parties de l'extension. Un cadre de niveau sup�rieur est la plus petite partie d'une extension pouvant utiliser un port. Lorsqu'une extension appelle tabs.connect(), runtime.connect() ou runtime.connectNative(), elle cr�e un port permettant d'envoyer imm�diatement des messages � l'aide de postMessage().

S'il y a plusieurs frames dans un onglet, l'appel de tabs.connect() appelle l'�v�nement runtime.onConnect une fois pour chaque frame de l'onglet. De m�me, si runtime.connect() est appel�, l'�v�nement onConnect peut se d�clencher une fois pour chaque frame du processus d'extension.

Vous voudrez peut-�tre savoir quand une connexion est ferm�e, par exemple si vous conservez des �tats distincts pour chaque port ouvert. Pour ce faire, �coutez l'�v�nement runtime.Port.onDisconnect. Cet �v�nement se d�clenche lorsqu'il n'y a pas de port valide � l'autre extr�mit� du canal. Cela peut avoir l'une des causes suivantes:

  • Il n'y a pas d'�couteur pour runtime.onConnect � l'autre extr�mit�.
  • L'onglet contenant le port est d�charg� (par exemple, s'il est parcouru).
  • Le frame dans lequel connect() a �t� appel� a �t� d�charg�.
  • Toutes les trames qui ont re�u le port (via runtime.onConnect) ont �t� d�charg�es.
  • runtime.Port.disconnect() est appel� par l'autre extr�mit�. Si un appel connect() entra�ne plusieurs ports du c�t� du r�cepteur et que disconnect() est appel� sur l'un de ces ports, l'�v�nement onDisconnect ne se d�clenche que sur le port d'envoi, et non sur les autres ports.

Messages sur les extensions multiples

En plus d'envoyer des messages entre diff�rents composants de votre extension, vous pouvez utiliser l'API de messagerie pour communiquer avec d'autres extensions. Cela vous permet d'exposer une API�publique pour que d'autres extensions puissent l'utiliser.

Pour �couter les requ�tes entrantes et les connexions provenant d'autres extensions, utilisez les m�thodes runtime.onMessageExternal ou runtime.onConnectExternal. Voici un exemple de chaque option:

service-worker.js

// For a single request:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id === blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

Pour envoyer un message � une autre extension, transmettez l'ID de l'extension avec laquelle vous souhaitez communiquer. Pour ce faire, proc�dez comme suit:

service-worker.js

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// For a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// For a long-lived connection:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

Envoyer des messages � partir de pages Web

Les extensions peuvent �galement recevoir des messages d'autres pages Web et y r�pondre, mais elles ne peuvent pas envoyer de messages � ces pages. Pour envoyer des messages � une extension depuis une page�Web, sp�cifiez dans votre manifest.json les sites Web avec lesquels vous souhaitez communiquer � l'aide de la cl� du fichier�manifeste "externally_connectable". Exemple�:

manifest.json

"externally_connectable": {
  "matches": ["https://*.example.com/*"]
}

L'API de messagerie est ainsi expos�e sur toutes les pages correspondant aux formats d'URL que vous sp�cifiez. Le format d'URL doit contenir au moins un domaine�de�deuxi�me�niveau. Autrement dit, les formats de nom d'h�te tels que "*", "*.com", "*.co.uk" et "*.appspot.com" ne sont pas accept�s. � partir de Chrome 107, vous pouvez utiliser <all_urls> pour acc�der � tous les domaines. �tant donn� qu'elle affecte tous les h�tes, l'examen des extensions qui utilisent le Chrome Web�Store sur les extensions qui l'utilisent peut prendre plus de temps.

Utilisez les API runtime.sendMessage() ou runtime.connect() pour envoyer un message � une application ou � une extension sp�cifique. Exemple�:

webpage.js

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

Depuis votre extension, �coutez les messages des pages Web � l'aide des API runtime.onMessageExternal ou runtime.onConnectExternal, comme dans la messagerie multi-extension. Exemple�:

service-worker.js

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url === blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

Messagerie native

Les extensions peuvent �changer des messages avec des applications natives enregistr�es en tant qu'h�te�de�messagerie�native. Pour en savoir plus sur cette fonctionnalit�, consultez l'article Messages natifs.

Points � noter concernant la s�curit�

Voici quelques points � prendre en compte concernant la s�curit� des messages.

Les scripts de contenu sont moins fiables

Les scripts de contenu sont moins fiables que le service�worker d'extension. Par exemple, une page�Web malveillante peut compromettre le processus d'affichage qui ex�cute les scripts de contenu. Supposons que les messages d'un script de contenu aient �t� r�dig�s par un pirate�informatique et assurez-vous de valider et nettoyer toutes les entr�es. Supposons que des donn�es envoy�es au script de contenu puissent �tre transmises � la page�Web. Limitez le champ d'application des actions privil�gi�es pouvant �tre d�clench�es par des messages provenant de scripts de contenu.

Script intersites

Assurez-vous de prot�ger vos scripts contre les scripts intersites. Lorsque vous recevez des donn�es provenant d'une source non fiable, telle qu'une entr�e�utilisateur, d'autres sites Web via un script de contenu ou une API, �vitez de les interpr�ter comme du code HTML ou de l'utiliser d'une mani�re qui pourrait permettre l'ex�cution d'un code inattendu.

M�thodes plus s�res

Dans la mesure du possible, utilisez des API qui n'ex�cutent pas de scripts:

service-worker.js

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse doesn't evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});

service-worker.js

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});
M�thodes non s�curis�es

�vitez d'utiliser les m�thodes suivantes, qui rendent votre extension vuln�rable:

service-worker.js

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating a malicious script!
  var resp = eval(`(${response.farewell})`);
});

service-worker.js

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});