Skrypty treści to pliki uruchamiane w kontekście stron internetowych. Przy użyciu standardowego Dokumentu modelu obiektowego (DOM), mogą odczytywać szczegóły stron internetowych odwiedzanych przez przeglądarkę, i przekazują informacje do rozszerzenia nadrzędnego.
Omówienie możliwości skryptów treści
Skrypty treści mają bezpośredni dostęp do tych interfejsów API rozszerzeń:
dom
i18n
storage
runtime.connect()
runtime.getManifest()
runtime.getURL()
runtime.id
runtime.onConnect
runtime.onMessage
runtime.sendMessage()
Skrypty treści nie mają bezpośredniego dostępu do innych interfejsów API. Mogą jednak uzyskiwać do nich dostęp pośredni, wymieniając wiadomości z innymi częściami rozszerzenia.
Dostęp do innych plików w rozszerzeniu możesz też uzyskać za pomocą skryptu treści, używając
Interfejsy API takie jak fetch()
. Aby to zrobić, musisz zadeklarować je jako
zasobów dostępnych przez internet. Pamiętaj, że to naraża zasoby również
skrypty własne i innych firm działające w tej samej witrynie.
Praca w odizolowanych światach
Skrypty treści funkcjonują w osobnym świecie, dzięki czemu mogą wprowadzać zmiany w środowisku JavaScript, w którym nie występuje konflikt ze stroną lub innymi rozszerzeniami. skrypty treści.
Rozszerzenie może działać na stronie internetowej z kodem podobnym do tego przykładu.
webPage.html
<html>
<button id="mybutton">click me</button>
<script>
var greeting = "hello, ";
var button = document.getElementById("mybutton");
button.person_name = "Bob";
button.addEventListener(
"click", () => alert(greeting + button.person_name + "."), false);
</script>
</html>
To rozszerzenie może wstrzykiwać następujący skrypt za pomocą jednej z technik opisanych w Wstaw skrypty.
content-script.js
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
"click", () => alert(greeting + button.person_name + "."), false);
Dzięki tej zmianie oba alerty pojawiają się po kliknięciu.
Wstrzykiwanie skryptów
Skrypty treści mogą być statycznie deklarowane, deklarowane dynamicznie lub wstrzykiwana automatycznie.
Wstrzykiwanie z deklaracjami statycznymi
Użyj deklaracji skryptu treści statycznej w pliku manifest.json w przypadku skryptów, które powinny być wykonywane automatycznie na dobrze znanym zestawie stron.
Statycznie zadeklarowane skrypty są zarejestrowane w pliku manifestu w kluczu "content_scripts"
.
Mogą obejmować pliki JavaScript, pliki CSS lub oba te elementy. Wszystkie automatycznie uruchamiane skrypty treści muszą zawierać parametr
wzorców dopasowania.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"css": ["my-styles.css"],
"js": ["content-script.js"]
}
],
...
}
Nazwa | Typ | Opis |
---|---|---|
matches |
tablica ciągów | Wymagane. Określa strony, na których ten skrypt treści będzie wstrzykiwany. Szczegółowe informacje o składni tych ciągów znajdziesz w sekcji Wzorce dopasowania. oraz wzorce i globy dopasowania, aby dowiedzieć się, jak wykluczać Adresy URL. |
css |
tablica ciągów | Opcjonalne. Lista plików CSS do wstrzykiwania do pasujących stron. Są to wstrzykiwane w kolejności, w jakiej występują w tej tablicy, przed utworzeniem lub wyświetleniem DOM dla strony. |
js |
|
Opcjonalne. Lista plików JavaScript do wstrzykiwania na pasujących stronach. Pliki są wstrzykiwane w kolejności, w jakiej występują w tej tablicy. Każdy ciąg na tej liście musi zawierać względną ścieżkę do zasobu w katalogu głównym rozszerzenia. Ukośniki wiodące („/”) są przycięty automatycznie. |
run_at |
RunAt | Opcjonalne. Określa, kiedy skrypt powinien zostać wstawiony na stronie. Domyślna wartość to
document_idle |
match_about_blank |
wartość logiczna | Opcjonalne. Określa, czy skrypt powinien wstrzykiwać się w ramce about:blank
gdzie ramka nadrzędna lub otwierająca pasuje do jednego ze wzorów zadeklarowanych w
matches Wartość domyślna to fałsz. |
match_origin_as_fallback |
wartość logiczna |
Opcjonalne. Określa, czy skrypt ma wstrzykiwać klatki,
utworzone przez pasujące źródło, ale którego adres URL lub źródło może nie być bezpośrednio
do wzorca. Obejmuje to ramki o różnych schematach, takich jak
about: , data: , blob: i
filesystem: Zobacz też
Wstrzyknięcie w powiązanych ramkach
|
world |
ExecutionWorld |
Opcjonalne. Świat JavaScriptu, w którym skrypt ma zostać wykonany. Domyślna wartość to ISOLATED . Zobacz też
Praca w odizolowanych światach.
|
Wstrzykiwanie z deklaracjami dynamicznymi
Skrypty treści dynamicznych są przydatne, gdy wzorce dopasowania skryptów treści są nie są dobrze znane lub gdy skrypty treści nie zawsze powinny być wstrzykiwane na znanych hostach.
Wprowadzone w Chrome 96 deklaracje dynamiczne są podobne do statycznych
, ale obiekt skryptu content jest zarejestrowany w Chrome przy użyciu klucza
w przestrzeni nazw chrome.scripting
, a nie w
manifest.json. Interfejs Scripting API umożliwia też programistom rozszerzeń
do:
- Zarejestruj skrypty treści.
- Uzyskaj listę zarejestrowanych skryptów treści.
- Zaktualizuj listę zarejestrowanych skryptów treści.
- Usuń zarejestrowane skrypty treści.
Podobnie jak deklaracje statyczne, deklaracje dynamiczne mogą zawierać pliki JavaScript, CSS lub oba te elementy.
service-worker.js
chrome.scripting
.registerContentScripts([{
id: "session-script",
js: ["content.js"],
persistAcrossSessions: false,
matches: ["*://example.com/*"],
runAt: "document_start",
}])
.then(() => console.log("registration complete"))
.catch((err) => console.warn("unexpected error", err))
service-worker.js
chrome.scripting
.updateContentScripts([{
id: "session-script",
excludeMatches: ["*://admin.example.com/*"],
}])
.then(() => console.log("registration updated"));
service-worker.js
chrome.scripting
.getRegisteredContentScripts()
.then(scripts => console.log("registered content scripts", scripts));
service-worker.js
chrome.scripting
.unregisterContentScripts({ ids: ["session-script"] })
.then(() => console.log("un-registration complete"));
Wstrzykiwanie automatycznie
Korzystaj z automatycznego wstrzykiwania w przypadku skryptów treści, które muszą być uruchamiane w odpowiedzi na zdarzenia lub w określonych miejscach do różnych okazji.
Aby można było automatycznie wstrzykiwać skrypt treści, rozszerzenie musi mieć uprawnienia hosta dla:
stronie, na której próbuje wstrzyknąć skrypty. Uprawnienia hosta mogą być przyznane przez
wysyła je w pliku manifestu rozszerzenia lub tymczasowo za pomocą "activeTab"
.
Poniżej znajdziesz różne wersje rozszerzenia ActiveTab.
manifest.json:
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
Skrypty treści można wstrzykiwać jako pliki.
content-script.js
document.body.style.backgroundColor = "orange";
service-worker.js:
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ["content-script.js"]
});
});
Treść funkcji można też wstrzykiwać i wykonywać jako skrypt treści.
service-worker.js:
function injectedFunction() {
document.body.style.backgroundColor = "orange";
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
});
});
Pamiętaj, że wstrzyknięta funkcja jest kopią funkcji, do której odwołuje się funkcja
chrome.scripting.executeScript()
, a nie samą funkcję. W efekcie funkcja
ciało musi być nieograniczone; odwołania do zmiennych spoza funkcji spowodują, że treść
skrypt ReferenceError
.
Podczas wstrzykiwania jako funkcji możesz też przekazywać do niej argumenty.
service-worker.js
function injectedFunction(color) {
document.body.style.backgroundColor = color;
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
args : [ "orange" ],
});
});
Wyklucz dopasowania i glory
Aby dostosować określone dopasowanie strony, uwzględnij w deklaracji następujące pola rejestracji.
Nazwa | Typ | Opis |
---|---|---|
exclude_matches |
tablica ciągów | Opcjonalne. Wyklucza strony, które w innym przypadku zostałby wstrzykiwany przez ten skrypt treści . Szczegółowe informacje o składni wyrażeń znajdziesz w artykule Wzorce dopasowania. tych strun. |
include_globs |
tablica ciągów | Opcjonalne. Stosowane po matches , aby uwzględnić tylko te adresy URL, które zawierają też
do tego globa. Ma na celu emulację interfejsu @include
Słowo kluczowe Greasemonkey. |
exclude_globs |
tablica ciągu znaków | Opcjonalne. Stosowane po matches , aby wykluczyć adresy URL, które pasują do tego ustawienia
glob. Służy do emulacji interfejsu @exclude
Słowo kluczowe Greasemonkey. |
Skrypt treści zostanie wstawiony na stronie, jeśli są spełnione oba te warunki:
- Jego adres URL pasuje do dowolnego wzorca
matches
i dowolnego wzorcainclude_globs
. - Adres URL nie pasuje również do wzorca
exclude_matches
aniexclude_globs
. Ponieważ wymagana jest właściwośćmatches
,exclude_matches
,include_globs
iexclude_globs
może jedynie służyć do ograniczenia stron, których on dotyczy.
To rozszerzenie wstawia skrypt treści do klucza https://www.nytimes.com/health
ale nie w https://www.nytimes.com/business
.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.nytimes.com/*" ],
excludeMatches : [ "*://*/*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, a znak zapytania (?
) pasuje do
dowolnego znaku.
Na przykład wzorzec glob https://???.example.com/foo/\*
pasuje do dowolnego z tych elementów:
https://www.example.com/foo/bar
https://the.example.com/foo/
Te dane nie są jednak zgodne z tymi:
https://my.example.com/foo/bar
https://example.com/foo/
https://www.example.com/foo
To rozszerzenie wstawia skrypt treści do języków https://www.nytimes.com/arts/index.html
i
https://www.nytimes.com/jobs/index.htm*
, ale nie w
https://www.nytimes.com/sports/index.html
:
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"include_globs": ["*nytimes.com/???s/*"],
"js": ["contentScript.js"]
}
],
...
}
To rozszerzenie wstawia skrypt treści do języków https://history.nytimes.com
i
https://.nytimes.com/history
, ale nie w: https://science.nytimes.com
ani
https://www.nytimes.com/science
:
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Aby uzyskać odpowiedni zakres, możesz uwzględnić jeden, wszystkie lub niektóre z nich.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_matches": ["*://*/*business*"],
"include_globs": ["*nytimes.com/???s/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Czas trwania
Pole run_at
określa, kiedy pliki JavaScript są wstrzykiwane do strony internetowej. Preferowane i
wartość domyślna to "document_idle"
. Sprawdź typ RunAt, aby poznać inne możliwe wartości.
.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id : "test",
matches : [ "https://*.nytimes.com/*" ],
runAt : "document_idle",
js : [ "contentScript.js" ],
}]);
Nazwa | Typ | Opis |
---|---|---|
document_idle |
ciąg znaków | Preferowana. W miarę możliwości używaj "document_idle" .Przeglądarka wybiera czas wstrzykiwania skryptów między "document_end" a natychmiast po
window.onload
pożary zdarzeń. Dokładny moment wstrzyknięcia zależy od tego, jak złożony jest dokument i w jaki sposób
długo się wczytuje i jest zoptymalizowana pod kątem szybkości wczytywania strony.Skrypty treści uruchomione w "document_idle" , nie muszą nasłuchiwać
window.onload , jest gwarantowane po zakończeniu tworzenia DOM. Jeśli
musi być uruchomiony po window.onload , rozszerzenie może sprawdzić, czy
onload uruchomiono już przy użyciu instancji document.readyState
usłudze. |
document_start |
ciąg znaków | Skrypty są wstrzykiwane po plikach z css , ale przed innymi elementami DOM
lub uruchomić dowolny inny skrypt. |
document_end |
ciąg znaków | Skrypty są wstrzykiwane bezpośrednio po zakończeniu tworzenia DOM, ale przed zasobami podrzędnymi, takimi jak Zdjęcia i ramki zostały wczytane. |
Określ ramki
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
.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
service-worker.js
chrome.scripting.registerContentScripts([{
id: "test",
matches : [ "https://*.nytimes.com/*" ],
allFrames : true,
js : [ "contentScript.js" ],
}]);
Nazwa | Typ | Opis |
---|---|---|
all_frames |
wartość logiczna | Opcjonalne. Domyślna wartość to false , co oznacza, że tylko górna klatka
dopasowane.Jeśli jest określony parametr true , zostaną wstrzyknięte wszystkie klatki, nawet jeśli parametr
nie jest to najwyższa klatka na karcie. Każda ramka jest sprawdzana niezależnie pod kątem adresu URL
. Nie będzie on wstrzyknięty do ramek podrzędnych, jeśli wymagania dotyczące adresów URL nie zostaną spełnione. |
Wstrzyknięcie do powiązanych ramek
Rozszerzenia mogą chcieć uruchamiać skrypty w ramkach powiązanych z dopasowaniem ale nie do siebie pasują. Częstym scenariuszem jest to, dla ramek z adresami URL, które zostały utworzone przez pasującą ramkę, ale których adresy URL do określonych wzorców skryptu.
Dzieje się tak, gdy rozszerzenie chce wstrzykiwać ramki z adresami URL
mają schematy about:
, data:
, blob:
i filesystem:
. W takich przypadkach
Adres URL nie jest zgodny ze wzorcem skryptu treści (oraz w przypadku ciągu about:
oraz
data:
, nie umieszczaj w adresie URL nadrzędnego adresu URL ani źródła
na przykład about:blank
czy data:text/html,<html>Hello, World!</html>
).
Takie klatki mogą jednak nadal być powiązane z ramką tworzącą.
Aby wstrzykiwać do tych ramek, rozszerzenia mogą określać
właściwość "match_origin_as_fallback"
w specyfikacji skryptu treści w parametrze
pliku manifestu.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.google.com/*"],
"match_origin_as_fallback": true,
"js": ["contentScript.js"]
}
],
...
}
Gdy podasz wartość true
i ustawisz wartość true
, Chrome sprawdzi pochodzenie
inicjator ramki, by określić, czy klatka pasuje, a nie w
adresu URL ramki. Może się ono różnić od atrybutu
origin ramki docelowej (np. data:
adresów URL ma wartość null).
Inicjator ramki to ramka, która utworzyła element docelowy lub przemieszczała się po nim ramki. Choć jest to zwykle bezpośrednia decyzja nadrzędna lub otwierająca, niekoniecznie (jak w przypadku w przypadku ramki poruszającej się po elemencie iframe w elemencie iframe).
Porównuje to pochodzenie ramki inicjatora,
może znajdować się na dowolnej ścieżce z tego punktu początkowego. Aby wyraźnie podkreślić to znaczenie, Chrome
wymaga skryptów treści określonych za pomocą parametru "match_origin_as_fallback"
ustaw na true
, aby określić także ścieżkę *
.
Jeśli określisz zarówno "match_origin_as_fallback"
, jak i "match_about_blank"
,
"match_origin_as_fallback"
ma wyższy priorytet.
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 wraz z rozszerzeniem za pomocą skryptu dotyczącego treści, musi to robić za pośrednictwem wspólnego modelu DOM.
Przykładem może być window.postMessage()
:
content-script.js
var port = chrome.runtime.connect();
window.addEventListener("message", (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);
example.js
document.getElementById("theButton").addEventListener("click", () => {
window.postMessage(
{type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);
Strona bez rozszerzeń (example.html) publikuje wiadomości w sobie. Ta wiadomość została przechwycona i sprawdzone przez skrypt treści, a następnie opublikowane w procesie rozszerzenia. W ten sposób strona ustanawia linię komunikacji z procesem przedłużania terminu. Odwrotność jest możliwa dzięki w podobny sposób.
Dostęp do plików rozszerzeń
Aby uzyskać dostęp do pliku rozszerzenia ze skryptu treści, możesz wywołać
chrome.runtime.getURL()
, aby uzyskać bezwzględny URL komponentu rozszerzenia zgodnie z tym przykładem (content.js
):
content-script.js
let image = chrome.runtime.getURL("images/my_image.png")
Aby użyć czcionek lub obrazów w pliku CSS, możesz użyć @@extension_id
do utworzenia adresu URL w sposób opisany w tym przykładzie (content.css
):
content.css
body {
background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');
}
@font-face {
font-family: 'Stint Ultra Expanded';
font-style: normal;
font-weight: 400;
src: url('chrome-extension://__MSG_@@extension_id__/fonts/Stint Ultra Expanded.woff') format('woff');
}
W pliku manifest.json
wszystkie zasoby muszą być zadeklarowane jako zasoby dostępne w internecie:
manifest.json
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
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. wywołując metodę fetch()
, pamiętaj, aby filtrować treści według
cross-site scripting, zanim go wstrzykniesz. Komunikuj się tylko przez HTTPS, aby:
unikaj ataków typu "man-in-the-middle".
Pamiętaj, aby odfiltrować złośliwe strony internetowe. Na przykład te wzorce są niebezpieczne i niedozwolone w pliku manifestu w wersji 3:
content-script.js
const data = document.getElementById("json-data"); // WARNING! Might be evaluating an evil script! const parsed = eval("(" + data + ")");
content-script.js
const 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:
content-script.js
const data = document.getElementById("json-data") // JSON.parse does not evaluate the attacker's scripts. const parsed = JSON.parse(data);
content-script.js
const elmt_id = ... // The closure form of setTimeout does not evaluate scripts. window.setTimeout(() => animate(elmt_id), 200);