Скрипты контента

Скрипты контента — это файлы, которые запускаются в контексте веб-страниц. Используя стандартную объектную модель документа (DOM), они могут считывать информацию о веб-страницах, которые посещает браузер, вносить в них изменения и передавать информацию своему родительскому расширению.

Понимание возможностей сценария контента

Скрипты контента могут получать доступ к API Chrome, используемым их родительским расширением, путем обмена сообщениями с расширением. Они также могут получить доступ к URL-адресу файла расширения с помощью chrome.runtime.getURL() и использовать результат так же, как и другие URL-адреса.

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

Кроме того, скрипт контента может напрямую обращаться к следующим API Chrome:

Сценарии контента не могут напрямую обращаться к другим API.

Работа в изолированных мирах

Скрипты контента живут в изолированном мире, что позволяет скрипту контента вносить изменения в свою среду JavaScript, не вступая в конфликт со скриптами страницы или дополнительным контентом.

Расширение может работать на веб-странице с кодом, аналогичным приведенному ниже примеру.

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

Это расширение может внедрить следующий скрипт содержимого.

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

Оба предупреждения появятся, если кнопка будет нажата.

Изолированные миры не позволяют сценариям содержимого, расширениям и веб-страницам получать доступ к каким-либо переменным или функциям, созданным другими. Это также дает сценариям содержимого возможность включать функции, которые не должны быть доступны на веб-странице.

Внедрить скрипты

Сценарии содержимого можно внедрять программно или декларативно .

Внедрить программно

Используйте программное внедрение для сценариев контента, которые необходимо запускать в определенных случаях.

Чтобы внедрить сценарий программного контента, предоставьте разрешение activeTab в манифесте. Это предоставляет безопасный доступ к хосту активного сайта и временный доступ к разрешению вкладок , позволяя сценарию содержимого запускаться на текущей активной вкладке без указания разрешений между источниками .

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

Сценарии контента можно внедрить в виде кода.

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

Или можно внедрить весь файл.

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

Внедрить декларативно

Используйте декларативное внедрение для сценариев контента, которые должны автоматически запускаться на определенных страницах.

Декларативно внедренные скрипты регистрируются в манифесте в поле "content_scripts" . Они могут включать файлы JavaScript, файлы CSS или и то, и другое. Все сценарии автозапуска содержимого должны указывать шаблоны соответствия .

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Имя Тип Описание
matches {: #matches } массив строк Необходимый. Указывает, на какие страницы будет внедрен этот скрипт содержимого. Дополнительные сведения о синтаксисе этих строк см. в разделе «Шаблоны сопоставления» , а также «Шаблоны сопоставления и глобусы» для получения информации о том, как исключить URL-адреса.
css {: #css } массив строк Необязательный. Список файлов CSS, которые будут вставлены в соответствующие страницы. Они вводятся в том порядке, в котором они появляются в этом массиве, до того, как будет создан или отображен какой-либо DOM для страницы.
js {: #js } массив строк Необязательный. Список файлов JavaScript, которые будут внедрены на соответствующие страницы. Они вводятся в том порядке, в котором они появляются в этом массиве.
match_about_blank {: #match_about_blank } логическое значение Необязательный. Должен ли сценарий внедриться в кадр about:blank , где родительский или открывающий кадр соответствует одному из шаблонов, объявленных в matches . По умолчанию установлено значение false .

Исключить совпадения и глобусы

Указанное соответствие страниц можно настроить, включив следующие поля в регистрацию манифеста.

Имя Тип Описание
exclude_matches {: #exclude_matches } массив строк Необязательный. Исключает страницы, в которые в противном случае был бы внедрен этот сценарий содержимого. Дополнительные сведения о синтаксисе этих строк см. в разделе «Шаблоны совпадений» .
include_globs {: #include_globs } массив строк Необязательный. Применяется после matches , чтобы включать только те URL-адреса, которые также соответствуют этому шаблону. Предназначен для эмуляции ключевого слова @include Greasemonkey.
exclude_globs {: #exclude_globs } массив строк Необязательный. Применяется после matches , чтобы исключить URL-адреса, соответствующие этому шаблону. Предназначен для эмуляции ключевого слова @exclude Greasemonkey.

Сценарий содержимого будет внедрен на страницу, если его URL-адрес соответствует любому шаблону matches и любому шаблону include_globs , если URL-адрес также не соответствует шаблону exclude_matches или exclude_globs .

Поскольку свойство matches является обязательным, exclude_matches , include_globs и exclude_globs можно использовать только для ограничения того, какие страницы будут затронуты.

Следующее расширение внедрит сценарий содержимого в http://www.nytimes.com/ health , но не в http://www.nytimes.com/ business .

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

Свойства Glob имеют другой, более гибкий синтаксис, чем шаблоны сопоставления . Приемлемые glob-строки — это URL-адреса, которые могут содержать подстановочные знаки и звездочки. Звездочка * соответствует любой строке любой длины, включая пустую строку, а вопросительный знак ? соответствует любому отдельному символу.

Например, глоб http:// ??? .example.com/foo/ * соответствует любому из следующих значений:

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

Однако он не соответствует следующему:

  • http://мой .example.com/foo/bar
  • http:// пример .com/foo/
  • http://www.example.com/foo

Это расширение будет вставлять сценарий содержимого в http:/www.nytimes.com/arts/index.html и http://www.nytimes.com/jobs/index.html , но не в http://www.nytimes.com. /спорт/index.html .

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

Это расширение будет вставлять сценарий содержимого в http:// History .nytimes.com и http://.nytimes.com/ History , но не в http:// science .nytimes.com или http://www.nytimes.com. / наука .

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

Для достижения правильной области действия можно включить один, все или некоторые из них.

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

Время выполнения

Время внедрения файлов JavaScript на веб-страницу контролируется полем run_at . Предпочтительным полем по умолчанию является "document_idle" , но при необходимости его также можно указать как "document_start" или "document_end" .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Имя Тип Описание
document_idle {: #document_idle } нить Предпочтительно. Используйте "document_idle" , когда это возможно.

Браузер выбирает время для внедрения скриптов между "document_end" и сразу после срабатывания события windowonload . Точный момент внедрения зависит от того, насколько сложен документ и сколько времени занимает его загрузка, и оптимизирован для скорости загрузки страницы.

Сценариям содержимого, работающим в "document_idle" не нужно прослушивать событие window.onload , они гарантированно запускаются после завершения DOM. Если сценарий обязательно должен быть запущен после window.onload , расширение может проверить, запущена ли уже onload , используя свойство document.readyState .
document_start {: #document_start } нить Скрипты вводятся после любых файлов из css , но до создания любого другого DOM или запуска любого другого скрипта.
document_end {: #document_end } нить Скрипты внедряются сразу после завершения DOM, но до загрузки подресурсов, таких как изображения и фреймы.

Укажите рамки

Поле "all_frames" позволяет расширению указать, следует ли вставлять файлы JavaScript и CSS во все кадры, соответствующие указанным требованиям URL-адреса, или только в самый верхний кадр на вкладке.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Имя Тип Описание
all_frames {: #all_frames } логическое значение Необязательный. По умолчанию установлено значение false , что означает, что сопоставляется только верхний кадр.

Если указано true , он будет вставлен во все кадры, даже если этот кадр не является самым верхним кадром на вкладке. Каждый кадр проверяется независимо на соответствие требованиям URL-адреса. Он не будет вставляться в дочерние кадры, если требования URL-адреса не выполняются.

Связь со страницей встраивания

Хотя среды выполнения сценариев контента и страниц, на которых они размещены, изолированы друг от друга, они имеют общий доступ к DOM страницы. Если страница желает взаимодействовать со сценарием содержимого или с расширением через сценарий содержимого, она должна делать это через общий DOM.

Пример можно реализовать с помощью 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);

Страница без расширения, example.html, отправляет сообщения самому себе. Это сообщение перехватывается и проверяется сценарием содержимого, а затем отправляется в процесс расширения. Таким образом, страница устанавливает канал связи с процессом расширения. Обратное возможно с помощью аналогичных средств.

Оставайтесь в безопасности

Хотя изолированные миры обеспечивают уровень защиты, использование сценариев содержимого может создать уязвимости в расширении и веб-странице. Если сценарий контента получает контент с отдельного веб-сайта, например, создавая XMLHttpRequest , будьте осторожны, чтобы фильтровать атаки с использованием межсайтовых сценариев контента перед его внедрением. Общайтесь только через HTTPS, чтобы избежать атак «человек посередине» .

Обязательно отфильтруйте вредоносные веб-страницы. Например, опасны следующие шаблоны:

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

Вместо этого отдайте предпочтение более безопасным API, которые не запускают скрипты:

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