Skrypty treści to pliki uruchamiane w kontekście stron internetowych. Za pomocą standardowego Dokumentu Object Model (DOM), odczytuje szczegóły stron odwiedzanych przez przeglądarkę, i przekazują informacje do rozszerzenia nadrzędnego.
Omówienie możliwości skryptów treści
Skrypty treści mogą uzyskiwać dostęp do interfejsów API Chrome używanych przez ich rozszerzenie nadrzędne, wymieniając się z nim wiadomościami. Mogą też uzyskać dostęp do adresu URL pliku rozszerzenia,
chrome.runtime.getURL()
i użyj wyniku w taki sam sposób jak w przypadku innych adresów URL.
// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
Dodatkowo skrypt treści może bezpośrednio uzyskiwać dostęp do tych interfejsów API Chrome:
Skrypty treści nie mogą bezpośrednio uzyskiwać dostępu do innych interfejsów API.
Praca w odizolowanych światach
Skrypty dotyczące zawartości działają w odizolowanym środowisku, co pozwala im wprowadzać zmiany w swoim środowisku JavaScript bez konfliktu ze stroną lub dodatkowymi skryptami dotyczącymi zawartości.
Rozszerzenie może działać na stronie internetowej z kodem podobnym do tego w przykładzie poniżej.
<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>
Rozszerzenie może wstrzyknąć następujący skrypt treści.
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
Po naciśnięciu przycisku wyświetliły się oba alerty.
Izolowane światy nie zezwalają skryptom treści, rozszerzeniu ani stronie internetowej na dostęp zmiennych lub funkcji utworzonych przez inne jednostki. Daje to skryptom treści możliwość włączenia funkcji, które nie powinny być dostępne dla strony internetowej.
Wstrzykiwanie skryptów
Skrypty treści można wstrzykiwać programowo lub deklaratywnie.
Wstawianie za pomocą kodu
Korzystaj z automatycznego wstrzykiwania w przypadku skryptów treści, które muszą być uruchamiane przy określonych okazjach.
Aby wprowadzić skrypt automatycznej treści, w pliku manifestu przyznaj uprawnienie activeTab. Daje to bezpieczny dostęp do hosta aktywnej witryny i tymczasowy dostęp do uprawnień tabs, co umożliwia uruchamianie skryptu treści na bieżącej aktywnej karcie bez konieczności określania uprawnień między domenami.
{
"name": "My extension",
...
"permissions": [
"activeTab"
],
...
}
Skrypty treści można wstrzykiwać jako kod.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "changeColor"){
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="orange"'
});
}
});
Możesz też wstrzyknąć cały plik.
chrome.runtime.onMessage.addListener(
function(message, callback) {
if (message == "runContentScript"){
chrome.tabs.executeScript({
file: 'contentScript.js'
});
}
});
deklaratywnie,
Używaj wstrzykiwania deklaratywnego w przypadku skryptów treści, które powinny być automatycznie uruchamiane na określonych stronach.
Skrypty deklaratywne wstrzykiwane są rejestrowane w pliku manifestu w polu "content_scripts"
.
Mogą obejmować pliki JavaScript, pliki CSS lub oba te elementy. Wszystkie skrypty treści uruchamiane automatycznie muszą zawierać wzorce dopasowania.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
],
...
}
Nazwa | Typ | Opis |
---|---|---|
matches {: #matches } |
Wymagany. Określa, na których stronach ma być wstrzykiwany skrypt treści. Więcej informacji o składni tych ciągów znaków znajdziesz w artykule Wzorce dopasowania, a o wykluczaniu adresów URL – w artykule Wzorce dopasowania i globy. | |
css {: #css } |
Opcjonalnie. Lista plików CSS, które mają zostać wstrzyknięte do pasujących stron. Są one wstawiane w kolejności, w jakiej występują w tym tablicy, zanim DOM zostanie utworzony lub wyświetlony na stronie. | |
js {: #js } |
Opcjonalne. Lista plików JavaScript, które mają zostać wstrzyknięte na pasujące strony. Są one wstawiane w kolejności, w jakiej występują w tym tablicy. | |
match_about_blank {: #match_about_blank } |
wartość logiczna | Opcjonalne. Określa, czy skrypt powinien wstrzykiwać się do ramki about:blank , w której ramka nadrzędna lub otwierająca pasuje do jednego z wzorców zadeklarowanych w zasadzie matches . Domyślna wartość to false . |
Wyklucz dopasowania i glory
Dopasowywanie do określonej strony można dostosować, podając w pliku rejestracji pliku manifestu odpowiednie pola.
Nazwa | Typ | Opis |
---|---|---|
exclude_matches {: #exclude_matches } |
Opcjonalne. Wyklucza strony, na które skrypt treści miałby zostać wstrzyknięty. Więcej informacji o składni tych ciągów znajdziesz w artykule Wzorce dopasowania. | |
include_globs {: #include_globs } |
Opcjonalne. Stosowane po matches , aby uwzględnić tylko te adresy URL, które również pasują do tego glob. Służy do emulacji słowa kluczowego Greasemonkey @include . |
|
exclude_globs {: #exclude_globs } |
Opcjonalne. Stosowane po matches , aby wykluczyć adresy URL pasujące do tego glob. Służy do emulacji słowa kluczowego @exclude Greasemonkey. |
Skrypt treści zostanie wstrzyknięty na stronę, jeśli jej adres URL pasuje do dowolnego wzorca matches
i dowolnego wzorca include_globs
, o ile adres URL nie pasuje do wzorca exclude_matches
ani exclude_globs
.
Ponieważ wymagana jest właściwość matches
, exclude_matches
, include_globs
i exclude_globs
może jedynie służyć do ograniczenia stron, których on dotyczy.
Podane niżej rozszerzenie wstrzyknęło skrypt treści na stronie http://www.nytimes.com/ Health. ale nie w http://www.nytimes.com/ business .
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
Właściwości glob mają inną, bardziej elastyczną składnię niż wzorce dopasowania. Dopuszczalny wzorzec glob ciągi to adresy URL, które mogą zawierać symbole wieloznaczne gwiazdek i znaków zapytania. Gwiazdka * pasuje do dowolnego ciągu o dowolnej długości, w tym do pustego ciągu, podczas gdy znak zapytania ? dopasowuje dowolny pojedynczy znak.
Na przykład glob http:// ??? .example.com/foo/ * odpowiada dowolnym z tych elementów:
- http:// www .example.com/foo /bar
- http:// .example.com/foo /
Nie odpowiada jednak:
- http:// moj .example.com/foo/bar
- http:// example .com/foo/
- http://www.example.com/foo
To rozszerzenie wstrzykuje skrypt treści do http:/www.nytimes.com/arts/index.html i http://www.nytimes.com/jobs/index.html, ale nie do http://www.nytimes.com/sports/index.html.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"include_globs": ["*nytimes.com/???s/*"],
"js": ["contentScript.js"]
}
],
...
}
Rozszerzenie wstrzykiwało skrypt treści do http:// history.nytimes.com i http://.nytimes.com/history, ale nie do http://science.nytimes.com ani http://www.nytimes.com/science.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Aby uzyskać odpowiedni zakres, możesz uwzględnić jeden, wszystkie lub niektóre z nich.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Czas trwania
Wstrzykiwanie plików JavaScriptu na stronę internetową jest kontrolowane przez pole run_at
. Pole preferowane i domyślne to "document_idle"
, ale w razie potrzeby można też użyć wartości "document_start"
lub "document_end"
.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
Nazwa | Typ | Opis |
---|---|---|
document_idle {: #document_idle } |
ciąg znaków | Preferowana. W miarę możliwości używaj narzędzia "document_idle" .Przeglądarka wybiera czas między "document_end" a bezpośrednio po uruchomieniu zdarzenia windowonload . Dokładny moment wstrzyknięcia zależy od złożoności dokumentu i czasu jego wczytywania. Jest on optymalizowany pod kątem szybkości wczytywania strony.Skrypty treści uruchamiane w momencie "document_idle" nie muszą nasłuchiwać zdarzenia window.onload , ponieważ zawsze są wykonywane po zakończeniu wczytywania DOM. Jeśli koniecznie trzeba uruchomić skrypt po window.onload , rozszerzenie może sprawdzić, czy onload już nie został uruchomiony, za pomocą właściwości document.readyState . |
document_start {: #document_start } |
ciąg znaków | Skrypty są wstrzykiwane po plikach z css , ale przed utworzeniem innego DOM lub uruchomieniem innego skryptu. |
document_end {: #document_end } |
ciąg znaków | Skrypty są wstrzykiwane natychmiast po utworzeniu modelu DOM, ale przed załadowaniem zasobów podrzędnych, takich jak obrazy i ramki. |
Określanie ramek
Pole "all_frames"
umożliwia rozszerzeniu określenie, czy pliki JavaScript i CSS powinny być
jest wstrzyknięta we wszystkich ramkach spełniających określone wymagania dotyczące adresów URL lub tylko w najwyższej klatki w
.
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
Nazwa | Typ | Opis |
---|---|---|
all_frames {: #all_frames } |
wartość logiczna | Opcjonalne. Wartość domyślna to false , co oznacza, że dopasowywana jest tylko górna klatka.Jeśli określisz parametr true , zostanie on wstawiony do wszystkich klatek, nawet jeśli nie jest to najwyższa klatka na karcie. Każda ramka jest sprawdzana niezależnie pod kątem wymagań dotyczących adresu URL i nie zostanie wstawiona do ramek podrzędnych, jeśli te wymagania nie zostaną spełnione. |
Komunikacja ze stroną umieszczania
Mimo że środowiska wykonawcze skryptów treści i strony, na których je znajdują, są odizolowane uzyskują one dostęp do modelu DOM strony. Jeśli strona chce komunikować się z skrypt treści lub rozszerzenie w ramach skryptu dotyczącego treści, musi to robić za pośrednictwem wspólnego modelu DOM.
Przykładem może być 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);
Strona bez rozszerzeń (example.html) publikuje wiadomości w sobie. Skrypt treści przechwytuje i sprawdza tę wiadomość, a następnie przekazuje ją do procesu rozszerzenia. W ten sposób strona umożliwia komunikację w ramach procesu rozszerzania. Odwrotność jest możliwa dzięki w podobny sposób.
Dbaj o bezpieczeństwo
Izolowane światy zapewniają warstwę ochrony, ale skrypty treści mogą luki w zabezpieczeniach rozszerzenia i strony internetowej. Jeśli skrypt treści otrzymuje treści z tagu oddzielnej witryny, np. przy użyciu XMLHttpRequest, pamiętaj, aby filtrować treści z innych witryn skryptu, zanim go wstrzykniesz. Komunikacja tylko przez HTTPS, aby uniknąć ataków „man-in-the-middle”.
Pamiętaj, aby filtrować złośliwe strony internetowe. Niebezpieczne są na przykład te wzorce:
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);
Zamiast tego korzystaj z bezpieczniejszych interfejsów API, które nie uruchamiają skryptów:
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);