Secuencias de comandos de contenido

Las secuencias de comandos de contenido son archivos que se ejecutan en el contexto de las páginas web. Mediante el uso del modelo de objetos del Document Object (DOM) estándar, pueden leer detalles de las páginas web que visita el navegador, realizar cambios en ellas y pasar información a su extensión superior.

Comprende las capacidades de las secuencias de comandos de contenido

Las secuencias de comandos de contenido pueden acceder a las APIs de Chrome que usa su extensión superior intercambiando mensajes con la extensión. También pueden acceder a la URL del archivo de una extensión con chrome.runtime.getURL() y usar el resultado de la misma manera que otras URLs.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

Además, las secuencias de comandos de contenido pueden acceder directamente a las siguientes APIs de Chrome:

Las secuencias de comandos de contenido no pueden acceder directamente a otras APIs.

Trabaja en mundos aislados

Las secuencias de comandos de contenido residen en un mundo aislado, lo que permite que una secuencia de comandos de contenido realice cambios en su entorno de JavaScript sin entrar en conflicto con la página ni con secuencias de comandos de contenido adicionales.

Una extensión puede ejecutarse en una página web con un código similar al del siguiente ejemplo.

<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>

Esa extensión podría insertar la siguiente secuencia de comandos de contenido.

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
  alert(greeting + button.person_name + ".");
}, false);

Ambas alertas aparecerían si se presionara el botón.

Los mundos aislados no permiten que las secuencias de comandos de contenido, la extensión y la página web accedan a ninguna variable o función creada por los demás. Esto también les da a las secuencias de comandos de contenido la capacidad de habilitar funciones a las que no se debe acceder a la página web.

Inserta secuencias de comandos

Las secuencias de comandos de contenido se pueden insertar de forma programática o declarativa.

Inserta de forma programática

Usa la inserción programática para las secuencias de comandos de contenido que deben ejecutarse en ocasiones específicas.

Para insertar una secuencia de comandos de contenido programática, proporciona el permiso activeTab en el manifiesto. Esto otorga acceso seguro al host del sitio activo y acceso temporal al permiso de pestañas, lo que permite que la secuencia de comandos de contenido se ejecute en la pestaña activa actual sin especificar permisos de origen cruzado.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

Las secuencias de comandos de contenido se pueden insertar como código.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

También se puede insertar un archivo completo.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "runContentScript"){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
  });

Inserta de forma declarativa

Usa la inserción declarativa para las secuencias de comandos de contenido que deben ejecutarse automáticamente en las páginas especificadas.

Las secuencias de comandos insertadas de forma declarativa se registran en el manifiesto en el campo "content_scripts". Pueden incluir archivos JavaScript, archivos CSS o ambos. Todas las secuencias de comandos de contenido de ejecución automática deben especificar patrones de coincidencia.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Nombre Tipo Descripción
matches {: #matches } matriz de cadenas Obligatorio. Especifica en qué páginas se insertará esta secuencia de comandos de contenido. Consulta Patrones de coincidencia para obtener más detalles sobre la sintaxis de estas cadenas y Patrones de coincidencia y globs para obtener información sobre cómo excluir URLs.
css {: #css } matriz de cadenas Opcional. Es la lista de archivos CSS que se insertarán en las páginas coincidentes. Se insertan en el orden en que aparecen en este array, antes de que se construya o muestre cualquier DOM para la página.
js {: #js } matriz de cadenas Opcional. Es la lista de archivos JavaScript que se insertarán en las páginas coincidentes. Se insertan en el orden en que aparecen en este array.
match_about_blank {: #match_about_blank } booleano Opcional. Indica si la secuencia de comandos debe insertarse en un marco about:blank en el que el marco superior o de apertura coincida con uno de los patrones declarados en matches. El valor predeterminado es false.

Excluye coincidencias y globs

La coincidencia de páginas especificadas se puede personalizar incluyendo los siguientes campos en el registro del manifiesto.

Nombre Tipo Descripción
exclude_matches {: #exclude_matches } matriz de cadenas Opcional. Excluye las páginas en las que, de lo contrario, se insertaría esta secuencia de comandos de contenido. Consulta Patrones de coincidencia para obtener más detalles sobre la sintaxis de estas cadenas.
include_globs {: #include_globs } matriz de cadenas Opcional. Se aplica después de matches para incluir solo las URLs que también coincidan con este glob. Su objetivo es emular la palabra clave @include de Greasemonkey.
exclude_globs {: #exclude_globs } matriz de cadenas Opcional. Se aplica después de matches para excluir las URLs que coincidan con este glob. Su objetivo es emular la palabra clave @exclude de Greasemonkey.

La secuencia de comandos de contenido se insertará en una página si su URL coincide con algún patrón matches y con algún include_globs patrón, siempre que la URL tampoco coincida con un exclude_matches o exclude_globs patrón.

Debido a que la propiedad matches es obligatoria, exclude_matches, include_globs y exclude_globs solo se pueden usar para limitar qué páginas se verán afectadas.

La siguiente extensión insertaría la secuencia de comandos de contenido en http://www.nytimes.com/ health , pero no en http://www.nytimes.com/ business .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Las propiedades de glob siguen una sintaxis diferente y más flexible que los patrones de coincidencia. Las cadenas de glob aceptables son URLs que pueden contener asteriscos y signos de interrogación "comodín". El asterisco * coincide con cualquier cadena de cualquier longitud, incluida la cadena vacía, mientras que el signo de interrogación ? coincide con cualquier carácter único.

Por ejemplo, el glob http:// ??? .example.com/foo/ * coincide con cualquiera de los siguientes:

  • http:// www .example.com/foo /bar
  • http:// the .example.com/foo /

Sin embargo, no coincide con lo siguiente:

  • http:// my .example.com/foo/bar
  • http:// example .com/foo/
  • http://www.example.com/foo

Esta extensión insertaría la secuencia de comandos de contenido en http:/www.nytimes.com/ arts /index.html y http://www.nytimes.com/ jobs /index.html , pero no en http://www.nytimes.com/ sports/index.html.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Esta extensión insertaría la secuencia de comandos de contenido en http:// history .nytimes.com y http://.nytimes.com/ history , pero no en http:// science .nytimes.com ni http://www.nytimes.com/ science .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Se puede incluir uno, todos o algunos de estos para lograr el alcance correcto.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Tiempo de ejecución

El campo run_at controla cuándo se insertan los archivos JavaScript en la página web. El campo preferido y predeterminado es "document_idle", pero también se puede especificar como "document_start" o "document_end" si es necesario.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Nombre Tipo Descripción
document_idle {: #document_idle } string Preferido. Usa "document_idle" siempre que sea posible.

El navegador elige un momento para insertar secuencias de comandos entre "document_end" e inmediatamente después de que se active el evento windowonload. El momento exacto de la inserción depende de la complejidad del documento y del tiempo que tarda en cargarse, y se optimiza para la velocidad de carga de la página.

Las secuencias de comandos de contenido que se ejecutan en "document_idle" no necesitan escuchar el evento window.onload. Se garantiza que se ejecutarán después de que se complete el DOM. Si una secuencia de comandos definitivamente necesita ejecutarse después de window.onload, la extensión puede verificar si onload ya se activó con la propiedad document.readyState.
document_start {: #document_start } string Las secuencias de comandos se insertan después de cualquier archivo de css, pero antes de que se construya cualquier otro DOM o se ejecute cualquier otra secuencia de comandos.
document_end {: #document_end } string Las secuencias de comandos se insertan inmediatamente después de que se completa el DOM, pero antes de que se carguen los subrecursos, como imágenes y marcos.

Especifica marcos

El campo "all_frames" permite que la extensión especifique si los archivos JavaScript y CSS se deben insertar en todos los marcos que coincidan con los requisitos de las URLs especificados o solo en el marco superior de una pestaña.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Nombre Tipo Descripción
all_frames {: #all_frames } booleano Opcional. El valor predeterminado es false, lo que significa que solo coincide el marco superior.

Si se especifica true, se insertará en todos los marcos, incluso si el marco no es el marco superior de la pestaña. Cada marco se verifica de forma independiente para los requisitos de las URLs. No se insertará en los marcos secundarios si no se cumplen los requisitos de las URLs.

Comunicación con la página de incorporación

Aunque los entornos de ejecución de las secuencias de comandos de contenido y las páginas que las alojan están aislados entre sí, comparten el acceso al DOM de la página. Si la página desea comunicarse con la secuencia de comandos de contenido o con la extensión a través de la secuencia de comandos de contenido, debe hacerlo a través del DOM compartido.

Se puede lograr un ejemplo con 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 página que no es de extensión, example.html, se publica mensajes a sí misma. La secuencia de comandos de contenido intercepta e inspecciona este mensaje y, luego, lo publica en el proceso de extensión. De esta manera, la página establece una línea de comunicación con el proceso de extensión. Lo contrario es posible a través de medios similares.

Mantente protegido

Si bien los mundos aislados proporcionan una capa de protección, el uso de secuencias de comandos de contenido puede crear vulnerabilidades en una extensión y en la página web. Si la secuencia de comandos de contenido recibe contenido de un sitio web independiente, como realizar una XMLHttpRequest, ten cuidado de filtrar los ataques de secuencias de comandos de sitios cruzados antes de insertarlo. Comunícate solo a través de HTTPS para evitar "man-in-the-middle" ataques.

Asegúrate de filtrar las páginas web maliciosas. Por ejemplo, los siguientes patrones son peligrosos:

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);

En su lugar, prefiere APIs más seguras que no ejecuten secuencias de comandos:

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);