Scripts de conteúdo são arquivos executados no contexto de páginas da Web. Ao usar o Modelo de Objeto de Documento (DOM) padrão, eles podem ler detalhes das páginas da Web que o navegador visita, fazer mudanças nelas e transmitir informações para a extensão pai.
Entender os recursos do script de conteúdo
Os scripts de conteúdo podem acessar as APIs do Chrome usadas pela extensão pai trocando mensagens
com ela. Eles também podem acessar o URL do arquivo de uma extensão com
chrome.runtime.getURL()
e usar o resultado da mesma forma que outros URLs.
// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
Além disso, o script de conteúdo pode acessar diretamente as seguintes APIs do Chrome:
Os scripts de conteúdo não podem acessar outras APIs diretamente.
Trabalhe em mundos isolados
Os scripts de conteúdo vivem em um mundo isolado, permitindo que um script de conteúdo faça alterações em seu JavaScript sem conflito com a página ou com scripts de conteúdo adicionais.
Uma extensão pode ser executada em uma página da Web com um código semelhante ao exemplo abaixo.
<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>
Essa extensão pode injetar o seguinte script de conteúdo.
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
Os dois alertas vão aparecer se o botão for pressionado.
Mundos isolados não permitem que scripts de conteúdo, a extensão e a página da Web acessem variáveis ou funções criadas por outras pessoas. Isso também dá aos scripts de conteúdo a capacidade de ativar funcionalidade que não deve estar acessível na página da Web.
Inserir scripts
Os scripts de conteúdo podem ser injetados de forma programática ou declarativa.
Injetar programaticamente
Use a injeção programática para scripts de conteúdo que precisam ser executados em ocasiões específicas.
Para injetar um script de conteúdo programático, conceda a permissão activeTab no manifesto. Isso concede acesso seguro ao host do site ativo e acesso temporário à permissão tabs, permitindo que o script de conteúdo seja executado na guia ativa atual sem especificar permissões entre origens.
{
"name": "My extension",
...
"permissions": [
"activeTab"
],
...
}
Os scripts de conteúdo podem ser injetados como código.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "changeColor"){
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"'
});
}
});
Ou um arquivo inteiro pode ser injetado.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "runContentScript"){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
}
});
Injectar de forma declarativa
Use a injeção declarativa para scripts de conteúdo que precisam ser executados automaticamente em páginas específicas.
Os scripts injetados de forma declarativa são registrados no manifesto no campo "content_scripts"
.
Eles podem incluir arquivos JavaScript, CSS ou ambos. Todos os scripts de conteúdo de execução automática precisam especificar
padrões de correspondência.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
],
...
}
Nome | Tipo | Descrição |
---|---|---|
matches {: #matches } |
Obrigatório. Especifica em quais páginas esse script de conteúdo será injetado. Consulte Padrões de correspondência para mais detalhes sobre a sintaxe dessas strings e Padrões e globs de correspondência para informações sobre como excluir URLs. | |
css {: #css } |
Opcional. A lista de arquivos CSS que serão injetados nas páginas correspondentes. Eles são injetados na ordem em que aparecem nessa matriz, antes de qualquer DOM ser construído ou exibido para a página. | |
js {: #js } |
Opcional. A lista de arquivos JavaScript a serem injetados em páginas correspondentes. Eles são injetados na ordem em que aparecem nesta matriz. | |
match_about_blank {: #match_about_blank } |
booleano | Opcional. Define se o script precisa injetar em um frame about:blank em que o frame pai ou de abertura corresponde a um dos padrões declarados em matches . O padrão é false . |
Excluir correspondências e globs
É possível personalizar a correspondência especificada entre as páginas incluindo os seguintes campos no manifesto registro.
Nome | Tipo | Descrição |
---|---|---|
exclude_matches {: #exclude_matches } |
Opcional. Exclui páginas em que esse script de conteúdo seria injetado de outra forma. Consulte Padrões de correspondência para mais detalhes sobre a sintaxe dessas strings. | |
include_globs {: #include_globs } |
Opcional. Aplicado após matches para incluir apenas os URLs que também correspondem a esse glob. que serve para emular a palavra-chave @include "Greasemonkey". |
|
exclude_globs {: #exclude_globs } |
Opcional. Aplicado após matches para excluir URLs que correspondem a esse glob. Destina-se a emular a palavra-chave @exclude Greasemonkey. |
O script de conteúdo será injetado em uma página se o URL dela corresponder a qualquer padrão matches
e
include_globs
, desde que o URL não corresponda a um padrão exclude_matches
ou
exclude_globs
.
Como a propriedade matches
é obrigatória, exclude_matches
, include_globs
e exclude_globs
só pode ser usado para limitar as páginas que serão afetadas.
A extensão a seguir injetaria o script de conteúdo em http://www.nytimes.com/ health mas não http://www.nytimes.com/ negócios .
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
As propriedades glob seguem uma sintaxe diferente e mais flexível do que os padrões de correspondência. As strings glob aceitáveis são URLs que podem conter asteriscos "coringa" e pontos de interrogação. O asterisco * corresponde a qualquer string de qualquer tamanho, incluindo a string vazia, enquanto o ponto de interrogação ? corresponde a qualquer caractere único.
Por exemplo, a glob http:// ??? .example.com/foo/ * corresponde a qualquer um dos seguintes itens:
- http:// www .example.com/foo /bar
- http:// the .example.com/foo /
No entanto, ela não corresponde aos seguintes:
- http:// my .example.com/foo/bar
- http:// exemplo .com/foo/
- http://www.example.com/foo
Essa extensão injetaria o script de conteúdo em http:/www.nytimes.com/ arts /index.html e http://www.nytimes.com/ jobs /index.html, mas não em http://www.nytimes.com/ sports /index.html.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"include_globs": ["*nytimes.com/???s/*"],
"js": ["contentScript.js"]
}
],
...
}
Essa extensão injetaria o script de conteúdo em http:// history .nytimes.com e http://.nytimes.com/ history, mas não em 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"]
}
],
...
}
Uma, todas ou algumas delas podem ser incluídas para atingir o escopo correto.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Tempo de execução
Quando os arquivos JavaScript são injetados na página da Web, eles são controlados pelo campo run_at
. O
preferencial e o campo padrão é "document_idle"
, mas também pode ser especificado como "document_start"
ou
"document_end"
, se necessário.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Nome | Tipo | Descrição |
---|---|---|
document_idle {: #document_idle } |
string | Preferencial. Use "document_idle" sempre que possível.O navegador escolhe um horário para injetar scripts entre "document_end" e imediatamente após o disparo do evento windowonload . O momento exato da injeção depende da complexidade do documento e do tempo que ele leva para carregar, e é otimizado para a velocidade de carregamento da página.Os scripts de conteúdo executados em "document_idle" não precisam detectar o evento window.onload . Eles são executados com certeza após a conclusão do DOM. Se um script precisar ser executado após window.onload , a extensão poderá verificar se onload já foi acionado usando a propriedade document.readyState . |
document_start {: #document_start } |
string | Os scripts são injetados após os arquivos de css , mas antes que qualquer outro DOM seja construído ou que qualquer outro script seja executado. |
document_end {: #document_end } |
string | Os scripts são injetados imediatamente após o DOM ser concluído, mas antes que subrecursos como imagens e frames sejam carregados. |
Especificar frames
O campo "all_frames"
permite que a extensão especifique se os arquivos JavaScript e CSS devem ser
injetada em todos os frames que correspondem aos requisitos de URL especificados ou somente no frame superior de um
.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
Nome | Tipo | Descrição |
---|---|---|
all_frames {: #all_frames } |
booleano | Opcional. O padrão é false , o que significa que apenas o frame superior é correspondente.Se true for especificado, ele será injetado em todos os frames, mesmo que não seja o frame mais importante na guia. Cada frame é verificado de maneira independente para cumprir os requisitos de URL. Ele não será injetado em frames filhos se os requisitos de URL não forem atendidos. |
Comunicação com a página de incorporação
Embora os ambientes de execução dos scripts de conteúdo e as páginas que os hospedam estejam isolados entre si, elas compartilham o acesso ao DOM da página. Se a página quiser se comunicar com o script de conteúdo, ou com a extensão pelo script de conteúdo, ele deverá fazer isso pelo DOM compartilhado.
Um exemplo pode ser feito usando 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);
A página sem extensão, example.html, publica mensagens nela mesma. Essa mensagem é interceptada e inspecionada pelo script de conteúdo e depois postada no processo de extensão. Dessa forma, a página estabelece uma linha de comunicação com o processo de extensão. O contrário é possível de meios semelhantes.
Proteja-se
Embora os mundos isolados forneçam uma camada de proteção, o uso de scripts de conteúdo pode criar vulnerabilidades em uma extensão e na página da Web. Se o script de conteúdo receber conteúdo de um site separado, como fazer um XMLHttpRequest, tenha o cuidado de filtrar o conteúdo entre sites scripting antes da injeção. Comunique-se apenas por HTTPS para evitar "man-in-the-middle".
Filtre páginas da Web maliciosas. Por exemplo, os seguintes padrões são perigosos:
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);
Em vez disso, prefira APIs mais seguras que não executem 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);