मैसेज पास करना

कॉन्टेंट स्क्रिप्ट वेब पेज के संदर्भ में चलती हैं, न कि उन्हें चलाने वाले एक्सटेंशन के बारे में. इस वजह से, उन्हें बाकी एक्सटेंशन के साथ इंटरैक्ट करने के तरीकों की ज़रूरत होती है. उदाहरण के लिए, आरएसएस रीडर एक्सटेंशन, किसी पेज पर आरएसएस फ़ीड मौजूद होने का पता लगाने के लिए, कॉन्टेंट स्क्रिप्ट का इस्तेमाल कर सकता है. इसके बाद, सर्विस वर्कर को उस पेज के लिए कार्रवाई आइकॉन दिखाने के लिए सूचना दी जा सकती है.

इस कम्यूनिकेशन में मैसेज भेजने का इस्तेमाल किया जाता है. इससे एक्सटेंशन और कॉन्टेंट स्क्रिप्ट, दोनों को एक-दूसरे के मैसेज सुनने और एक ही चैनल पर जवाब देने की सुविधा मिलती है. मैसेज में कोई भी मान्य JSON ऑब्जेक्ट (शून्य, बूलियन, नंबर, स्ट्रिंग, अरे या ऑब्जेक्ट) हो सकता है. मैसेज पास करने वाले दो एपीआई हैं: एक एक बार के अनुरोधों के लिए और दूसरा, लंबे समय तक चलने वाले कनेक्शन के लिए ज़्यादा जटिल होता है, जिससे एक से ज़्यादा मैसेज भेजे जा सकते हैं. एक्सटेंशन के बीच मैसेज भेजने के बारे में जानकारी पाने के लिए, क्रॉस-एक्सटेंशन मैसेज सेक्शन देखें.

एक बार किए जाने वाले अनुरोध

अपने एक्सटेंशन के किसी दूसरे हिस्से पर एक मैसेज भेजने और जवाब पाने के लिए, runtime.sendMessage() या tabs.sendMessage() पर कॉल करें. इन तरीकों से, कॉन्टेंट स्क्रिप्ट से एक्सटेंशन या एक्सटेंशन से कॉन्टेंट स्क्रिप्ट पर, एक बार JSON-सीरियलाइज़ किया जा सकने वाला मैसेज भेजा जा सकता है. रिस्पॉन्स को मैनेज करने के लिए, लौटाए गए प्रॉमिस का इस्तेमाल करें. पुराने एक्सटेंशन के साथ पुराने एक्सटेंशन के साथ काम करने के लिए, आपके पास कॉलबैक को आखिरी आर्ग्युमेंट के तौर पर पास करने का विकल्प होता है. एक ही कॉल में, प्रॉमिस और कॉलबैक का इस्तेमाल नहीं किया जा सकता.

कॉलबैक को प्रॉमिस में बदलने और उनका एक्सटेंशन में इस्तेमाल करने के बारे में जानकारी के लिए, मेनिफ़ेस्ट V3 माइग्रेशन गाइड देखें.

किसी कॉन्टेंट स्क्रिप्ट से अनुरोध भेजना ऐसा दिखता है:

content-script.js:

(async () => {
  const response = await chrome.runtime.sendMessage({greeting: "hello"});
  // do something with response here, not outside the function
  console.log(response);
})();

किसी कॉन्टेंट स्क्रिप्ट पर अनुरोध भेजने के लिए, बताएं कि वह अनुरोध किस टैब पर लागू होता है, जैसा कि यहां दिखाया गया है. यह उदाहरण सर्विस वर्कर, पॉप-अप, और टैब के तौर पर खोले गए chrome-extension:// पेजों पर काम करता है.

(async () => {
  const [tab] = await chrome.tabs.query({active: true, lastFocusedWindow: true});
  const response = await chrome.tabs.sendMessage(tab.id, {greeting: "hello"});
  // do something with response here, not outside the function
  console.log(response);
})();

मैसेज पाने के लिए, runtime.onMessage इवेंट लिसनर सेट अप करें. इनसे एक्सटेंशन और कॉन्टेंट स्क्रिप्ट, दोनों में एक ही कोड का इस्तेमाल होता है:

content-script.js या service-worker.js:

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting === "hello")
      sendResponse({farewell: "goodbye"});
  }
);

पिछले उदाहरण में, sendResponse() को सिंक्रोनस रूप से कॉल किया गया था. sendResponse() को एसिंक्रोनस तरीके से इस्तेमाल करने के लिए, return true; को onMessage इवेंट हैंडलर में जोड़ें.

अगर कई पेज पर onMessage इवेंट का डेटा मौजूद है, तो किसी खास इवेंट के लिए sendResponse() को सबसे पहले कॉल करने वाला व्यक्ति ही जवाब भेज पाएगा. उस इवेंट के अन्य सभी जवाबों को अनदेखा कर दिया जाएगा.

लंबे समय तक चले कनेक्शन

लंबे समय तक इस्तेमाल किया जा सकने वाला मैसेज भेजने वाला चैनल बनाने के लिए, कॉन्टेंट स्क्रिप्ट से मैसेज को एक्सटेंशन पेज पर पास करने के लिए, runtime.connect() को कॉल करें. इसके अलावा, एक्सटेंशन पेज से कॉन्टेंट स्क्रिप्ट पर मैसेज भेजने के लिए, tabs.connect() को कॉल करें. कनेक्शन के अलग-अलग प्रकारों में अंतर करने के लिए अपने चैनल को एक नाम दिया जा सकता है.

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

कनेक्शन बनाते समय, हर एंड को उस कनेक्शन से मैसेज भेजने और पाने के लिए, एक runtime.Port ऑब्जेक्ट असाइन किया जाता है.

कॉन्टेंट की स्क्रिप्ट से चैनल खोलने और मैसेज भेजने और सुनने के लिए, इस कोड का इस्तेमाल करें:

content-script.js:

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question === "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question === "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

एक्सटेंशन से कॉन्टेंट स्क्रिप्ट पर अनुरोध भेजने के लिए, पिछले उदाहरण में runtime.connect() पर कॉल की जगह tabs.connect() लिखें.

कॉन्टेंट स्क्रिप्ट या एक्सटेंशन पेज के इनकमिंग कनेक्शन को मैनेज करने के लिए, runtime.onConnect इवेंट लिसनर सेट अप करें. जब आपके एक्सटेंशन का कोई दूसरा हिस्सा connect() को कॉल करता है, तो यह इस इवेंट और runtime.Port ऑब्जेक्ट को चालू कर देता है. इनकमिंग कनेक्शन का जवाब देने के लिए कोड ऐसा दिखेगा:

service-worker.js:

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name === "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke === "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer === "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer === "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

पोर्ट लाइफ़टाइम

पोर्ट को, एक्सटेंशन के अलग-अलग हिस्सों के बीच दो-तरफ़ा कम्यूनिकेशन के तरीके के तौर पर डिज़ाइन किया जाता है. टॉप-लेवल फ़्रेम, किसी एक्सटेंशन का सबसे छोटा हिस्सा होता है, जो पोर्ट का इस्तेमाल कर सकता है. जब एक्सटेंशन का कोई हिस्सा tabs.connect(), runtime.connect() या runtime.connectNative() को कॉल करता है, तो यह एक पोर्ट बनाता है, जो postMessage() का इस्तेमाल करके तुरंत मैसेज भेज सकता है.

अगर किसी टैब में एक से ज़्यादा फ़्रेम हैं, तो tabs.connect() को कॉल करने से, टैब में मौजूद हर फ़्रेम के लिए, runtime.onConnect इवेंट एक बार शुरू होगा. इसी तरह, अगर runtime.connect() को कॉल किया जाता है, तो onConnect इवेंट, एक्सटेंशन प्रोसेस के हर फ़्रेम के लिए एक बार फ़ायर हो सकता है.

कनेक्शन बंद होने का समय पता किया जा सकता है. उदाहरण के लिए, अगर हर पोर्ट के लिए अलग-अलग राज्यों का रखरखाव किया जा रहा है. ऐसा करने के लिए, runtime.Port.onDisconnect इवेंट सुनें. यह इवेंट तब ट्रिगर होता है, जब चैनल के दूसरे सिरे पर कोई मान्य पोर्ट नहीं होता. इसकी ये वजहें हो सकती हैं:

  • वहीं, runtime.onConnect के लिए कोई लिसनर नहीं है.
  • पोर्ट वाले टैब को अनलोड कर दिया जाता है. उदाहरण के लिए, अगर टैब को नेविगेट किया जा रहा हो.
  • जिस फ़्रेम पर connect() को कॉल किया गया था वह अनलोड हो गया है.
  • runtime.onConnect के ज़रिए, पोर्ट मिलने वाले सभी फ़्रेम अनलोड हो गए हैं.
  • runtime.Port.disconnect() को दूसरे व्यक्ति से कॉल किया जा रहा है. अगर किसी connect() कॉल के जवाब में, डेटा पाने वाले व्यक्ति को एक से ज़्यादा पोर्ट मिलते हैं और disconnect() कॉल किया जाता है, तो onDisconnect इवेंट सिर्फ़ भेजने वाले पोर्ट पर ट्रिगर होता है, दूसरे पोर्ट पर नहीं.

क्रॉस-एक्सटेंशन मैसेज सेवा

अपने एक्सटेंशन में अलग-अलग कॉम्पोनेंट के बीच मैसेज भेजने के साथ-साथ, अन्य एक्सटेंशन के साथ संपर्क करने के लिए, मैसेजिंग एपीआई का इस्तेमाल किया जा सकता है. इससे आपको दूसरे एक्सटेंशन के इस्तेमाल के लिए, एक सार्वजनिक एपीआई दिख सकता है.

दूसरे एक्सटेंशन से आने वाले अनुरोधों और कनेक्शन को सुनने के लिए, runtime.onMessageExternal या runtime.onConnectExternal तरीकों का इस्तेमाल करें. यहां हर एक उदाहरण के बारे में बताया गया है:

service-worker.js (सर्विस-worker.js)

// For a single request:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id === blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

किसी दूसरे एक्सटेंशन को मैसेज भेजने के लिए, उस एक्सटेंशन का आईडी इस तरह पास करें जिससे आपको संपर्क करना है:

service-worker.js (सर्विस-worker.js)

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// For a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// For a long-lived connection:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

वेब पेजों से मैसेज भेजना

एक्सटेंशन, अन्य वेब पेजों से मैसेज पा सकते हैं और उनका जवाब भी दे सकते हैं. हालांकि, ये वेब पेजों पर मैसेज नहीं भेज सकते. किसी वेब पेज से एक्सटेंशन पर मैसेज भेजने के लिए, "externally_connectable" मेनिफ़ेस्ट कुंजी का इस्तेमाल करके अपने manifest.json में बताएं कि आपको किन वेबसाइटों से मैसेज भेजना है. उदाहरण के लिए:

manifest.json

"externally_connectable": {
  "matches": ["https://*.example.com/*"]
}

इससे, मैसेजिंग एपीआई को ऐसे किसी भी पेज पर दिखाया जाता है जो आपके बताए गए यूआरएल पैटर्न से मेल खाता है. यूआरएल पैटर्न में कम से कम सेकंड-लेवल डोमेन होना चाहिए. इसका मतलब है कि "*", "*.com", "*.co.uk", और "*.appspot.com" जैसे होस्टनेम पैटर्न का इस्तेमाल नहीं किया जा सकता. Chrome 107 से, सभी डोमेन को ऐक्सेस करने के लिए <all_urls> का इस्तेमाल किया जा सकता है. ध्यान दें कि इससे सभी होस्ट पर असर पड़ता है. इसलिए, इसका इस्तेमाल करने वाले एक्सटेंशन की समीक्षा में ज़्यादा समय लग सकता है.

किसी ऐप्लिकेशन या एक्सटेंशन पर मैसेज भेजने के लिए, runtime.sendMessage() या runtime.connect() एपीआई का इस्तेमाल करें. उदाहरण के लिए:

webpage.js

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

अपने एक्सटेंशन से, runtime.onMessageExternal या runtime.onConnectExternal एपीआई का इस्तेमाल करके, वेब पेजों के मैसेज सुनें. जैसे, क्रॉस-एक्सटेंशन मैसेज सेवा का इस्तेमाल करके. यहां एक उदाहरण दिया गया है:

service-worker.js (सर्विस-worker.js)

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url === blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

नेटिव मैसेजिंग

एक्सटेंशन, नेटिव मैसेजिंग होस्ट के तौर पर रजिस्टर किए गए नेटिव ऐप्लिकेशन के साथ मैसेज का लेन-देन कर सकते हैं. इस सुविधा के बारे में ज़्यादा जानने के लिए, नेटिव मैसेजिंग देखें.

सुरक्षा से जुड़ी बातें

यहां मैसेज सेवा के लिए, सुरक्षा से जुड़ी कुछ बातें बताई गई हैं.

कॉन्टेंट स्क्रिप्ट भरोसेमंद नहीं होती हैं

एक्सटेंशन सर्विस वर्कर की तुलना में कॉन्टेंट स्क्रिप्ट कम भरोसेमंद होती हैं. उदाहरण के लिए, नुकसान पहुंचाने वाला कोई वेब पेज, कॉन्टेंट स्क्रिप्ट को चलाने वाली रेंडरिंग प्रोसेस से छेड़छाड़ कर सकता है. मान लें कि कॉन्टेंट स्क्रिप्ट के मैसेज को हो सकता है कि किसी हमलावर ने तैयार किया हो. साथ ही, सभी इनपुट की पुष्टि करके उन्हें सैनिटाइज़ कर दें. मान लें कि कॉन्टेंट स्क्रिप्ट को भेजा गया कोई भी डेटा, वेब पेज पर लीक हो सकता है. उन खास कार्रवाइयों के दायरे को सीमित करें जो कॉन्टेंट स्क्रिप्ट से मिले मैसेज से ट्रिगर हो सकती हैं.

क्रॉस-साइट स्क्रिप्टिंग

पक्का करें कि आपकी स्क्रिप्ट को क्रॉस-साइट स्क्रिप्टिंग से सुरक्षित रखा गया हो. कॉन्टेंट स्क्रिप्ट या एपीआई के ज़रिए उपयोगकर्ता के इनपुट, दूसरी वेबसाइटों जैसे गैर-भरोसेमंद सोर्स से डेटा हासिल करते समय, इसे एचटीएमएल के तौर पर न समझें. इसके अलावा, इसे इस तरह इस्तेमाल करने से बचें जिससे अनचाहा कोड चल सके.

ज़्यादा सुरक्षित तरीके

जब भी संभव हो, ऐसे एपीआई इस्तेमाल करें जो स्क्रिप्ट नहीं चलाते:

service-worker.js (सर्विस-worker.js)

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse doesn't evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});

service-worker.js (सर्विस-worker.js)

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});
असुरक्षित तरीके

नीचे दिए गए तरीकों का इस्तेमाल करने से बचें, जो आपके एक्सटेंशन को जोखिम में डालते हैं:

service-worker.js (सर्विस-worker.js)

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating a malicious script!
  var resp = eval(`(${response.farewell})`);
});

service-worker.js (सर्विस-worker.js)

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});