Gli script di contenuti sono file che vengono eseguiti nel contesto delle pagine web. L'utilizzo dello standard Documento modello a oggetti (DOM), sono in grado di leggere i dettagli delle pagine web visitate dal browser, modifiche e passare le informazioni all'estensione principale.
Comprendere le funzionalità degli script di contenuti
Gli script di contenuti possono accedere direttamente alle API di estensione indicate di seguito:
dom
i18n
storage
runtime.connect()
runtime.getManifest()
runtime.getURL()
runtime.id
runtime.onConnect
runtime.onMessage
runtime.sendMessage()
Gli script di contenuti non sono in grado di accedere direttamente ad altre API. Tuttavia, possono accedervi indirettamente scambiando messaggi con altre parti della tua estensione.
Puoi anche accedere ad altri file dell'estensione da uno script di contenuti, utilizzando
API come fetch()
. Per farlo, devi dichiarare
risorse accessibili dal web. Tieni presente che in questo modo le risorse vengono esposte anche a qualsiasi
script proprietari o di terze parti eseguiti sullo stesso sito.
Lavora in mondi isolati
I script di contenuti risiedono in un mondo isolato e consentono a un copione di apportare modifiche ambiente JavaScript senza essere in conflitto con la pagina o con altre estensioni script di contenuti.
Un'estensione può essere eseguita in una pagina web con un codice simile all'esempio riportato di seguito.
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>
Questa estensione potrebbe inserire il seguente script di contenuti utilizzando una delle tecniche descritte nel Sezione Inserisci script.
content-script.js
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
"click", () => alert(greeting + button.person_name + "."), false);
Con questa modifica, entrambi gli avvisi vengono visualizzati in sequenza quando si fa clic sul pulsante.
Inserisci script
Gli script di contenuti possono essere dichiarati in modo statico, dichiarati in modo dinamico o iniettato in modo programmatico.
Inserisci dichiarazioni statiche
Utilizza dichiarazioni relative agli script dei contenuti statici in manifest.json per gli script che dovrebbero essere automatici vengono eseguite su un insieme di pagine noto.
Gli script dichiarati in modo statico sono registrati nel file manifest nella chiave "content_scripts"
.
Possono includere file JavaScript, CSS o entrambi. Tutti gli script di contenuti a esecuzione automatica devono specificare
pattern di corrispondenza.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"css": ["my-styles.css"],
"js": ["content-script.js"]
}
],
...
}
Nome | Tipo | Descrizione |
---|---|---|
matches |
array di stringhe | Obbligatorio. Specifica le pagine in cui verrà inserito questo script di contenuti. Consulta Pattern di corrispondenza per i dettagli sulla sintassi di queste stringhe e Pattern di corrispondenza e glob per informazioni su come escludere URL. |
css |
array di stringhe | Facoltativo. L'elenco di file CSS da inserire nelle pagine corrispondenti. Si tratta di inseriti nell'ordine in cui appaiono in questo array, prima che venga creato o visualizzato qualsiasi DOM per la pagina. |
js |
|
Facoltativo. L'elenco di file JavaScript da inserire nelle pagine corrispondenti. File vengono inseriti nell'ordine in cui appaiono in questo array. Ogni stringa in questo elenco deve contenere un percorso relativo di una risorsa nella directory radice dell'estensione. Le barre iniziali ("/") sono tagliato automaticamente. |
run_at |
RunAt | Facoltativo. Specifica quando lo script deve essere inserito nella pagina. Il valore predefinito è
document_idle . |
match_about_blank |
booleano | Facoltativo. Indica se lo script deve essere inserito in un frame about:blank
in cui il frame principale o di apertura corrisponde a uno dei pattern dichiarati
matches . Il valore predefinito è false. |
match_origin_as_fallback |
booleano |
Facoltativo. Indica se lo script deve essere inserito nei frame che sono stati
creati da un'origine corrispondente, ma il cui URL o la cui origine potrebbero non essere
corrispondono al pattern. Sono inclusi frame con schemi diversi, come
about: , data: , blob: e
filesystem: . Vedi anche
Inserimento nei frame correlati.
|
world |
ExecutionWorld |
Facoltativo. Il mondo JavaScript in cui deve essere eseguito uno script. Il valore predefinito è ISOLATED . Vedi anche
Lavora in mondi isolati.
|
Inserisci con dichiarazioni dinamiche
Gli script di contenuti dinamici sono utili quando i pattern di corrispondenza per gli script di contenuti sono non sono noti o quando gli script di contenuti non devono sempre essere inseriti su host noti.
Introdotte in Chrome 96, le dichiarazioni dinamiche sono simili alle
dichiarazioni, ma l'oggetto script dei contenuti è registrato in Chrome utilizzando
nello spazio dei nomi chrome.scripting
anziché nello
manifest.json. L'API Scripting consente inoltre agli sviluppatori di estensioni
a:
- Registra script di contenuti.
- Ottieni un elenco di script di contenuti registrati.
- Aggiorna l'elenco degli script di contenuti registrati.
- Rimuovi script di contenuti registrati.
Come le dichiarazioni statiche, le dichiarazioni dinamiche possono includere file JavaScript, file CSS o entrambi.
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"));
Inserisci in modo programmatico
Usa l'inserimento programmatico per gli script di contenuti che devono essere eseguiti in risposta a eventi o su specifici occasioni.
Per inserire uno script di contenuti in modo programmatico, l'estensione deve disporre delle autorizzazioni host per
la pagina in cui sta tentando di inserire script. Le autorizzazioni host possono essere concesse
richiedendoli come parte del file manifest dell'estensione o utilizzando temporaneamente "activeTab"
.
Di seguito sono riportate le diverse versioni di un'estensione basata su ActiveTab.
manifest.json:
{
"name": "My extension",
...
"permissions": [
"activeTab",
"scripting"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_title": "Action Button"
}
}
Gli script di contenuti possono essere inseriti come file.
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"]
});
});
Il corpo di una funzione può essere inserito ed eseguito come script di contenuti.
service-worker.js:
function injectedFunction() {
document.body.style.backgroundColor = "orange";
}
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target : {tabId : tab.id},
func : injectedFunction,
});
});
Tieni presente che la funzione inserita è una copia della funzione a cui viene fatto riferimento nel
chrome.scripting.executeScript()
, non la funzione originale. Di conseguenza, la funzione
il corpo deve essere autonomo; i riferimenti a variabili al di fuori della funzione faranno sì che i contenuti
per generare un ReferenceError
.
Quando esegui l'inserimento come funzione, puoi anche passare argomenti alla funzione.
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" ],
});
});
Escludi corrispondenze e glob
Per personalizzare la corrispondenza delle pagine specificate, includi i seguenti campi in una registrazione.
Nome | Tipo | Descrizione |
---|---|---|
exclude_matches |
array di stringhe | Facoltativo. Esclude le pagine che altrimenti verrebbe inserito lo script di contenuti in cui viene eseguito il deployment. Consulta Pattern di corrispondenza per i dettagli sulla sintassi dei queste stringhe. |
include_globs |
array di stringhe | Facoltativo. Applicata dopo il giorno matches per includere solo gli URL che
corrispondono a questo glob. Il suo scopo è emulare @include
Parola chiave Greasemonkey. |
exclude_globs |
array di stringhe | Facoltativo. Applicato dopo il giorno matches per escludere gli URL corrispondenti
glob. Ha lo scopo di emulare @exclude
Parola chiave Greasemonkey. |
Lo script dei contenuti verrà inserito in una pagina se entrambe le seguenti condizioni sono vere:
- Il suo URL corrisponde a qualsiasi pattern
matches
e a qualsiasi patterninclude_globs
. - Inoltre, l'URL non corrisponde a un pattern
exclude_matches
oexclude_globs
. Poiché la proprietàmatches
è obbligatoria,exclude_matches
,include_globs
eexclude_globs
può essere utilizzato solo per limitare le pagine interessate.
La seguente estensione inserisce lo script dei contenuti in https://www.nytimes.com/health
ma non in 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" ],
}]);
Le proprietà dei globi seguono una sintassi diversa e più flessibile rispetto ai pattern di corrispondenza. Glob accettabile
le stringhe sono URL che possono contenere "caratteri jolly" asterischi e punti interrogativi. L'asterisco (*
)
corrisponde a qualsiasi stringa di qualsiasi lunghezza, inclusa la stringa vuota, mentre il punto interrogativo (?
) corrisponde
è qualsiasi carattere.
Ad esempio, il glob https://???.example.com/foo/\*
corrisponde a uno dei seguenti valori:
https://www.example.com/foo/bar
https://the.example.com/foo/
Tuttavia, non corrisponde a quanto segue:
https://my.example.com/foo/bar
https://example.com/foo/
https://www.example.com/foo
Questa estensione inserisce lo script dei contenuti in https://www.nytimes.com/arts/index.html
e
https://www.nytimes.com/jobs/index.htm*
, ma non in
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"]
}
],
...
}
Questa estensione inserisce lo script dei contenuti in https://history.nytimes.com
e
https://.nytimes.com/history
, ma non in https://science.nytimes.com
o
https://www.nytimes.com/science
:
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"exclude_globs": ["*science*"],
"js": ["contentScript.js"]
}
],
...
}
Puoi includere uno, tutti o alcuni di questi elementi per raggiungere l'ambito corretto.
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"]
}
],
...
}
Tempo di esecuzione
Il campo run_at
consente di stabilire quando i file JavaScript vengono inseriti nella pagina web. L'interfaccia preferita e
il valore predefinito è "document_idle"
. Vedi il tipo RunAt per altri possibili
e i relativi valori.
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" ],
}]);
Nome | Tipo | Descrizione |
---|---|---|
document_idle |
stringa | Preferito. Utilizza "document_idle" quando possibile.Il browser sceglie un orario per inserire gli script tra il giorno "document_end" e subito dopo
window.onload
di eventi. Il momento esatto dell'inserimento dipende dalla complessità del documento e da quanto
richiede molto tempo ed è ottimizzato per la velocità di caricamento delle pagine.Script di contenuti in esecuzione alle "document_idle" non hanno bisogno di ascoltare
window.onload , la loro esecuzione è garantita al termine del DOM. Se
lo script deve sicuramente essere eseguito dopo il giorno window.onload , l'estensione può controllare
onload è già stato attivato utilizzando document.readyState
proprietà. |
document_start |
stringa | Gli script vengono inseriti dopo qualsiasi file da css , ma prima che qualsiasi altro DOM
o eseguire qualsiasi altro script. |
document_end |
stringa | Gli script vengono inseriti subito dopo il completamento del DOM, ma prima delle sottorisorse come immagini e frame sono stati caricati. |
Specifica frame
Il campo "all_frames"
consente all'estensione di specificare se i file JavaScript e CSS devono essere
inseriti in tutti i frame corrispondenti ai requisiti dell'URL specificati o solo nel frame più in alto in un
.
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" ],
}]);
Nome | Tipo | Descrizione |
---|---|---|
all_frames |
booleano | Facoltativo. Il valore predefinito è false , il che significa che solo il frame superiore è
corrispondenti.Se true viene specificato, tutti i frame verranno inseriti, anche se
non è il frame più in alto nella scheda. Ogni frame viene controllato separatamente per verificare l'URL
i tuoi requisiti. Non verrà inserito nei frame secondari se non vengono soddisfatti i requisiti degli URL. |
Inserisci nei frame correlati
Le estensioni potrebbero voler eseguire script in frame correlati a un modello ma non corrispondono. Uno scenario comune in questo caso è per i frame con URL creati da un frame corrispondente, ma i cui URL non corrispondono corrispondono ai pattern specificati dello script.
Questo è il caso quando un'estensione vuole inserire frame con URL che
hanno schemi about:
, data:
, blob:
e filesystem:
. In questi casi,
L'URL non corrisponderà al pattern dello script dei contenuti (e, nel caso di about:
e
data:
, non includere nell'URL l'URL o l'origine principale
come in about:blank
o data:text/html,<html>Hello, World!</html>
).
Tuttavia, questi frame possono comunque essere associati al frame in fase di creazione.
Per essere inseriti in questi frame, le estensioni possono specificare
"match_origin_as_fallback"
nella specifica di Content Script in
del file manifest.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.google.com/*"],
"match_origin_as_fallback": true,
"js": ["contentScript.js"]
}
],
...
}
Se specificato e impostato su true
, Chrome esaminerà l'origine del
iniziatore del frame per determinare se quest'ultimo corrisponde, anziché
l'URL del frame stesso. Tieni presente che potrebbe anche essere diversa dalla
origin del frame di destinazione (ad es. data:
URL hanno un'origine nulla).
L'iniziatore del frame è il frame che ha creato o navigato nel target frame. Anche se di solito questo è il genitore diretto o l'interlocutore, potrebbe non essere (come nel caso di un frame che naviga all'interno di un iframe).
Poiché viene confrontata l'origine del frame iniziatore, quest'ultimo
potrebbe trovarsi su qualsiasi percorso da quell'origine. Per chiarire questa implicazione, Chrome
richiede eventuali script di contenuti specificati con "match_origin_as_fallback"
impostato su true
per specificare anche un percorso di *
.
Quando "match_origin_as_fallback"
e "match_about_blank"
sono specificati,
"match_origin_as_fallback"
ha la priorità.
Comunicazione con la pagina di incorporamento
Sebbene gli ambienti di esecuzione degli script di contenuti e le pagine che li ospitano siano isolati condividono l'accesso al DOM della pagina. Se la pagina desidera comunicare con Content Script o con l'estensione tramite lo script dei contenuti, deve farlo tramite il DOM condiviso.
Puoi ottenere un esempio utilizzando 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);
La pagina senza estensione example.html pubblica i messaggi su se stessa. Questo messaggio è stato intercettato e venga esaminata dallo script dei contenuti e pubblicata nel processo di estensione. In questo modo, la pagina stabilisce una linea di comunicazione con il processo di estensione. L'inversione è possibile grazie alla con mezzi simili.
Accedere ai file delle estensioni
Per accedere a un file di estensione da uno script di contenuti, puoi chiamare
chrome.runtime.getURL()
per ottenere l'URL assoluto dell'asset dell'estensione, come mostrato nell'esempio seguente (content.js
):
content-script.js
let image = chrome.runtime.getURL("images/my_image.png")
Per utilizzare caratteri o immagini in un file CSS, puoi utilizzare @@extension_id
per creare un URL come mostrato nell'esempio seguente (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');
}
Tutte le risorse devono essere dichiarate come risorse accessibili dal web nel file manifest.json
:
manifest.json
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Rafforza la tua sicurezza
Mentre i mondi isolati forniscono un livello di protezione, l'uso degli script di contenuti può creare
le vulnerabilità in un'estensione e nella pagina web. Se lo script dei contenuti riceve contenuti da un
sito web separato, ad esempio chiamando fetch()
, presta attenzione a filtrare i contenuti
tramite attacchi cross-site scripting. Comunicare solo tramite HTTPS per
Evita gli attacchi "man-in-the-middle".
Assicurati di filtrare le pagine web dannose. Ad esempio, i seguenti pattern sono pericolosi e non consentito in Manifest V3:
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);
Preferisci API più sicure che non eseguono script:
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);