�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 appelconnect()
entra�ne plusieurs ports du c�t� du r�cepteur et quedisconnect()
est appel� sur l'un de ces ports, l'�v�nementonDisconnect
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.
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; });
�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; });