Script di contenuti

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:

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 array di stringhe 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:

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 pattern include_globs.
  • Inoltre, l'URL non corrisponde a un pattern exclude_matches o exclude_globs. Poiché la proprietà matches è obbligatoria, exclude_matches, include_globs e exclude_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.

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 &quot;man-in-the-middle&quot;.

Assicurati di filtrare le pagine web dannose. Ad esempio, i seguenti pattern sono pericolosi e non consentito in Manifest V3:

Cosa non fare

content-script.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
Cosa non fare

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:

Cosa fare

content-script.js

const data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
const parsed = JSON.parse(data);
Cosa fare

content-script.js

const elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(() => animate(elmt_id), 200);