Skrypty treści

Skrypty treści to pliki, które są uruchamiane w kontekście stron internetowych. Za pomocą standardowego obiektowego modelu dokumentu (DOM) mogą odczytywać szczegóły stron odwiedzanych przez przeglądarkę, wprowadzać na nich zmiany i przekazywać informacje do rozszerzenia nadrzędnego.

Informacje o możliwościach skryptów treści

Skrypty treści mogą uzyskiwać dostęp do interfejsów API Chrome używanych przez rozszerzenie nadrzędne, wymieniając wiadomości z rozszerzeniem. Mogą też uzyskać dostęp do adresu URL pliku rozszerzenia za pomocą chrome.runtime.getURL() i korzystać z tego samego wyniku tak samo jak w innych adresach 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 ma bezpośredni dostęp do tych interfejsów API Chrome:

Skrypty treści nie mają bezpośredniego dostępu do innych interfejsów API.

Praca w odizolowanym świecie

Skrypty treści działają w izolowanym świecie, co umożliwia skryptowi treści wprowadzanie zmian w środowisku JavaScriptu bez konfliktów ze stroną lub dodatkowymi skryptami treś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>

To rozszerzenie może wstrzyknąć poniższy 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 pojawią się oba alerty.

Odizolowane światy nie zezwalają skryptom treści, rozszerzeniu ani stronie internetowej na dostęp do żadnych zmiennych lub funkcji tworzonych przez inne strony. Umożliwia to również skryptom treści włączenie funkcji, które nie powinny być dostępne na stronie internetowej.

Wstrzyknij skrypty

Skrypty treści można wstrzykiwać programowo lub deklaratywnie.

Wstawiaj automatycznie

Używaj wstrzykiwania automatycznego w przypadku skryptów treści, które mają być uruchamiane w określonych sytuacjach.

Aby wstrzyknąć skrypt treści zautomatyzowanej, podaj w pliku manifestu uprawnienie activeTab. Daje to bezpieczny dostęp do hosta aktywnej witryny i tymczasowy dostęp do uprawnień kart, co umożliwia uruchamianie skryptu zawartości w bieżącej aktywnej karcie bez określania uprawnień z innych domen.

{
  "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żna też wstrzykiwać cały plik.

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

Wstrzykiwać deklaratywnie

Użyj wstrzykiwania deklaratywnego w przypadku skryptów treści, które powinny być uruchamiane automatycznie na określonych stronach.

Skrypty wstrzyknięte deklaratywnie są zarejestrowane w pliku manifestu w polu "content_scripts". Mogą one obejmować pliki JavaScript, pliki CSS lub oba te elementy. Wszystkie automatycznie uruchamiane skrypty treści muszą określać wzorce dopasowania.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Nazwa Typ Opis
matches {: #matches } tablica ciągów znaków Wymagane. Określa, na których stronach będzie wstrzyknięty ten skrypt treści. Więcej informacji o składni tych ciągów tekstowych znajdziesz w sekcji Wzorce dopasowania, a w sekcji Wzorce dopasowania i obiektów glob dowiesz się, jak wykluczać adresy URL.
css {: #css } tablica ciągów znaków Opcjonalne. Lista plików CSS, które mają zostać wstawione na pasujących stronach. Są one wstrzykiwane w kolejności, w jakiej pojawiają się w tej tablicy, przed utworzeniem lub wyświetleniem DOM dla strony.
js {: #js } tablica ciągów znaków Opcjonalne. Lista plików JavaScript, które mają zostać wstawione na pasujących stronach. Są one wstrzykiwane w kolejności, w jakiej występują w tej tablicy.
match_about_blank {: #match_about_blank } boolean Opcjonalne. Określa, czy skrypt powinien wstrzyknąć w ramkę about:blank, w której ramka nadrzędna lub otwierająca odpowiada jednemu z wzorców zadeklarowanych w zasadzie matches. Domyślna wartość to false.

Wyklucz dopasowania i obiekty globs

Określone dopasowanie stron można dostosować, uwzględniając w rejestracji manifestu poniższe pola.

Nazwa Typ Opis
exclude_matches {: #excl_matches } tablica ciągów znaków Opcjonalne. Wyklucza strony, do których w innym przypadku zostałby wstrzyknięty ten skrypt treści. Więcej informacji o składni tych ciągów tekstowych znajdziesz w sekcji Wzorce dopasowania.
include_globs {: #include_globs } tablica ciągów znaków Opcjonalne. Stosowane po matches, aby uwzględniać tylko te adresy URL, które również pasują do tego wzorca glob. Ma emulować słowo kluczowe @include Greasemonkey.
exclude_globs {: #excl_globs } tablica ciągów znaków Opcjonalne. Stosowane po matches w celu wykluczania adresów URL pasujących do tego wzorca glob. Ma emulować słowo kluczowe @excludeGreasemonkey.

Skrypt treści zostanie wstawiony na stronie, jeśli jej adres URL pasuje do dowolnego wzorca matches i dowolnego wzorca include_globs, o ile adres URL nie jest też zgodny ze wzorcem exclude_matches ani exclude_globs.

Właściwość matches jest wymagana, więc za pomocą właściwości exclude_matches, include_globs i exclude_globs można tylko ograniczyć zakres stron, których dotyczy problem.

To rozszerzenie wstrzykuje skrypt treści na stronie http://www.nytimes.com/ health, ale nie na stronie http://www.nytimes.com/ business .

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

Właściwości kuli ziemskiej mają inną, bardziej elastyczną składnię niż wzorce dopasowania. Dopuszczalne ciągi znaków glob to adresy URL, które mogą zawierać symbole wieloznaczne i znaki zapytania. Gwiazdka * pasuje do dowolnego ciągu o dowolnej długości, w tym do pustego ciągu znaków, a do znaku zapytania ? pasuje do dowolnego pojedynczego znaku.

Na przykład adres glob http:// ??? .example.com/foo/ * odpowiada dowolnym z tych elementów:

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

Nie jest on jednak zgodny z tymi zasadami:

  • http:// mój .example.com/foo/bar
  • http:// example .com/foo/
  • http://www.example.com/foo

To rozszerzenie wstrzykuje skrypt treści do stron http:/www.nytimes.com/ arts /index.html i http://www.nytimes.com/ jobs /index.html, ale nie do witryny http://www.nytimes.com/ sports /index.html.

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

Spowoduje to wstawienie skryptu dotyczącego treści do http:// historii .nytimes.com czy http://.nytimes.com/ historii, ale nie do http:// science .nytimes.com czy http://www.nytimes.com/ science .

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

Aby uzyskać prawidłowy zakres, można uwzględnić jedną, 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

Umieszczanie plików JavaScript na stronie internetowej jest kontrolowane przez pole run_at. Wybrane i domyślne pole to "document_idle", ale w razie potrzeby można je też określić jako "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. Gdy tylko jest to możliwe, używaj metody "document_idle".

Przeglądarka wybiera czas wstrzyknięcia skryptów między "document_end" a bezpośrednio po uruchomieniu zdarzenia windowonload. Dokładny moment wstrzyknięcia zależy od tego, jak złożony jest dokument i jak długo trwa jego wczytywanie. Jest zoptymalizowany pod kątem szybkości wczytywania strony.

Skrypty treści działające w "document_idle" nie muszą nasłuchiwać zdarzenia window.onload – gwarantowane jest uruchomienie po zakończeniu DOM. Jeśli skrypt musi zostać uruchomiony po window.onload, rozszerzenie może sprawdzić, czy został już uruchomiony tag onload, korzystając z właściwości document.readyState.
document_start {: #document_start } ciąg znaków Skrypty są wstrzykiwane po plikach z pliku css, ale przed utworzeniem jakiegokolwiek elementu DOM lub uruchomieniem jakiegokolwiek innego skryptu.
document_end {: #document_end } ciąg znaków Skrypty są wstrzykiwane bezpośrednio po zakończeniu DOM, ale przed załadowaniem zasobów podrzędnych, takich jak obrazy i ramki.

Określ klatki

Pole "all_frames" umożliwia rozszerzeniu określenie, czy pliki JavaScript i CSS mają być umieszczane we wszystkich ramkach pasujących do wymagań dotyczących adresu URL, czy tylko w ramce najwyższego poziomu na karcie.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Nazwa Typ Opis
all_frames {: #all_frames } boolean Opcjonalne. Wartość domyślna to false, co oznacza, że dopasowywana jest tylko górna klatka.

Jeśli określisz wartość true, zostanie ona wstrzyknięta we wszystkich klatkach, nawet jeśli nie będzie to najwyższa ramka na karcie. Każda ramka jest sprawdzana niezależnie pod kątem wymagań dotyczących adresu URL. Jeśli te wymagania nie zostaną spełnione, nie będzie wstrzykiwana do ramek podrzędnych.

Komunikacja ze stroną umieszczania

Mimo że środowiska wykonawcze skryptów treści i strony, na których je znajdują, są od siebie odizolowane, mają one dostęp do DOM strony. Jeśli strona chce komunikować się ze skryptem treści lub rozszerzeniem przez skrypt treści, musi to zrobić za pomocą współdzielonego modelu DOM.

Przykład można uzyskać za pomocą 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 na siebie. Wiadomość jest przechwytywana i sprawdzana przez skrypt treści, a następnie publikowana w procesie rozszerzenia. W ten sposób strona nawiązuje komunikację z procesem rozszerzenia. W podobny sposób można zaradzić na odwrót.

Dbaj o bezpieczeństwo

Choć odizolowane światy stanowią warstwę ochrony, używanie skryptów związanych z treścią może skutkować lukami w zabezpieczeniach rozszerzenia i strony internetowej. Jeśli skrypt treści otrzymuje treści z innej witryny, na przykład tworząc żądanie XMLHttpRequest, przed wstrzyknięciem takiego skryptu musisz odfiltrować ataki typu cross-site scripting. Aby uniknąć ataków typu "man-in-the-middle", komunikuj się tylko przez HTTPS.

Pamiętaj, aby filtrować strony pod kątem złośliwych stron. 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 wybierz bezpieczniejsze interfejsy 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);