कॉन्टेंट स्क्रिप्ट

कॉन्टेंट स्क्रिप्ट ऐसी फ़ाइलें होती हैं जो वेब पेजों से जुड़ी होती हैं. स्टैंडर्ड डॉक्यूमेंट ऑब्जेक्ट मॉडल (DOM) का इस्तेमाल करके, वे उन वेब पेजों की जानकारी पढ़ सकते हैं जिन पर ब्राउज़र जाता है. साथ ही, वे उनमें बदलाव कर सकते हैं और अपने पैरंट एक्सटेंशन को जानकारी भेज सकते हैं.

कॉन्टेंट के लिए स्क्रिप्ट की क्षमताओं को समझना

कॉन्टेंट स्क्रिप्ट, उन Chrome API को ऐक्सेस कर सकती हैं जिनका इस्तेमाल उनके पैरंट एक्सटेंशन के ज़रिए किया जा रहा है. वे एक्सटेंशन के साथ मैसेज की अदला-बदली कर सकते हैं. वे chrome.runtime.getURL() से, किसी एक्सटेंशन की फ़ाइल का यूआरएल भी ऐक्सेस कर सकते हैं और उसी नतीजे का इस्तेमाल कर सकते हैं जिसका इस्तेमाल दूसरे यूआरएल की मदद से किया जाता है.

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

इसके अलावा, कॉन्टेंट स्क्रिप्ट नीचे दिए गए chrome API को सीधे ऐक्सेस कर सकती है:

कॉन्टेंट स्क्रिप्ट, दूसरे एपीआई को सीधे ऐक्सेस नहीं कर सकतीं.

एकांत में काम करना

कॉन्टेंट स्क्रिप्ट एक अलग दुनिया में रहती हैं. इससे कॉन्टेंट स्क्रिप्ट, पेज या अन्य कॉन्टेंट स्क्रिप्ट से टकराव किए बिना, अपने JavaScript एनवायरमेंट में बदलाव कर सकती है.

नीचे दिए गए उदाहरण के जैसे कोड के साथ किसी वेब पेज पर एक्सटेंशन चल सकता है.

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

वह एक्सटेंशन, यहां दी गई कॉन्टेंट स्क्रिप्ट इंजेक्ट कर सकता है.

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

अगर बटन दबाया गया था, तो दोनों चेतावनियां दिखेंगी.

अलग-अलग दुनिया में कॉन्टेंट स्क्रिप्ट, एक्सटेंशन, और वेब पेज को दूसरों के बनाए गए किसी भी वैरिएबल या फ़ंक्शन को ऐक्सेस करने की अनुमति नहीं होती. इससे कॉन्टेंट स्क्रिप्ट को वह फ़ंक्शन चालू करने की सुविधा भी मिलती है जो वेब पेज पर नहीं होना चाहिए.

स्क्रिप्ट इंजेक्ट करें

कॉन्टेंट स्क्रिप्ट को प्रोग्राम के रूप में या डिक्लेरेटिव के तौर पर शामिल किया जा सकता है.

प्रोग्राम के हिसाब से इंजेक्ट करें

ऐसे कॉन्टेंट स्क्रिप्ट के लिए प्रोग्रामैटिक इंजेक्शन का इस्तेमाल करें जिसे खास मौकों पर चलाने की ज़रूरत होती है.

प्रोग्रामैटिक कॉन्टेंट की स्क्रिप्ट इंजेक्ट करने के लिए, मेनिफ़ेस्ट में activeTab अनुमति दें. इससे, चालू साइट के होस्ट को सुरक्षित ऐक्सेस मिलता है और टैब की अनुमति का कुछ समय के लिए ऐक्सेस मिलता है. इससे, क्रॉस-ऑरिजिन अनुमतियों के बिना, मौजूदा ऐक्टिव टैब पर कॉन्टेंट स्क्रिप्ट चलाने की सुविधा चालू हो जाती है.

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

कॉन्टेंट स्क्रिप्ट को कोड के तौर पर इंजेक्ट किया जा सकता है.

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

इसके अलावा, एक पूरी फ़ाइल को इंजेक्ट किया जा सकता है.

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

डिक्लेरेटिव तौर पर इंजेक्ट करें

ऐसे कॉन्टेंट स्क्रिप्ट के लिए डिक्लेरेटिव इंजेक्शन का इस्तेमाल करें जो तय किए गए पेजों पर अपने-आप चलने चाहिए.

डिक्लेरेटिव इंजेक्ट की गई स्क्रिप्ट, "content_scripts" फ़ील्ड के तहत मेनिफ़ेस्ट में रजिस्टर की जाती हैं. इनमें JavaScript फ़ाइलें, सीएसएस फ़ाइलें या दोनों शामिल हो सकते हैं. अपने-आप चलने वाली सभी कॉन्टेंट स्क्रिप्ट में, मिलते-जुलते पैटर्न तय होने चाहिए.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
नाम Type ब्यौरा
matches {: #matches } स्ट्रिंग का कलेक्शन ज़रूरी है. इससे पता चलता है कि यह कॉन्टेंट स्क्रिप्ट किन पेजों पर इंजेक्ट की जाएगी. इन स्ट्रिंग के सिंटैक्स के बारे में ज़्यादा जानकारी के लिए, मिलते-जुलते पैटर्न और यूआरएल हटाने का तरीका जानने के लिए, मिलते-जुलते पैटर्न और ग्लोब देखें.
css {: #css } स्ट्रिंग का कलेक्शन ज़रूरी नहीं है. सीएसएस फ़ाइलों की सूची, जिन्हें मिलते-जुलते पेजों में इंजेक्ट किया जाना है. इन्हें उसी क्रम में इंजेक्ट किया जाता है जिस क्रम में वे इस अरे में दिखते हैं. ऐसा, पेज के लिए किसी भी DOM को बनाने या दिखाने से पहले किया जाता है.
js {: #js } स्ट्रिंग का कलेक्शन ज़रूरी नहीं है. मिलते-जुलते पेजों में इंजेक्ट की जाने वाली JavaScript फ़ाइलों की सूची. इन्हें उसी क्रम में इंजेक्ट किया जाता है जिस क्रम में वे इस कलेक्शन में दिखते हैं.
match_about_blank {: #match_about_blank } boolean ज़रूरी नहीं है. क्या स्क्रिप्ट को किसी about:blank फ़्रेम में इंजेक्ट करना चाहिए, जहां पैरंट या ओपनर फ़्रेम, matches में बताए गए किसी एक पैटर्न से मेल खाता है. डिफ़ॉल्ट तौर पर, यह वैल्यू false होती है.

मैच और ग्लोब को शामिल न करें

मेनिफ़ेस्ट रजिस्ट्रेशन में नीचे दिए गए फ़ील्ड शामिल करके, बताए गए पेज को मैच कराने की सुविधा को अपनी पसंद के मुताबिक बनाया जा सकता है.

नाम Type ब्यौरा
exclude_matches {: #excluded_matches } स्ट्रिंग का कलेक्शन ज़रूरी नहीं है. ऐसे पेजों को शामिल नहीं करता जिनमें इस कॉन्टेंट स्क्रिप्ट को शामिल किया जाता है. इन स्ट्रिंग के सिंटैक्स पर ज़्यादा जानकारी के लिए, मैच पैटर्न देखें.
include_globs {: #include_grobs } स्ट्रिंग का कलेक्शन ज़रूरी नहीं है. सिर्फ़ इस ग्लोब से मेल खाने वाले यूआरएल को शामिल करने के लिए, matches के बाद लागू किया गया. इसका मकसद, @include Greesmonkey कीवर्ड को एम्युलेट करना है.
exclude_globs {: #excluded_glbs } स्ट्रिंग का कलेक्शन ज़रूरी नहीं है. इस ग्लोब से मेल खाने वाले यूआरएल को बाहर रखने के लिए, matches के बाद लागू किया गया. इसका मकसद, @excludeGriesmonkey के कीवर्ड को एम्युलेट करना है.

अगर कॉन्टेंट स्क्रिप्ट का यूआरएल किसी भी matches पैटर्न और किसी भी include_globs पैटर्न से मेल खाता है, तो कॉन्टेंट स्क्रिप्ट को पेज में इंजेक्ट किया जाएगा. ऐसा तब तक होगा, जब तक यूआरएल भी exclude_matches या exclude_globs पैटर्न से मेल न खाता हो.

matches प्रॉपर्टी ज़रूरी है, इसलिए exclude_matches, include_globs, और exclude_globs का इस्तेमाल सिर्फ़ यह तय करने के लिए किया जा सकता है कि किन पेजों पर असर पड़ेगा.

नीचे दिया गया एक्सटेंशन, कॉन्टेंट स्क्रिप्ट को http://www.nytimes.com/ health में इंजेक्ट करेगा, लेकिन http://www.nytimes.com/ business में नहीं .

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

ग्लोब प्रॉपर्टी, मैच पैटर्न के मुकाबले अलग, ज़्यादा सुविधाजनक सिंटैक्स को फ़ॉलो करती हैं. स्वीकार किए जाने वाले ग्लोब स्ट्रिंग ऐसे यूआरएल होते हैं जिनमें "वाइल्डकार्ड" तारे के निशान और सवाल के निशान हो सकते हैं. तारे का निशान *, खाली स्ट्रिंग सहित किसी भी लंबाई की किसी भी स्ट्रिंग से मेल खाता है, जबकि प्रश्न चिह्न ? किसी एक वर्ण से मेल खाता है.

उदाहरण के लिए, ग्लॉब http:// br .example.com/foo/ * इनमें से किसी से भी मेल खाता है:

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

हालांकि, यह नीचे दी गई जानकारी से मेल नहीं खाता:

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

यह एक्सटेंशन, कॉन्टेंट स्क्रिप्ट को http:/www.nytimes.com/ art /index.html और http://www.nytimes.com/ Jobs /index.html में इंजेक्ट करेगा, लेकिन http://www.nytimes.com/ sports /index.html में नहीं.

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

यह एक्सटेंशन, कॉन्टेंट स्क्रिप्ट को http:// history .nytimes.com और http://.nytimes.com/ इतिहास में इंजेक्ट करेगा. हालांकि, http:// Science .nytimes.com या http://www.nytimes.com/ Science में ऐसा नहीं करेगा.

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

सही दायरा हासिल करने के लिए, इनमें से सभी या इनमें से कुछ को शामिल किया जा सकता है.

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

रनटाइम

जब JavaScript फ़ाइलों को वेब पेज में इंजेक्ट किया जाता है, तो उन्हें run_at फ़ील्ड से कंट्रोल किया जाता है. पहले से फ़्लैग किया गया और डिफ़ॉल्ट फ़ील्ड "document_idle" है. हालांकि, ज़रूरत पड़ने पर इसे "document_start" या "document_end" के तौर पर भी बताया जा सकता है.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
नाम Type ब्यौरा
document_idle {: #document_idle } स्ट्रिंग पसंदीदा. जहां भी हो सके, "document_idle" का इस्तेमाल करें.

ब्राउज़र, "document_end" से लेकर windowonload इवेंट के चालू होने के तुरंत बाद, स्क्रिप्ट इंजेक्ट करने का समय चुनता है. इंजेक्ट करने का सटीक समय, इस बात पर निर्भर करता है कि दस्तावेज़ कितना मुश्किल है और उसे लोड होने में कितना समय लग रहा है. साथ ही, इसे पेज लोड होने की स्पीड के लिए ऑप्टिमाइज़ किया गया है.

"document_idle" पर चल रही कॉन्टेंट स्क्रिप्ट के लिए, window.onload इवेंट सुनने की ज़रूरत नहीं है. यह गारंटी है कि डीओएम के पूरा होने के बाद ही वे काम करेंगी. अगर किसी स्क्रिप्ट को window.onload के बाद चलाना ज़रूरी है, तो एक्सटेंशन यह जांच कर सकता है कि document.readyState प्रॉपर्टी का इस्तेमाल करके, onload पहले ही ट्रिगर हो चुका है या नहीं.
document_start {: #document_start } स्ट्रिंग css में मौजूद किसी भी फ़ाइल के बाद स्क्रिप्ट इंजेक्ट की जाती हैं. हालांकि, कोई दूसरा DOM बनाने या कोई दूसरी स्क्रिप्ट चलाने से पहले.
document_end {: #document_end } स्ट्रिंग डीओएम पूरा होने के तुरंत बाद, लेकिन इमेज और फ़्रेम जैसे सबरिसॉर्स के लोड होने से पहले स्क्रिप्ट को इंजेक्ट किया जाता है.

फ़्रेम तय करें

"all_frames" फ़ील्ड की मदद से एक्सटेंशन यह तय कर सकता है कि JavaScript और सीएसएस फ़ाइलों को, बताए गए यूआरएल की ज़रूरी शर्तों से मेल खाने वाले सभी फ़्रेम में इंजेक्ट किया जाए या किसी टैब में सबसे ऊपर वाले फ़्रेम में.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
नाम Type ब्यौरा
all_frames {: #all_frames } boolean ज़रूरी नहीं है. डिफ़ॉल्ट तौर पर, यह false पर सेट होता है. इसका मतलब है कि सिर्फ़ टॉप फ़्रेम मैच करता है.

अगर true को चुना गया है, तो इसे सभी फ़्रेम में इंजेक्ट किया जाएगा, भले ही फ़्रेम टैब में सबसे ऊपर वाला फ़्रेम न हो. यूआरएल की ज़रूरी शर्तों के लिए, हर फ़्रेम की अलग से जांच की जाती है. अगर यूआरएल की ज़रूरी शर्तें पूरी नहीं होती हैं, तो उसे चाइल्ड फ़्रेम में इंजेक्ट नहीं किया जाएगा.

एम्बेड किए गए पेज से कम्यूनिकेशन

कॉन्टेंट स्क्रिप्ट और उन्हें होस्ट करने वाले पेजों के काम करने के एनवायरमेंट एक-दूसरे से अलग होते हैं, लेकिन पेज के DOM का ऐक्सेस शेयर करते हैं. अगर पेज, कॉन्टेंट स्क्रिप्ट या कॉन्टेंट स्क्रिप्ट के ज़रिए एक्सटेंशन के साथ इंटरैक्ट करना चाहता है, तो शेयर किए गए DOM के ज़रिए ऐसा करना होगा.

ऐसा करने के लिए, 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);

बिना एक्सटेंशन वाला पेज, example.html, मैसेज को खुद ही पोस्ट करता है. इस मैसेज को कॉन्टेंट स्क्रिप्ट ने रोक लिया और उसकी जांच की. इसके बाद, इसे एक्सटेंशन प्रोसेस में पोस्ट कर दिया गया. इस तरह, पेज, एक्सटेंशन प्रोसेस से कम्यूनिकेशन की एक लाइन तय करता है. इसी तरह के दूसरे तरीकों से गलत तरीके से नतीजे दिखाए जा सकते हैं.

सुरक्षित रहें

अलग-अलग दुनिया में कॉन्टेंट की सुरक्षा एक स्तर की सुरक्षा देती है, लेकिन कॉन्टेंट स्क्रिप्ट का इस्तेमाल करने से, किसी एक्सटेंशन और वेब पेज में जोखिम की आशंकाएं पैदा हो सकती हैं. अगर कॉन्टेंट स्क्रिप्ट को किसी अलग वेबसाइट से कॉन्टेंट मिलता है, जैसे कि XMLHttpRequest, तो कॉन्टेंट इंजेक्ट करने से पहले, उसे क्रॉस-साइट स्क्रिप्टिंग हमलों से फ़िल्टर कर लें. "man-in-the-middle" के हमलों से बचने के लिए, सिर्फ़ एचटीटीपीएस पर बातचीत करें.

नुकसान पहुंचाने वाले वेब पेजों को फ़िल्टर करना न भूलें. उदाहरण के लिए, यहां दिए गए पैटर्न खतरनाक हैं:

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

इसके बजाय, उन सुरक्षित एपीआई को प्राथमिकता दें जो स्क्रिप्ट नहीं चलाते:

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