İçerik komut dosyaları

İçerik komut dosyaları, web sayfaları bağlamında çalışan dosyalardır. Standart Belge Nesne Modeli'ni (DOM) kullanarak, tarayıcının ziyaret ettiği web sayfalarının ayrıntılarını okuyabilir, bu sayfalarda değişiklikler yapabilir ve üst uzantılarına bilgi aktarabilirler.

İçerik komut dosyası işlevlerini anlama

İçerik komut dosyaları, web'den erişilebilen kaynaklar olarak tanımlandıktan sonra uzantı dosyalarına erişebilir. Aşağıdaki uzantı API'lerine doğrudan erişebilirler:

İçerik komut dosyaları, diğer API'lere doğrudan erişemez. Ancak, uzantınızın diğer bölümleriyle mesaj alışverişinde bulunarak bunlara dolaylı olarak erişebilirler.

Yalnız dünyalarda çalışın

İçerik komut dosyaları yalıtılmış bir dünyada yaşar ve içerik komut dosyasının sayfayla veya diğer uzantıların içerik komut dosyalarıyla çakışmadan JavaScript ortamında değişiklik yapmasına olanak tanır.

Bir uzantı, bir web sayfasında aşağıdaki örneğe benzer bir kodla çalışabilir.

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>

Bu uzantı, Komut dosyası yerleştirme bölümünde açıklanan tekniklerden birini kullanarak aşağıdaki içerik komut dosyasını yerleştirebilir.

content-script.js

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

Bu değişiklikle birlikte, düğme tıklandığında her iki uyarı da sırayla gösterilir.

Komut dosyası ekle

İçerik komut dosyaları statik olarak bildirilebilir, dinamik olarak bildirilebilir veya programatik olarak eklenebilir.

Statik bildirimlerle ekleme

İyi bilinen bir sayfa grubunda otomatik olarak çalıştırılması gereken komut dosyaları için manifest.json dosyasında statik içerik komut dosyası bildirimleri kullanın.

Statik olarak tanımlanan komut dosyaları, manifest dosyasında "content_scripts" anahtarı altında kaydedilir. JavaScript dosyalarını, CSS dosyalarını veya her ikisini birden içerebilirler. Otomatik olarak çalıştırılan tüm içerik komut dosyaları, eşleşme kalıpları belirtmelidir.

manifest.json

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["https://*.nytimes.com/*"],
     "css": ["my-styles.css"],
     "js": ["content-script.js"]
   }
 ],
 ...
}

Ad Tür Açıklama
matches dize dizisi Zorunludur. Bu içerik komut dosyasının hangi sayfalara yerleştirileceğini belirtir. Bu dizelerin söz dizimiyle ilgili ayrıntılar için Eşleşme Kalıpları'na, URL'lerin nasıl hariç tutulacağıyla ilgili bilgi için Eşleşme kalıpları ve glob'lar bölümüne bakın.
css dize dizisi İsteğe bağlı. Eşleşen sayfalara eklenecek CSS dosyalarının listesi. Bunlar, sayfa için herhangi bir DOM oluşturulmadan veya görüntülenmeden önce, bu dizide göründükleri sırayla eklenir.
js dize dizisi İsteğe bağlı. Eşleşen sayfalara yerleştirilecek JavaScript dosyalarının listesi. Dosyalar, bu dizide göründükleri sırayla eklenir. Bu listedeki her dize, uzantının kök dizinindeki bir kaynağa giden göreli bir yol içermelidir. Baştaki eğik çizgiler ("/") otomatik olarak kırpılır.
run_at RunAt İsteğe bağlı. Komut dosyasının sayfaya ne zaman eklenmesi gerektiğini belirtir. Varsayılan olarak document_idle değerine ayarlanır.
match_about_blank boolean İsteğe bağlı. Komut dosyasının, üst veya açılış çerçevesinin matches içinde açıklanan kalıplardan biriyle eşleştiği bir about:blank çerçevesine eklenip eklenmeyeceğini belirtir. Varsayılan olarak false değerine ayarlanır.
match_origin_as_fallback boolean İsteğe bağlı. Komut dosyasının eşleşen bir kaynak tarafından oluşturulan ancak URL'si veya kaynağı kalıpla doğrudan eşleşmeyebileceği karelere ekleme yapması gerekip gerekmediği. Bunlara about:, data:, blob: ve filesystem: gibi farklı şemalara sahip çerçeveler dahildir. Ayrıca bkz. İlgili çerçevelere ekleme.
world ExecutionWorld İsteğe bağlı. Bir komut dosyasının içinde yürütüleceği JavaScript dünyası. Varsayılan olarak ISOLATED değerine ayarlanır. Ayrı dünyalarda çalışma konusuna da bakın.

Dinamik bildirimlerle ekleme

Dinamik içerik komut dosyaları, içerik komut dosyalarına ilişkin eşleşme kalıpları iyi bilinmiyorsa veya içerik komut dosyalarının bilinen ana makinelere her zaman yerleştirilmemesi gerektiğinde yararlı olur.

Chrome 96'da kullanıma sunulan dinamik bildirimler statik bildirimlere benzer, ancak içerik komut dosyası nesnesi Chrome ile manifest.json yerine chrome.scripting ad alanındaki yöntemler kullanılarak kaydedilir. Scripting API, uzantı geliştiricilerinin aşağıdakileri yapmasına da olanak tanır:

Statik bildirimler gibi dinamik bildirimler de JavaScript dosyalarını, CSS dosyalarını veya her ikisini birden içerebilir.

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

Programlı olarak ekle

Etkinliklere yanıt olarak veya belirli durumlarda çalışması gereken içerik komut dosyaları için programatik yerleştirme kullanın.

Bir içerik komut dosyasını programatik olarak eklemek için uzantınızın, komut dosyası eklemeye çalıştığı sayfa için ana makine izinlerine ihtiyacı vardır. Ana makine izinleri, uzantınızın manifestinin bir parçası olarak isteyerek veya geçici olarak "activeTab" kullanılarak verilebilir.

Aşağıda, ActiveTab tabanlı bir uzantının farklı sürümleri gösterilmektedir.

manifest.json:

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Action Button"
  }
}

İçerik komut dosyaları dosya olarak yerleştirilebilir.

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"]
  });
});

Alternatif olarak, işlev gövdesi eklenebilir ve içerik komut dosyası olarak yürütülebilir.

service-worker.js:

function injectedFunction() {
  document.body.style.backgroundColor = "orange";
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
  });
});

Yerleştirilen işlevin, orijinal işlevin kendisi değil, chrome.scripting.executeScript() çağrısında başvurulan işlevin bir kopyası olduğunu unutmayın. Sonuç olarak, işlevin gövdesi bağımsız olmalıdır; işlevin dışındaki değişkenlere referanslar, content komut dosyasının bir ReferenceError göndermesine neden olur.

İşlev olarak yerleştirirken, işleve bağımsız değişkenler de geçirebilirsiniz.

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" ],
  });
});

Eşleşmeleri ve glob'ları hariç tutma

Belirtilen sayfa eşleşmesini özelleştirmek için bildirim temelli kayda aşağıdaki alanları ekleyin.

Ad Tür Açıklama
exclude_matches dize dizisi İsteğe bağlı. Bu içerik komut dosyasının başka bir şekilde yerleştirileceği sayfaları hariç tutar. Bu dizelerin söz dizimiyle ilgili ayrıntılar için Eşleşme Kalıpları bölümüne bakın.
include_globs dize dizisi İsteğe bağlı. Yalnızca bu glob'la eşleşen URL'leri dahil etmek için matches tarihinden sonra uygulanır. Bunun amacı, @include Greasemonkey anahtar kelimesinin emülasyonudur.
exclude_globs dize dizisi İsteğe bağlı. Bu glob'la eşleşen URL'leri hariç tutmak için matches tarihinden sonra uygulandı. @exclude Greasemonkey anahtar kelimesine emülasyon sağlamak amacıyla tasarlanmıştır.

Aşağıdakilerin her ikisi de doğru olduğunda içerik komut dosyası sayfaya yerleştirilir:

  • URL'si, herhangi bir matches kalıbıyla ve tüm include_globs kalıbıyla eşleşir.
  • URL, bir exclude_matches veya exclude_globs kalıbıyla da eşleşmiyor. matches özelliği zorunlu olduğundan, exclude_matches, include_globs ve exclude_globs yalnızca hangi sayfaların etkileneceğini sınırlamak için kullanılabilir.

Aşağıdaki uzantı, içerik komut dosyasını https://www.nytimes.com/health içine ekler, ancak https://www.nytimes.com/business içine eklemez .

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" ],
}]);

Yerküre özellikleri eşleşme kalıplarından farklı, daha esnek bir söz dizimi kullanır. Kabul edilebilir glob dizeleri, "joker karakter" yıldız ve soru işaretleri içerebilen URL'lerdir. Yıldız işareti (*) boş dize de dahil olmak üzere herhangi bir uzunlukta herhangi bir dizeyle eşleşirken, soru işareti (?) tek bir karakterle eşleşir.

Örneğin, https://???.example.com/foo/\* glob'u aşağıdakilerin herhangi biriyle eşleşir:

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

Ancak aşağıdakilerle eşleşmez:

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

Bu uzantı, içerik komut dosyasını https://www.nytimes.com/arts/index.html ve https://www.nytimes.com/jobs/index.htm* bağlantılarına ekler, ancak https://www.nytimes.com/sports/index.html içine eklemez:

manifest.json

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

Bu uzantı, içerik komut dosyasını https://history.nytimes.com ve https://.nytimes.com/history bağlantılarına ekler, ancak https://science.nytimes.com veya https://www.nytimes.com/science içine eklemez:

manifest.json

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

Doğru kapsama ulaşmak için bunlardan biri, tümü veya bir kısmı dahil edilebilir.

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"]
    }
  ],
  ...
}

Süre

run_at alanı, JavaScript dosyalarının web sayfasına ne zaman ekleneceğini kontrol eder. Tercih edilen ve varsayılan değer "document_idle"'tır. Diğer olası değerler için RunAt türüne bakın.

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" ],
}]);
Ad Tür Açıklama
document_idle dize Tercih edilir. Mümkün olduğunda "document_idle" kullanın.

Tarayıcı, komut dosyalarının "document_end" arasında ve window.onload etkinliğinin hemen tetiklenmesinden hemen sonra eklenecek zamanı seçer. Yerleştirme işleminin gerçek zamanı, belgenin ne kadar karmaşık olduğuna, yüklenmesinin ne kadar sürdüğüne bağlıdır ve sayfa yükleme hızı için optimize edilmiştir.

"document_idle" konumunda çalışan içerik komut dosyalarının window.onload etkinliğini dinlemesi gerekmez. DOM tamamlandıktan sonra çalışacakları garanti edilir. Bir komut dosyasının window.onload tarihinden sonra kesinlikle çalışması gerekiyorsa uzantı, document.readyState özelliğini kullanarak onload önceden tetiklenip tetiklenmediğini kontrol edebilir.
document_start dize Komut dosyaları, css özelliğinden herhangi bir dosyadan sonra, ancak başka bir DOM oluşturulmadan veya başka bir komut dosyası çalıştırılmadan önce yerleştirilir.
document_end dize Komut dosyaları, DOM tamamlandıktan hemen sonra ancak resim ve çerçeve gibi alt kaynaklar yüklenmeden önce yerleştirilir.

Çerçeveleri belirtin

"all_frames" alanı, uzantının, JavaScript ve CSS dosyalarının belirtilen URL gereksinimleriyle eşleşen tüm çerçevelere mi yoksa yalnızca bir sekmedeki en üstteki çerçeveye mi yerleştirilmesi gerektiğini belirtmesine olanak tanır.

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" ],
}]);
Ad Tür Açıklama
all_frames boolean İsteğe bağlı. Varsayılan olarak false değerine ayarlanır, yani yalnızca üst kare eşleşir.

true belirtilirse kare, sekmenin en üstündeki kare olmasa bile tüm kareler içine eklenir. Her çerçeve, URL gereksinimleri açısından bağımsız olarak kontrol edilir. URL gereksinimleri karşılanmazsa alt çerçevelere eklenmez.

Uzantılar, eşleşen bir çerçeveyle ilgili olan ancak kendileri eşleşmeyen çerçevelerde komut dosyaları çalıştırmak isteyebilir. Eşleşen bir çerçeve tarafından oluşturulan URL'lere sahip ancak URL'leri komut dosyasının belirtilen kalıplarıyla eşleşmeyen çerçeveler için bu durumun yaygın bir senaryo olduğu durumlar.

Bu durum, bir uzantının about:, data:, blob: ve filesystem: şemalarına sahip URL'lere sahip çerçeveler eklemek istemesidir. Bu durumlarda URL, içerik komut dosyasının kalıbıyla eşleşmez (ve about: ve data: söz konusu olduğunda about:blank veya data:text/html,<html>Hello, World!</html>'da olduğu gibi üst URL'yi veya kaynağı URL'ye hiç dahil etmeyin). Ancak bu çerçeveler yine de oluşturma çerçevesiyle ilişkilendirilebilir.

Uzantılar, bu çerçevelere ekleme yapmak için manifestteki içerik komut dosyası spesifikasyonunda "match_origin_as_fallback" özelliğini belirtebilir.

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.google.com/*"],
      "match_origin_as_fallback": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Bu parametre belirtildiğinde ve true değerine ayarlandığında Chrome, çerçevenin URL'sine bakmak yerine, çerçevenin eşleşip eşleşmediğini belirlemek için çerçeveyi başlatanın kaynağına bakar. Bunun, hedef çerçevenin kaynakından da farklı olabileceğini unutmayın (ör. data: URL'nin kaynağı boş).

Çerçeveyi başlatan, hedef kareyi oluşturan veya bu çerçevede gezinen karedir. Bu genellikle doğrudan üst veya açıcı olsa da olmayabilir (bir iframe içindeki iframe'de gezinen bir çerçevede olduğu gibi).

Bu değer, başlatıcı çerçevesinin origin ile karşılaştırıldığından başlatan çerçevesi, söz konusu başlangıç noktasından herhangi bir yolda olabilir. Bu sonucun açık bir şekilde anlaşılması için Chrome, "match_origin_as_fallback" ile belirtilen içerik komut dosyalarının true olarak ayarlanmasını ve * yolunu belirtmesini gerektirir.

Hem "match_origin_as_fallback" hem de "match_about_blank" belirtildiğinde "match_origin_as_fallback" öncelikli olur.

Yerleştirme sayfasıyla ilgili iletişim

İçerik komut dosyalarının yürütme ortamları ve bunları barındıran sayfalar birbirinden izole olsa da sayfanın DOM'sine erişimi paylaşırlar. Sayfa, içerik komut dosyası veya içerik komut dosyası üzerinden uzantıyla iletişim kurmak istiyorsa bunu paylaşılan DOM üzerinden yapmalıdır.

window.postMessage() kullanılarak bir örnek oluşturulabilir:

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

Uzantı olmayan sayfa (example.html) kendisine mesaj gönderir. Bu mesaj, içerik komut dosyası tarafından engellenir ve incelenir, ardından uzantı işleminde yayınlanır. Bu şekilde sayfa, uzantı süreciyle bir iletişim hattı oluşturur. Bunun tersi de benzer yollarla mümkündür.

Uzantı dosyalarına erişme

İçerik komut dosyasından bir uzantı dosyasına erişmek için chrome.runtime.getURL() yöntemini çağırarak uzantı öğenizin mutlak URL'sini aşağıdaki örnekte (content.js) gösterildiği gibi alabilirsiniz:

content-script.js

let image = chrome.runtime.getURL("images/my_image.png")

Bir CSS dosyasında yazı tipi veya resim kullanmak için aşağıdaki örnekte (content.css) gösterildiği gibi bir URL oluşturmak amacıyla @@extension_id kullanabilirsiniz:

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

manifest.json dosyasında tüm öğeler web'den erişilebilen kaynaklar olarak beyan edilmelidir:

manifest.json

{
 ...
 "web_accessible_resources": [
   {
     "resources": [ "images/*.png" ],
     "matches": [ "https://example.com/*" ]
   },
   {
     "resources": [ "fonts/*.woff" ],
     "matches": [ "https://example.com/*" ]
   }
 ],
 ...
}

Güvende kalın

Yalıtılmış dünyalar bir koruma katmanı sağlarken, içerik komut dosyalarının kullanılması bir uzantıda ve web sayfasında güvenlik açıkları oluşturabilir. İçerik komut dosyası ayrı bir web sitesinden içerik alıyorsa (örneğin, fetch() yöntemini çağırarak) içeriği yerleştirmeden önce siteler arası komut dosyası saldırılarına karşı filtrelemeye dikkat edin. Yalnızca "man-in-the-middle" saldırılarından kaçınmak için HTTPS üzerinden iletişim kurun.

Kötü amaçlı web sayfalarını filtrelediğinizden emin olun. Örneğin, aşağıdaki kalıplar tehlikelidir ve Manifest V3'te izin verilmez:

Yapılmaması gerekenler

content-script.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
Yapılmaması gerekenler

content-script.js

const elmt_id = ...
// WARNING! elmt_id might be '); ... evil script ... //'!
window.setTimeout("animate(" + elmt_id + ")", 200);

Bunun yerine, komut dosyası çalıştırmayan daha güvenli API'leri tercih edin:

Yapılması gerekenler

content-script.js

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

content-script.js

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