Skrip konten

Skrip konten adalah file yang berjalan dalam konteks halaman web. Dengan menggunakan Document Object Model (DOM) standar, ekstensi ini dapat membaca detail halaman web yang dikunjungi browser, membuat perubahan pada halaman tersebut, dan meneruskan informasi ke ekstensi induknya.

Memahami kemampuan skrip konten

Skrip konten dapat mengakses Chrome API yang digunakan oleh ekstensi induknya dengan bertukar pesan dengan ekstensi. File tersebut juga dapat mengakses URL file ekstensi dengan chrome.runtime.getURL() dan menggunakan hasilnya sama seperti URL lainnya.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

Selain itu, skrip konten dapat mengakses Chrome API berikut secara langsung:

Skrip konten tidak dapat mengakses API lain secara langsung.

Bekerja di dunia yang terisolasi

Skrip konten berada di dunia yang terisolasi, sehingga memungkinkan skrip konten membuat perubahan pada lingkungan JavaScript-nya tanpa bertentangan dengan halaman atau skrip konten tambahan.

Ekstensi dapat berjalan di halaman web dengan kode yang mirip dengan contoh di bawah.

<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>

Ekstensi tersebut dapat memasukkan skrip konten berikut.

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
  alert(greeting + button.person_name + ".");
}, false);

Kedua pemberitahuan akan muncul jika tombol ditekan.

Dunia yang terisolasi tidak mengizinkan skrip konten, ekstensi, dan halaman web mengakses variabel atau fungsi apa pun yang dibuat oleh yang lain. Hal ini juga memberi skrip konten kemampuan untuk mengaktifkan fungsi yang tidak boleh diakses oleh halaman web.

Memasukkan skrip

Skrip Konten dapat dimasukkan secara terprogram atau secara deklaratif.

Memasukkan secara terprogram

Gunakan injeksi terprogram untuk skrip konten yang perlu dijalankan pada kesempatan tertentu.

Untuk memasukkan skrip konten terprogram, berikan izin activeTab dalam manifes. Tindakan ini memberikan akses aman ke host situs aktif dan akses sementara ke izin tab, sehingga skrip konten dapat berjalan di tab aktif saat ini tanpa menentukan izin lintas-asal.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

Skrip konten dapat dimasukkan sebagai kode.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

Atau, seluruh file dapat dimasukkan.

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

Memasukkan secara deklaratif

Gunakan injeksi deklaratif untuk skrip konten yang harus otomatis dijalankan di halaman yang ditentukan.

Skrip yang dimasukkan secara deklaratif didaftarkan dalam manifes di kolom "content_scripts". File tersebut dapat menyertakan file JavaScript, file CSS, atau keduanya. Semua skrip konten yang berjalan otomatis harus menentukan pola pencocokan.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Nama Jenis Deskripsi
matches {: #matches } array string Wajib. Menentukan halaman tempat skrip konten ini akan dimasukkan. Lihat Pola Pencocokan untuk mengetahui detail selengkapnya tentang sintaksis string ini dan Pola pencocokan dan glob untuk mengetahui informasi tentang cara mengecualikan URL.
css {: #css } array string Opsional. Daftar file CSS yang akan dimasukkan ke halaman yang cocok. Ini dimasukkan sesuai urutan kemunculan dalam array ini, sebelum DOM dibuat atau ditampilkan untuk halaman.
js {: #js } array string Opsional. Daftar file JavaScript yang akan dimasukkan ke halaman yang cocok. Ini dimasukkan sesuai urutan yang muncul dalam array ini.
match_about_blank {: #match_about_blank } boolean Opsional. Apakah skrip harus dimasukkan ke dalam frame about:blank dengan frame induk atau pembuka yang cocok dengan salah satu pola yang dideklarasikan di matches. Defaultnya adalah false.

Mengecualikan kecocokan dan glob

Pencocokan halaman yang ditentukan dapat disesuaikan dengan menyertakan kolom berikut dalam pendaftaran manifes.

Nama Jenis Deskripsi
exclude_matches {: #exclude_matches } array string Opsional. Mengecualikan halaman yang akan disuntik oleh skrip konten ini. Lihat Pola Pencocokan untuk mengetahui detail selengkapnya tentang sintaksis string ini.
include_globs {: #include_globs } array string Opsional. Diterapkan setelah matches untuk hanya menyertakan URL yang juga cocok dengan glob ini. Dimaksudkan untuk mengemulasi kata kunci Greasemonkey @include.
exclude_globs {: #exclude_globs } array string Opsional. Diterapkan setelah matches untuk mengecualikan URL yang cocok dengan glob ini. Dimaksudkan untuk mengemulasi kata kunci Greasemonkey @exclude.

Skrip konten akan dimasukkan ke dalam halaman jika URL-nya cocok dengan pola matches dan pola include_globs apa pun, selama URL tersebut juga tidak cocok dengan pola exclude_matches atau exclude_globs.

Karena properti matches diperlukan, exclude_matches, include_globs, dan exclude_globs hanya dapat digunakan untuk membatasi halaman mana yang akan terpengaruh.

Ekstensi berikut akan memasukkan skrip konten ke http://www.nytimes.com/ health, tetapi tidak ke http://www.nytimes.com/ business .

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

Properti glob mengikuti sintaksis yang berbeda dan lebih fleksibel daripada pola pencocokan. String glob yang dapat diterima adalah URL yang dapat berisi tanda bintang "karakter pengganti" dan tanda tanya. Tanda bintang * cocok dengan string apa pun dengan panjang berapa pun, termasuk string kosong, sedangkan tanda tanya ? cocok dengan satu karakter apa pun.

Misalnya, glob http:// ??? .example.com/foo/ * cocok dengan salah satu dari yang berikut:

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

Namun, tidak cocok dengan hal berikut:

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

Ekstensi ini akan memasukkan skrip konten ke http:/www.nytimes.com/ arts /index.html dan http://www.nytimes.com/ jobs /index.html, tetapi tidak ke http://www.nytimes.com/ sports /index.html.

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

Ekstensi ini akan memasukkan skrip konten ke http:// history .nytimes.com dan http://.nytimes.com/ history, tetapi tidak ke http:// science .nytimes.com atau http://www.nytimes.com/ science .

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

Satu, semua, atau beberapa dari hal ini dapat disertakan untuk mencapai cakupan yang benar.

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

Waktu proses

Saat file JavaScript dimasukkan ke halaman web, file tersebut dikontrol oleh kolom run_at. Kolom yang lebih disukai dan default adalah "document_idle", tetapi juga dapat ditentukan sebagai "document_start" atau "document_end" jika diperlukan.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Nama Jenis Deskripsi
document_idle {: #document_idle } string Lebih disukai. Gunakan "document_idle" jika memungkinkan.

Browser memilih waktu untuk memasukkan skrip antara "document_end" dan segera setelah peristiwa windowonload diaktifkan. Momen injeksi yang tepat bergantung pada kompleksitas dokumen dan waktu yang diperlukan untuk memuat, serta dioptimalkan untuk kecepatan pemuatan halaman.

Skrip konten yang berjalan di "document_idle" tidak perlu memproses peristiwa window.onload, karena skrip tersebut dijamin akan berjalan setelah DOM selesai. Jika skrip harus dijalankan setelah window.onload, ekstensi dapat memeriksa apakah onload telah diaktifkan menggunakan properti document.readyState.
document_start {: #document_start } string Skrip dimasukkan setelah file dari css, tetapi sebelum DOM lain dibuat atau skrip lain dijalankan.
document_end {: #document_end } string Skrip dimasukkan segera setelah DOM selesai, tetapi sebelum sub-resource seperti gambar dan frame dimuat.

Menentukan frame

Kolom "all_frames" memungkinkan ekstensi menentukan apakah file JavaScript dan CSS harus dimasukkan ke semua frame yang cocok dengan persyaratan URL yang ditentukan atau hanya ke frame paling atas di tab.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Nama Jenis Deskripsi
all_frames {: #all_frames } boolean Opsional. Defaultnya adalah false, yang berarti hanya frame atas yang cocok.

Jika true ditentukan, true akan dimasukkan ke semua frame, meskipun frame tersebut bukan frame paling atas di tab. Setiap frame diperiksa secara terpisah untuk persyaratan URL, dan tidak akan dimasukkan ke dalam frame turunan jika persyaratan URL tidak terpenuhi.

Komunikasi dengan halaman penyematan

Meskipun lingkungan eksekusi skrip konten dan halaman yang menghostingnya terisolasi satu sama lain, keduanya berbagi akses ke DOM halaman. Jika halaman ingin berkomunikasi dengan skrip konten, atau dengan ekstensi melalui skrip konten, halaman harus melakukannya melalui DOM bersama.

Contoh dapat dilakukan menggunakan 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);

Halaman non-ekstensi, example.html, memposting pesan ke dirinya sendiri. Pesan ini dicegat dan diperiksa oleh skrip konten, lalu diposting ke proses ekstensi. Dengan cara ini, halaman akan membuat jalur komunikasi ke proses ekstensi. Hal sebaliknya dapat dilakukan melalui cara yang serupa.

Tetap aman

Meskipun dunia terisolasi memberikan lapisan perlindungan, penggunaan skrip konten dapat membuat kerentanan dalam ekstensi dan halaman web. Jika skrip konten menerima konten dari situs terpisah, seperti membuat XMLHttpRequest, berhati-hatilah untuk memfilter serangan cross-site scripting konten sebelum memasukkannya. Hanya berkomunikasi melalui HTTPS untuk menghindari serangan "man-in-the-middle".

Pastikan untuk memfilter halaman web berbahaya. Misalnya, pola berikut berbahaya:

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);

Sebagai gantinya, pilih API yang lebih aman yang tidak menjalankan skrip:

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);