Скрипты контента — это файлы, которые запускаются в контексте веб-страниц. Используя стандартную объектную модель документа (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://.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);