Les scripts de contenu sont des fichiers exécutés dans le contexte de pages Web. En utilisant le modèle objet de document (DOM) standard, elles peuvent lire les détails des pages Web que le navigateur consulte, les modifier et transmettre des informations à leur extension parente.
Comprendre les fonctionnalités de script de contenu
Les scripts de contenu peuvent accéder aux API Chrome utilisées par leur extension parente en échangeant des messages avec l'extension. Ils peuvent également accéder à l'URL du fichier d'une extension avec chrome.runtime.getURL()
et utiliser le résultat de la même manière que les autres URL.
// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
De plus, le script de contenu peut accéder directement aux API Chrome suivantes:
Les scripts de contenu ne peuvent pas accéder directement à d'autres API.
Travailler dans des mondes isolés
Les scripts de contenu vivent dans un monde isolé, ce qui leur permet de modifier leur environnement JavaScript sans entrer en conflit avec la page ou d'autres scripts de contenu.
Une extension peut s'exécuter dans une page Web avec un code similaire à l'exemple ci-dessous.
<html>
<button id="mybutton">click me</button>
<script>
var greeting = "hello, ";
var button = document.getElementById("mybutton");
button.person_name = "Bob";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
</script>
</html>
Cette extension peut injecter le script de contenu suivant.
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
Les deux alertes s'affichent si l'utilisateur appuie sur le bouton.
Les mondes isolés ne permettent pas aux scripts de contenu, à l'extension et à la page Web d'accéder des variables ou des fonctions créées par les autres. Cela permet aussi aux scripts de contenu d'activer des fonctionnalités qui ne doivent pas être accessibles à la page Web.
Injecter des scripts
Les scripts de contenu peuvent être injectés de manière programmatique ou déclarative.
Injecter par programmation
Utilisez l'injection programmatique pour les scripts de contenu qui doivent s'exécuter à des occasions spécifiques.
Pour injecter un script de contenu programmatique, fournissez l'autorisation activeTab dans le fichier manifeste. Cela permet d'accorder un accès sécurisé à l'hôte du site actif et un accès temporaire à l'autorisation tabs, ce qui permet au script de contenu d'être exécuté dans l'onglet actif actuel sans spécifier d'autorisations multi-origines.
{
"name": "My extension",
...
"permissions": [
"activeTab"
],
...
}
Les scripts de contenu peuvent être injectés sous forme de code.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "changeColor"){
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"'
});
}
});
Un fichier entier peut également être injecté.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "runContentScript"){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
}
});
Injecter de manière déclarative
Utilisez l'injection déclarative pour les scripts de contenu qui doivent être exécutés automatiquement sur des pages spécifiées.
Les scripts injectés de manière déclarative sont enregistrés dans le fichier manifeste sous le champ "content_scripts"
.
Ils peuvent inclure des fichiers JavaScript, des fichiers CSS ou les deux. Tous les scripts de contenu exécutés automatiquement doivent spécifier
modèles de correspondance.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
],
...
}
Nom | Type | Description |
---|---|---|
matches {: #matches } |
Obligatoire. Spécifie les pages dans lesquelles ce script de contenu sera injecté. Consultez Formats de correspondance pour plus de détails sur la syntaxe de ces chaînes et Modèles de correspondance et globs pour savoir comment exclure des URL. | |
css {: #css } |
Facultatif. Liste des fichiers CSS à injecter dans les pages correspondantes. Ils sont injectés dans l'ordre dans lequel ils apparaissent dans ce tableau, avant qu'un DOM ne soit construit ou affiché pour la page. | |
js {: #js } |
Facultatif. Liste des fichiers JavaScript à injecter dans les pages correspondantes. Celles-ci sont injectées dans l'ordre dans lequel elles apparaissent dans le tableau. | |
match_about_blank {: #match_about_blank } |
booléen | Facultatif. Indique si le script doit être injecté dans un frame about:blank où le frame parent ou d'ouverture correspond à l'un des modèles déclarés dans matches . La valeur par défaut est false . |
Exclure les correspondances et les expressions régulières
Vous pouvez personnaliser la correspondance de page spécifiée en incluant les champs suivants dans l'enregistrement du fichier manifeste.
Nom | Type | Description |
---|---|---|
exclude_matches {: #exclude_matches } |
Facultatif. Exclut les pages dans lesquelles ce script de contenu serait autrement injecté. Pour en savoir plus sur la syntaxe de ces chaînes, consultez Formats de correspondance. | |
include_globs {: #include_globs } |
Facultatif. Appliqué après matches pour n'inclure que les URL qui correspondent également à ce glob. Destiné à émuler le mot clé Greasemonkey @include . |
|
exclude_globs {: #exclude_globs } |
Facultatif. Appliqué après le matches pour exclure les URL correspondant à ce plan global. Destiné à émuler le mot clé Greasemonkey @exclude . |
Le script de contenu est injecté dans une page si son URL correspond à un format matches
et à un format include_globs
, à condition que l'URL ne corresponde pas également à un format exclude_matches
ou exclude_globs
.
Étant donné que la propriété matches
est obligatoire, exclude_matches
, include_globs
et exclude_globs
ne peuvent être utilisés que pour limiter les pages concernées.
L'extension suivante injecte le script de contenu dans http://www.nytimes.com/ health. mais pas sur http://www.lemonde.fr/ business .
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
Les propriétés Glob suivent une syntaxe différente et plus flexible que celle des motifs de correspondance. Les chaînes glob acceptées sont des URL pouvant contenir des astérisques et des points d'interrogation "génériques". L'astérisque * correspond à n'importe quelle chaîne de n'importe quelle longueur, y compris la chaîne vide, tandis que le point d'interrogation ? correspond à n'importe quel caractère unique.
Par exemple, le tag glob http:// ??? .example.com/foo/ * correspond à l'un des éléments suivants:
- http:// www .example.com/foo /bar
- http:// .example.com/foo /
Toutefois, il ne correspond pas aux éléments suivants:
- http:// mon .example.com/foo/bar
- http:// exemple .com/foo/
- http://www.example.com/foo
Cette extension injecterait le script de contenu dans http:/www.nytimes.com/ arts /index.html et http://www.nytimes.com/ jobs /index.html, mais pas dans http://www.nytimes.com/ sports /index.html.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"include_globs": ["*nytimes.com/???s/*"],
"js": ["contentScript.js"]
}
],
...
}
Cette extension injecte le script de contenu dans http:// history .nytimes.com et http://.nytimes.com/ history, mais pas dans http:// science .nytimes.com ou http://www.nytimes.com/ science
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Vous pouvez inclure une, toutes ou certaines d'entre elles pour atteindre le champ d'application approprié.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Durée de diffusion
Le moment où les fichiers JavaScript sont injectés dans la page Web est contrôlé par le champ run_at
. Le champ préféré et par défaut est "document_idle"
, mais il peut également être spécifié comme "document_start"
ou "document_end"
si nécessaire.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Nom | Type | Description |
---|---|---|
document_idle {: #document_idle } |
chaîne | Recommandé. Utilisez "document_idle" dans la mesure du possible.Le navigateur choisit un moment pour injecter des scripts entre "document_end" et immédiatement après le déclenchement de l'événement windowonload . Le moment exact de l'injection dépend de la complexité du document et de la durée de chargement. Il est optimisé pour la vitesse de chargement des pages.Les scripts de contenu exécutés à "document_idle" n'ont pas besoin d'écouter l'événement window.onload . Leur exécution est garantie une fois le DOM terminé. Si un script doit absolument s'exécuter après window.onload , l'extension peut vérifier si onload s'est déjà déclenché à l'aide de la propriété document.readyState . |
document_start {: #document_start } |
chaîne | Les scripts sont injectés après les fichiers de css , mais avant la création de tout autre DOM ou l'exécution de tout autre script. |
document_end {: #document_end } |
chaîne | Les scripts sont injectés immédiatement après la finalisation du DOM, mais avant le chargement des sous-ressources telles que les images et les cadres. |
Spécifier des cadres
Le champ "all_frames"
permet à l'extension de spécifier si les fichiers JavaScript et CSS doivent être injectés dans tous les cadres correspondant aux exigences d'URL spécifiées ou uniquement dans le cadre le plus élevé d'un onglet.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
Nom | Type | Description |
---|---|---|
all_frames {: #all_frames } |
booléen | Facultatif. La valeur par défaut est false , ce qui signifie que seul le frame supérieur est mis en correspondance.Si vous spécifiez true , l'injection s'effectue dans tous les frames, même s'ils ne sont pas le frame supérieur de l'onglet. Les exigences concernant les URL sont vérifiées indépendamment pour chaque frame. Elles ne seront pas injectées dans les frames enfants si elles ne sont pas respectées. |
Communication avec la page d'intégration
Bien que les environnements d'exécution des scripts de contenu et les pages qui les hébergent soient isolés l'un de l'autre, ils partagent l'accès au DOM de la page. Si la page souhaite communiquer avec script de contenu, ou avec l'extension via le script de contenu, il doit le faire par le biais du DOM partagé.
Vous pouvez par exemple utiliser window.postMessage
:
var port = chrome.runtime.connect();
window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
console.log("Content script received: " + event.data.text);
port.postMessage(event.data.text);
}
}, false);
document.getElementById("theButton").addEventListener("click",
function() {
window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);
La page sans extension, example.html, publie des messages sur elle-même. Ce message est intercepté et inspecté par le script de contenu, puis publié dans le processus d'extension. De cette façon, la page établit une ligne de communication avec le processus de prolongation. L'inverse est possible par des moyens similaires.
Bénéficiez d'une sécurité optimale
Alors que les mondes isolés fournissent une couche de protection, l'utilisation de scripts de contenu peut créer les vulnérabilités dans une extension et la page Web. Si le script de contenu reçoit du contenu à partir d'un autre site Web, par exemple en créant une XMLHttpRequest, veillez à filtrer les attaques de scripts intersites avant de les injecter. Ne communiquez que via HTTPS pour éviter les attaques man-in-the-middle.
Veillez à filtrer les pages Web malveillantes. Par exemple, les modèles suivants sont dangereux :
var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);
Privilégiez plutôt des API plus sûres qui n'exécutent pas de scripts :
var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
animate(elmt_id);
}, 200);