মেসেজিং এপিআই আপনাকে আপনার এক্সটেনশনের সাথে সম্পর্কিত প্রসঙ্গে চলমান বিভিন্ন স্ক্রিপ্টের মধ্যে যোগাযোগ করার অনুমতি দেয়। এতে আপনার পরিষেবা কর্মী, chrome-extension://pages এবং সামগ্রী স্ক্রিপ্টগুলির মধ্যে যোগাযোগ অন্তর্ভুক্ত রয়েছে৷ উদাহরণস্বরূপ, একটি RSS পাঠক এক্সটেনশন একটি পৃষ্ঠায় একটি RSS ফিডের উপস্থিতি সনাক্ত করতে সামগ্রী স্ক্রিপ্ট ব্যবহার করতে পারে, তারপর সেই পৃষ্ঠাটির জন্য অ্যাকশন আইকন আপডেট করার জন্য পরিষেবা কর্মীকে অবহিত করুন৷
দুটি বার্তা পাসিং API আছে: একটি এককালীন অনুরোধের জন্য, এবং একটি দীর্ঘস্থায়ী সংযোগের জন্য আরও জটিল যা একাধিক বার্তা পাঠানোর অনুমতি দেয়৷
এক্সটেনশনগুলির মধ্যে বার্তা পাঠানো সম্পর্কে তথ্যের জন্য, ক্রস-এক্সটেনশন বার্তা বিভাগটি দেখুন৷
এককালীন অনুরোধ
আপনার এক্সটেনশনের অন্য অংশে একটি একক বার্তা পাঠাতে এবং ঐচ্ছিকভাবে একটি প্রতিক্রিয়া পেতে, runtime.sendMessage()
বা tabs.sendMessage()
কল করুন। এই পদ্ধতিগুলি আপনাকে একটি বিষয়বস্তু স্ক্রিপ্ট থেকে এক্সটেনশনে বা এক্সটেনশন থেকে একটি সামগ্রী স্ক্রিপ্টে একটি এককালীন JSON-ক্রমিক বার্তা পাঠাতে দেয়৷ উভয় APIই একটি প্রতিশ্রুতি প্রদান করে যা একটি প্রাপকের দ্বারা প্রদত্ত প্রতিক্রিয়ার সমাধান করে।
একটি বিষয়বস্তু স্ক্রিপ্ট থেকে একটি অনুরোধ পাঠানো এই মত দেখায়:
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.runtime.onMessage
ইভেন্টটি ব্যবহার করুন:
// Event listener
function handleMessages(message, sender, sendResponse) {
fetch(message.url)
.then((response) => sendResponse({statusCode: response.status}))
// Since `fetch` is asynchronous, must return an explicit `true`
return true;
}
chrome.runtime.onMessage.addListener(handleMessages);
// From the sender's context...
const {statusCode} = await chrome.runtime.sendMessage({
url: 'https://example.com'
});
যখন ইভেন্ট শ্রোতাকে কল করা হয়, একটি sendResponse
ফাংশন তৃতীয় প্যারামিটার হিসাবে পাস করা হয়। এটি একটি ফাংশন যা একটি প্রতিক্রিয়া প্রদান করতে বলা যেতে পারে। ডিফল্টরূপে, sendResponse
কলব্যাক সিঙ্ক্রোনাস কল করা আবশ্যক। আপনি sendResponse
এ মানটি পাস করার জন্য অ্যাসিঙ্ক্রোনাস কাজ করতে চাইলে, আপনাকে অবশ্যই ইভেন্ট শ্রোতার কাছ থেকে একটি আক্ষরিক true
(শুধু একটি সত্য মান নয়) ফেরত দিতে হবে । এটি করার ফলে sendResponse
কল না হওয়া পর্যন্ত বার্তা চ্যানেলটি অন্য প্রান্তে খোলা থাকবে।
আপনি কোনো পরামিতি ছাড়া sendResponse
কল করলে, null
একটি প্রতিক্রিয়া হিসাবে পাঠানো হয়।
যদি একাধিক পৃষ্ঠা onMessage
ইভেন্টের জন্য শুনছে, শুধুমাত্র একটি নির্দিষ্ট ইভেন্টের জন্য sendResponse()
কল করা প্রথম ব্যক্তি প্রতিক্রিয়া পাঠাতে সফল হবে। সেই ইভেন্টের অন্যান্য সমস্ত প্রতিক্রিয়া উপেক্ষা করা হবে৷
দীর্ঘস্থায়ী সংযোগ
একটি পুনঃব্যবহারযোগ্য দীর্ঘস্থায়ী বার্তা পাসিং চ্যানেল তৈরি করতে, কল করুন:
-
runtime.connect()
একটি বিষয়বস্তু স্ক্রিপ্ট থেকে একটি এক্সটেনশন পৃষ্ঠায় বার্তা পাঠাতে -
tabs.connect()
একটি এক্সটেনশন পৃষ্ঠা থেকে একটি বিষয়বস্তু স্ক্রিপ্টে বার্তা পাঠাতে।
আপনি বিভিন্ন ধরনের সংযোগের মধ্যে পার্থক্য করার জন্য একটি name
কী সহ একটি বিকল্প প্যারামিটার পাস করে আপনার চ্যানেলের নাম দিতে পারেন:
const port = chrome.runtime.connect({name: "example"});
দীর্ঘস্থায়ী সংযোগের জন্য একটি সম্ভাব্য ব্যবহারের ক্ষেত্রে একটি স্বয়ংক্রিয় ফর্ম-ফিলিং এক্সটেনশন। বিষয়বস্তু স্ক্রিপ্ট একটি নির্দিষ্ট লগইনের জন্য এক্সটেনশন পৃষ্ঠায় একটি চ্যানেল খুলতে পারে, এবং ফর্ম ডেটা পূরণ করার জন্য অনুরোধ করার জন্য পৃষ্ঠার প্রতিটি ইনপুট উপাদানের জন্য এক্সটেনশনে একটি বার্তা পাঠাতে পারে৷ ভাগ করা সংযোগ এক্সটেনশনটিকে এক্সটেনশন উপাদানগুলির মধ্যে স্থিতি ভাগ করার অনুমতি দেয়৷
একটি সংযোগ স্থাপন করার সময়, প্রতিটি প্রান্তে একটি runtime.Port
বরাদ্দ করা হয়৷ সেই সংযোগের মাধ্যমে বার্তা পাঠানো এবং গ্রহণ করার জন্য পোর্ট অবজেক্ট৷
একটি বিষয়বস্তু স্ক্রিপ্ট থেকে একটি চ্যানেল খুলতে এবং বার্তা পাঠাতে এবং শুনতে নিম্নলিখিত কোডটি ব্যবহার করুন:
content-script.js:
const port = chrome.runtime.connect({name: "knockknock"});
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"});
}
});
port.postMessage({joke: "Knock knock"});
এক্সটেনশন থেকে একটি কন্টেন্ট স্ক্রিপ্টে একটি অনুরোধ পাঠাতে, আগের উদাহরণে tabs.connect()
runtime.connect()
() এ কলটি প্রতিস্থাপন করুন।
একটি বিষয়বস্তু স্ক্রিপ্ট বা একটি এক্সটেনশন পৃষ্ঠার জন্য ইনকামিং সংযোগগুলি পরিচালনা করতে, একটি runtime.onConnect
ইভেন্ট লিসেনার সেট আপ করুন৷ যখন আপনার এক্সটেনশনের অন্য একটি অংশ connect()
কল করে, এটি এই ইভেন্ট এবং runtime.Port
সক্রিয় করে। পোর্ট অবজেক্ট। ইনকামিং সংযোগে সাড়া দেওয়ার জন্য কোডটি এইরকম দেখাচ্ছে:
service-worker.js:
chrome.runtime.onConnect.addListener(function(port) {
if (port.name !== "knockknock") {
return;
}
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."});
}
});
});
সিরিয়ালাইজেশন
ক্রোমে, বার্তা পাসকারী APIগুলি JSON সিরিয়ালাইজেশন ব্যবহার করে। এর মানে হল একটি বার্তা (এবং প্রাপকদের দ্বারা প্রদত্ত প্রতিক্রিয়া) যেকোন বৈধ JSON মান (নাল, বুলিয়ান, সংখ্যা, স্ট্রিং, অ্যারে বা অবজেক্ট) থাকতে পারে। অন্যান্য মানগুলিকে সিরিয়ালাইজেবল মানগুলিতে বাধ্য করা হবে।
উল্লেখযোগ্যভাবে, এটি অন্যান্য ব্রাউজারগুলির থেকে আলাদা যা কাঠামোগত ক্লোন অ্যালগরিদমের সাথে একই API প্রয়োগ করে।
পোর্ট জীবনকাল
পোর্টগুলিকে একটি এক্সটেনশনের বিভিন্ন অংশের মধ্যে দ্বিমুখী যোগাযোগ ব্যবস্থা হিসাবে ডিজাইন করা হয়েছে। যখন একটি এক্সটেনশনের অংশ 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
ইভেন্টটি শুধুমাত্র সেন্ডিং পোর্টে ফায়ার হয়, অন্য পোর্টে নয়।
ক্রস-এক্সটেনশন মেসেজিং
আপনার এক্সটেনশনের বিভিন্ন উপাদানের মধ্যে বার্তা পাঠানোর পাশাপাশি, আপনি অন্যান্য এক্সটেনশনের সাথে যোগাযোগ করতে মেসেজিং API ব্যবহার করতে পারেন৷ এটি আপনাকে অন্যান্য এক্সটেনশন ব্যবহারের জন্য একটি সর্বজনীন API প্রকাশ করতে দেয়।
অন্যান্য এক্সটেনশন থেকে আগত অনুরোধ এবং সংযোগগুলি শুনতে, runtime.onMessageExternal
বা runtime.onConnectExternal
পদ্ধতিগুলি ব্যবহার করুন৷ এখানে প্রতিটির একটি উদাহরণ:
service-worker.js
// For a single request:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
if (sender.id !== allowlistedExtension) {
return; // don't allow this extension access
}
if (request.getTargetData) {
sendResponse({ targetData: targetData });
} else if (request.activateLasers) {
const 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
// The ID of the extension we want to talk to.
const laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
// For a minimal request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
function(response) {
if (targetInRange(response.targetData))
chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
}
);
// For a long-lived connection:
const port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);
ওয়েব পেজ থেকে বার্তা পাঠান
এক্সটেনশনগুলি ওয়েব পৃষ্ঠাগুলি থেকে বার্তাগুলি গ্রহণ করতে এবং প্রতিক্রিয়া জানাতে পারে৷ একটি ওয়েব পৃষ্ঠা থেকে একটি এক্সটেনশনে বার্তা পাঠাতে, আপনার manifest.json
এ উল্লেখ করুন যে কোন ওয়েবসাইটগুলিকে আপনি "externally_connectable"
ম্যানিফেস্ট কী ব্যবহার করে বার্তাগুলিকে অনুমতি দিতে চান৷ যেমন:
manifest.json
"externally_connectable": {
"matches": ["https://*.example.com/*"]
}
এটি আপনার নির্দিষ্ট করা URL প্যাটার্নের সাথে মেলে এমন যেকোনো পৃষ্ঠায় মেসেজিং এপিআই প্রকাশ করে। URL প্যাটার্নে কমপক্ষে একটি দ্বিতীয়-স্তরের ডোমেন থাকতে হবে; অর্থাৎ হোস্টনাম প্যাটার্ন যেমন "*", "*.com", "*.co.uk", এবং "*.appspot.com" সমর্থিত নয়। আপনি <all_urls>
ব্যবহার করতে পারেন সমস্ত ডোমেন অ্যাক্সেস করতে।
একটি নির্দিষ্ট এক্সটেনশনে একটি বার্তা পাঠাতে runtime.sendMessage()
বা runtime.connect()
API ব্যবহার করুন। যেমন:
webpage.js
// The ID of the extension we want to talk to.
const editorExtensionId = 'abcdefghijklmnoabcdefhijklmnoabc';
// Check if extension is installed
if (chrome && chrome.runtime) {
// Make a request:
chrome.runtime.sendMessage(
editorExtensionId,
{
openUrlInEditor: url
},
(response) => {
if (!response.success) handleError(url);
}
);
}
আপনার এক্সটেনশন থেকে, ক্রস-এক্সটেনশন মেসেজিংয়ের মতো runtime.onMessageExternal
বা runtime.onConnectExternal
API ব্যবহার করে ওয়েব পৃষ্ঠাগুলি থেকে বার্তাগুলি শুনুন৷ এখানে একটি উদাহরণ:
service-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);
});
একটি এক্সটেনশন থেকে একটি ওয়েব পৃষ্ঠায় একটি বার্তা পাঠানো সম্ভব নয়৷
নেটিভ মেসেজিং
এক্সটেনশনগুলি নেটিভ অ্যাপ্লিকেশনগুলির সাথে বার্তা বিনিময় করতে পারে যা একটি নেটিভ মেসেজিং হোস্ট হিসাবে নিবন্ধিত৷ এই বৈশিষ্ট্য সম্পর্কে আরও জানতে, নেটিভ মেসেজিং দেখুন।
নিরাপত্তা বিবেচনা
এখানে বার্তা পাঠানোর সাথে সম্পর্কিত কয়েকটি নিরাপত্তা বিবেচনা রয়েছে।
কন্টেন্ট স্ক্রিপ্ট কম বিশ্বস্ত হয়
বিষয়বস্তু স্ক্রিপ্ট এক্সটেনশন পরিষেবা কর্মীর তুলনায় কম বিশ্বস্ত । উদাহরণস্বরূপ, একটি দূষিত ওয়েব পৃষ্ঠা রেন্ডারিং প্রক্রিয়ার সাথে আপস করতে সক্ষম হতে পারে যা সামগ্রী স্ক্রিপ্টগুলি চালায়৷ অনুমান করুন যে একটি বিষয়বস্তু স্ক্রিপ্ট থেকে বার্তাগুলি একটি আক্রমণকারী দ্বারা তৈরি করা হতে পারে এবং সমস্ত ইনপুটকে যাচাই এবং স্যানিটাইজ করা নিশ্চিত করুন৷ অনুমান করুন বিষয়বস্তু স্ক্রিপ্টে পাঠানো কোনো ডেটা ওয়েব পৃষ্ঠায় লিক হতে পারে। বিষয়বস্তু স্ক্রিপ্ট থেকে প্রাপ্ত বার্তা দ্বারা ট্রিগার করা যেতে পারে যে বিশেষাধিকার কর্মের সুযোগ সীমিত.
ক্রস-সাইট স্ক্রিপ্টিং
ক্রস-সাইট স্ক্রিপ্টিংয়ের বিরুদ্ধে আপনার স্ক্রিপ্টগুলিকে রক্ষা করা নিশ্চিত করুন। ব্যবহারকারীর ইনপুট, একটি বিষয়বস্তু স্ক্রিপ্ট বা একটি API এর মাধ্যমে একটি অবিশ্বস্ত উৎস থেকে ডেটা গ্রহণ করার সময়, এটিকে HTML হিসাবে ব্যাখ্যা করা বা অপ্রত্যাশিত কোড চালানোর অনুমতি দিতে পারে এমনভাবে এটি ব্যবহার করা এড়াতে যত্ন নিন।
এপিআই ব্যবহার করুন যেগুলো যখনই সম্ভব স্ক্রিপ্ট চালায় না:
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // JSON.parse doesn't evaluate the attacker's scripts. const resp = JSON.parse(response.farewell); });
service-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
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be evaluating a malicious script! const resp = eval(`(${response.farewell})`); });
service-worker.js
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) { // WARNING! Might be injecting a malicious script! document.getElementById("resp").innerHTML = response.farewell; });