İç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:
dom
i18n
storage
runtime.connect()
runtime.getManifest()
runtime.getURL()
runtime.id
runtime.onConnect
runtime.onMessage
runtime.sendMessage()
İç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 |
|
İ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:
- İçerik komut dosyalarını kaydedin.
- Kayıtlı içerik komut dosyalarının listesini alın.
- Kayıtlı içerik komut dosyalarının listesini güncelleyin.
- Kayıtlı içerik komut dosyalarını kaldırabilir.
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üminclude_globs
kalıbıyla eşleşir. - URL, bir
exclude_matches
veyaexclude_globs
kalıbıyla da eşleşmiyor.matches
özelliği zorunlu olduğundan,exclude_matches
,include_globs
veexclude_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. |
İlgili çerçevelere ekle
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:
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);
Bunun yerine, komut dosyası çalıştırmayan daha güvenli API'leri tercih edin:
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);