İçerik komut dosyaları, web sayfaları bağlamında çalışan dosyalardır. Standart Belge Nesnesi Modeli'ni (DOM) kullanarak tarayıcının ziyaret ettiği web sayfalarının ayrıntılarını okuyabilir, bu sayfalarda değişiklik yapabilir ve üst uzantılarına bilgi aktarabilirler.
İçerik komut dosyası özelliklerini anlama
İçerik komut dosyaları aşağıdaki uzantı API'lerine doğrudan erişebilir:
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 bu bilgilere dolaylı olarak erişebilirler.
fetch()
gibi API'leri kullanarak içerik komut dosyasından uzantınızdaki diğer dosyalara da erişebilirsiniz. Bunun için bu kaynakları web'den erişilebilir kaynaklar olarak belirtmeniz gerekir. Bu işlemin, kaynakları aynı sitede çalışan tüm birinci taraf veya üçüncü taraf komut dosyalarına da maruz bıraktığını unutmayın.
İzole edilmiş dünyalarda çalışma
İçerik komut dosyaları, izole bir dünyada bulunur. Bu sayede, içerik komut dosyaları sayfa veya diğer eklentilerin içerik komut dosyalarıyla çakışma olmadan JavaScript ortamında değişiklik yapabilir.
Bir uzantı, aşağıdaki örneğe benzer kod içeren bir web sayfasında ç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ı yerleştirme
İçerik komut dosyaları statik olarak tanımlanabilir, dinamik olarak tanımlanabilir veya programlı olarak enjekte edilebilir.
Statik beyanlarla 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ı beyanları kullanın.
Statik olarak tanımlanan komut dosyaları, manifest dosyasında "content_scripts"
anahtarı altında kaydedilir.
Bunlar JavaScript dosyaları, CSS dosyaları veya her ikisi olabilir. Tüm otomatik çalıştırılan içerik komut dosyaları eşleme kalıplarını 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 ekleneceğini belirtir. Bu dizelerin söz dizimi hakkında ayrıntılı bilgi için Eşleşme kalıpları başlıklı makaleyi, URL'lerin nasıl hariç tutulacağı hakkında bilgi için Eşleşme kalıpları ve genel eşlemeler başlıklı makaleyi inceleyin. |
css |
dize dizisi | İsteğe bağlıdır. 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 dizgede göründükleri sırada eklenir. |
js |
|
İsteğe bağlıdır. Eşleşen sayfalara eklenecek JavaScript dosyalarının listesi. Dosyalar bu dizgede göründükleri sırayla eklenir. Bu listedeki her dize, uzantının kök dizininde bulunan bir kaynağa yönlendiren göreli bir yol içermelidir. Baştaki eğik çizgiler ("/") otomatik olarak kırpılır. |
run_at |
RunAt | İsteğe bağlıdır. Komut dosyasının sayfaya ne zaman ekleneceğini belirtir. Varsayılan olarak document_idle değerine ayarlanır. |
match_about_blank |
boolean | İsteğe bağlıdır. Komut dosyasının, üst veya açıcı çerçevenin matches içinde tanımlanan kalıplardan biriyle eşleştiği bir about:blank çerçevesine eklenip eklenmeyeceği. Varsayılan değer yanlıştır. |
match_origin_as_fallback |
boolean |
İsteğe bağlıdır. Komut dosyasının, eşleşen bir kaynak tarafından oluşturulan ancak URL'si veya kaynağı doğrudan kalıpla eşleşmeyebilecek çerçevelere eklenip eklenmeyeceği. Bunlara about: , data: , blob: ve filesystem: gibi farklı şemalara sahip çerçeveler dahildir. Ayrıca İlgili çerçevelere kod yerleştirme başlıklı makaleyi de inceleyin.
|
world |
ExecutionWorld |
İsteğe bağlıdır. Bir komut dosyasının çalışacağı JavaScript dünyası. Varsayılan olarak ISOLATED değerine ayarlanır. Ayrıca Bağımsız dünyalarda çalışma başlıklı makaleyi de inceleyin.
|
Dinamik beyanlarla ekleme yapma
Dinamik içerik komut dosyaları, içerik komut dosyalarının eşleşme kalıpları iyi bilinmediğinde veya içerik komut dosyalarının her zaman bilinen ana makinelere yerleştirilmemesi gerektiğinde kullanışlıdır.
Chrome 96'da kullanıma sunulan dinamik beyanlar statik beyanlara benzer ancak içerik komut dosyası nesnesi, manifest.json yerine chrome.scripting
ad alanındaki yöntemler kullanılarak Chrome'a kaydedilir. Komut Dosyası API'si, uzantı geliştiricilerine şunları da sağlar:
- İç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ırın.
Statik bildirimler gibi dinamik bildirimler de JavaScript dosyaları, CSS dosyaları veya her ikisi de 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"));
Programatik olarak ekleme
Etkinliklere veya belirli durumlarda çalıştırılması gereken içerik komut dosyaları için programatik enjeksiyon kullanın.
Bir içerik komut dosyasını programatik olarak yerleştirmek için eklentinizin, komut dosyası yerleştirmeye çalıştığı sayfa için barındırma izinlerine ihtiyacı vardır. Ana makine izinleri, uzantınızın manifest'i kapsamında isteyerek veya geçici olarak "activeTab"
kullanarak 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"]
});
});
Ayrıca, bir işlev gövdesi içerik komut dosyası olarak enjekte edilebilir ve 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,
});
});
Enjekte edilen işlevin, orijinal işlevin kendisi değil, chrome.scripting.executeScript()
çağrısında referans verilen işlevin bir kopyası olduğunu unutmayın. Bu nedenle, işlevin gövdesi kendi kendine yetmelidir. İşlevin dışındaki değişkenlere yapılan referanslar, içerik komut dosyasının ReferenceError
hatası vermesine neden olur.
İşlev olarak eklerken işleve bağımsız değişkenler de aktarabilirsiniz.
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 genel eşlemelerini hariç tutma
Belirtilen sayfa eşleşmesini özelleştirmek için aşağıdaki alanları açıklayıcı bir kayda ekleyin.
Ad | Tür | Açıklama |
---|---|---|
exclude_matches |
dize dizisi | İsteğe bağlıdır. Bu içerik komut dosyasının aksi takdirde yerleştirileceği sayfaları hariç tutar. Bu dizelerin söz dizimi hakkında ayrıntılı bilgi için Eşleşme Kalıpları başlıklı makaleyi inceleyin. |
include_globs |
dize dizisi | İsteğe bağlıdır. Yalnızca bu genel ifadeyle eşleşen URL'leri dahil etmek için matches 'ten sonra uygulanır. Bu, @include Greasemonkey anahtar kelimesini taklit etmek için tasarlanmıştır. |
exclude_globs |
dize dizisi | İsteğe bağlıdır. Bu genel ifadeyle eşleşen URL'leri hariç tutmak için matches 'ten sonra uygulanır. @exclude
Greasemonkey anahtar kelimesini taklit etmek için tasarlanmıştır. |
İçerik komut dosyası, aşağıdakilerin her ikisi de doğruysa bir sayfaya yerleştirilir:
- URL'si herhangi bir
matches
kalıbıyla ve herhangi birinclude_globs
kalıbıyla eşleşir. - URL,
exclude_matches
veyaexclude_globs
kalıplarıyla da eşleşmiyor.matches
özelliği zorunlu olduğundanexclude_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 yerleştirir ancak https://www.nytimes.com/business
içine yerleştirmez .
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" ],
}]);
Glob özellikleri, eşleme kalıplarından farklı ve daha esnek bir söz dizimi kullanır. Kabul edilen genel dize, "joker karakter" yıldız işaretleri ve soru işaretleri içerebilen URL'lerdir. Yıldız işareti (*
), boş dize dahil olmak üzere herhangi bir uzunluktaki dizelerle eşleşirken soru işareti (?
) herhangi bir tek karakterle eşleşir.
Örneğin, https://???.example.com/foo/\*
genel ifadesi aşağıdakilerden 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*
'e enjekte eder ancak https://www.nytimes.com/sports/index.html
'ye enjekte etmez:
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
'e enjekte eder ancak https://science.nytimes.com
veya https://www.nytimes.com/science
'a enjekte etmez:
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 bazıları 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"
. 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 edilen. Mümkün olduğunda "document_idle" kullanın.Tarayıcı, "document_end" ile window.onload
etkinliğinin hemen sonrasındaki zaman aralığında komut dosyaları yerleştirmek için bir zaman seçer. Tam enjeksiyon anı, belgenin ne kadar karmaşık olduğuna ve yüklenmesinin ne kadar sürdüğüne bağlıdır ve sayfa yükleme hızı için optimize edilir."document_idle" zamanında çalışan içerik komut dosyalarının window.onload etkinliğini dinlemesi gerekmez. Bu komut dosyalarının DOM tamamlandıktan sonra çalışacağı garanti edilir. Bir komut dosyasının window.onload 'ten sonra çalıştırılmasının kesinlikle gerekli olduğu durumlarda uzantı, document.readyState özelliğini kullanarak onload 'un tetiklenip tetiklenmediğini kontrol edebilir. |
document_start |
dize | Komut dosyaları, css 'deki dosyalardan sonra ancak başka bir DOM oluşturulmadan veya başka bir komut dosyası çalıştırılmadan önce eklenir. |
document_end |
dize | Komut dosyaları, DOM tamamlandıktan hemen sonra ancak resim ve çerçeve gibi alt kaynakların yüklenmesinden önce eklenir. |
Çerçeveleri belirtme
Manifestte belirtilen açıklayıcı içerik komut dosyaları için "all_frames"
alanı, uzantının JavaScript ve CSS dosyalarının belirtilen URL koşullarını karşılayan tüm çerçevelere mi yoksa yalnızca sekmedeki en üst çerçeveye mi ekleneceğini belirtmesine olanak tanır:
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
İçerik komut dosyalarını chrome.scripting.registerContentScripts(...)
kullanarak programatik olarak kaydederken allFrames
parametresi, içerik komut dosyasının belirtilen URL koşullarını karşılayan tüm çerçevelere mi yoksa yalnızca bir sekmedeki en üst çerçeveye mi ekleneceğini belirtmek için kullanılabilir. Bu yalnızca tabId ile kullanılabilir ve frameIds veya documentIds belirtilmişse kullanılamaz:
service-worker.js
chrome.scripting.registerContentScripts([{
id: "test",
matches : [ "https://*.nytimes.com/*" ],
allFrames : true,
js : [ "contentScript.js" ],
}]);
İlgili çerçevelere ekleme
Uzantılar, eşleşen bir çerçeveyle ilişkili ancak eşleşmeyen çerçevelerde komut dosyaları çalıştırmak isteyebilir. Bu durumun yaşandığı yaygın bir senaryo, eşleşen bir çerçeve tarafından oluşturulan ancak URL'leri komut dosyasının belirtilen kalıplarıyla eşleşmeyen URL'lere sahip çerçevelerdir.
Bu durum, bir uzantının about:
, data:
, blob:
ve filesystem:
düzenleri içeren URL'leri çerçevelere eklemek istediğinde ortaya çıkar. Bu durumlarda, URL içerik komut dosyasının kalıbıyla eşleşmez (about:
ve data:
durumunda, about:blank
veya data:text/html,<html>Hello, World!</html>
'ta olduğu gibi URL'ye üst URL'yi veya kaynağı hiç dahil etmez). Ancak bu çerçeveler, oluşturan çerçeveyle ilişkilendirilmeye devam edebilir.
Uzantılar, bu çerçevelere içerik eklemek için manifest'teki bir içerik komut dosyası spesifikasyonunda "match_origin_as_fallback"
mülkünü belirtebilir.
manifest.json
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["https://*.google.com/*"],
"match_origin_as_fallback": true,
"js": ["contentScript.js"]
}
],
...
}
Belirtilip true
olarak ayarlandığında Chrome, karenin eşleşip eşleşmediğini belirlemek için karenin URL'si yerine kareyi başlatan öğenin kaynağına bakar. Bunun, hedef çerçevenin kökeninden (ör. data:
URL'leri null bir kaynağa sahiptir).
Çerçevenin başlatıcısı, hedef çerçeveyi oluşturan veya bu çerçeveye giden çerçevedir. Bu genellikle doğrudan üst öğe veya açan öğe olsa da öyle olmayabilir (iframe içinde bir iframe'de gezinen bir çerçeve durumunda olduğu gibi).
Bu işlem, başlatıcı çerçevenin kaynağını karşılaştırdığından başlatıcı çerçeve, bu kaynaktan gelen herhangi bir yolda olabilir. Bu sonucun net olması için Chrome, "match_origin_as_fallback"
ile belirtilen tüm içerik komut dosyalarının true
olarak ayarlanmasının yanı sıra *
yolunu da belirtmesini zorunlu kılar.
Hem "match_origin_as_fallback"
hem de "match_about_blank"
belirtildiğinde "match_origin_as_fallback"
önceliklidir.
Yerleştirme sayfasıyla iletişim
İçerik komut dosyalarının yürütme ortamları ve bunları barındıran sayfalar birbirinden izole olsa da sayfanın DOM'una erişimi paylaşırlar. Sayfa, içerik komut dosyasıyla veya içerik komut dosyası üzerinden uzantı ile iletişim kurmak istiyorsa bunu paylaşılan DOM üzerinden yapmalıdır.
window.postMessage()
kullanılarak bir örnek verilebilir:
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 example.html sayfası, kendisine mesaj gönderir. Bu ileti, içerik komut dosyası tarafından yakalanıp incelenir ve ardından uzantı işlemine gönderilir. Bu sayede sayfa, uzantı süreciyle iletişim hattı oluşturur. Benzer yöntemlerle tersini de yapabilirsiniz.
Uzatma dosyalarına erişme
Bir içerik komut dosyasından uzantı dosyasına erişmek için aşağıdaki örnekte (content.js
) gösterildiği gibi uzantı öğenizin mutlak URL'sini almak üzere chrome.runtime.getURL()
işlevini çağırabilirsiniz:
content-script.js
let image = chrome.runtime.getURL("images/my_image.png")
CSS dosyasında yazı tipleri veya resimler kullanmak için aşağıdaki örnekte (content.css
) gösterildiği gibi bir URL oluşturmak üzere @@extension_id
seçeneğini 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');
}
Tüm öğeler manifest.json
dosyasında web'e erişilebilir kaynaklar olarak tanımlanmalıdır:
manifest.json
{
...
"web_accessible_resources": [
{
"resources": [ "images/*.png" ],
"matches": [ "https://example.com/*" ]
},
{
"resources": [ "fonts/*.woff" ],
"matches": [ "https://example.com/*" ]
}
],
...
}
Güvende kalın
İzole dünyalar bir koruma katmanı sağlarken içerik komut dosyalarının kullanılması, uzantı ve web sayfasında güvenlik açıkları oluşturabilir. İçerik komut dosyası, fetch()
çağrısı yaparak ayrı bir web sitesinden içerik alıyorsa içeriği eklemeden önce siteler arası komut dosyası çalıştırma saldırılarına karşı filtrelediğinizden emin olun. "man-in-the-middle" saldırılarını önlemek için yalnızca 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);