যেহেতু বিষয়বস্তু স্ক্রিপ্টগুলি একটি ওয়েব পৃষ্ঠার প্রেক্ষাপটে চালিত হয়, যে এক্সটেনশনটি চালায় তা নয়, তাই তাদের প্রায়শই বাকি এক্সটেনশনের সাথে যোগাযোগ করার উপায়গুলির প্রয়োজন হয়৷ উদাহরণস্বরূপ, একটি RSS রিডার এক্সটেনশন একটি পৃষ্ঠায় একটি RSS ফিডের উপস্থিতি সনাক্ত করতে সামগ্রী স্ক্রিপ্ট ব্যবহার করতে পারে, তারপর সেই পৃষ্ঠাটির জন্য একটি অ্যাকশন আইকন প্রদর্শন করতে পরিষেবা কর্মীকে অবহিত করুন৷
এই যোগাযোগ বার্তা পাসিং ব্যবহার করে, যা এক্সটেনশন এবং বিষয়বস্তু স্ক্রিপ্ট উভয়ই একে অপরের বার্তা শুনতে এবং একই চ্যানেলে প্রতিক্রিয়া জানাতে দেয়। একটি বার্তায় যেকোনো বৈধ JSON অবজেক্ট থাকতে পারে (নাল, বুলিয়ান, সংখ্যা, স্ট্রিং, অ্যারে বা অবজেক্ট)। দুটি বার্তা পাসিং API আছে: একটি এককালীন অনুরোধের জন্য, এবং একটি দীর্ঘস্থায়ী সংযোগের জন্য আরও জটিল যা একাধিক বার্তা পাঠানোর অনুমতি দেয়৷ এক্সটেনশনগুলির মধ্যে বার্তা পাঠানো সম্পর্কে তথ্যের জন্য, ক্রস-এক্সটেনশন বার্তা বিভাগটি দেখুন৷
এককালীন অনুরোধ
আপনার এক্সটেনশনের অন্য অংশে একটি একক বার্তা পাঠাতে এবং ঐচ্ছিকভাবে একটি প্রতিক্রিয়া পেতে, runtime.sendMessage()
বা tabs.sendMessage()
কল করুন। এই পদ্ধতিগুলি আপনাকে একটি বিষয়বস্তু স্ক্রিপ্ট থেকে এক্সটেনশনে বা এক্সটেনশন থেকে একটি সামগ্রী স্ক্রিপ্টে একটি এককালীন JSON-ক্রমিক বার্তা পাঠাতে দেয়৷ প্রতিক্রিয়া পরিচালনা করতে, ফিরে আসা প্রতিশ্রুতি ব্যবহার করুন। পুরানো এক্সটেনশনগুলির সাথে পিছিয়ে থাকা সামঞ্জস্যের জন্য, আপনি পরিবর্তে শেষ যুক্তি হিসাবে একটি কলব্যাক পাস করতে পারেন৷ আপনি একই কলে একটি প্রতিশ্রুতি এবং একটি কলব্যাক ব্যবহার করতে পারবেন না৷
আপনি যখন একটি বার্তা পাঠান, ইভেন্ট শ্রোতা যে বার্তাটি পরিচালনা করে তাকে একটি ঐচ্ছিক তৃতীয় যুক্তি, sendResponse
পাস করা হয়। এটি এমন একটি ফাংশন যা একটি JSON- সিরিয়ালাইজেবল অবজেক্ট নেয় যা বার্তা পাঠানোর ফাংশনে রিটার্ন মান হিসাবে ব্যবহৃত হয়। ডিফল্টরূপে, sendResponse
কলব্যাক সিঙ্ক্রোনাস কল করা আবশ্যক। আপনি sendResponse
এ মানটি পাস করার জন্য অ্যাসিঙ্ক্রোনাস কাজ করতে চাইলে, আপনাকে অবশ্যই ইভেন্ট শ্রোতার কাছ থেকে একটি আক্ষরিক true
(শুধু একটি সত্য মান নয়) ফেরত দিতে হবে । এটি করার ফলে sendResponse
কল না হওয়া পর্যন্ত বার্তা চ্যানেলটি অন্য প্রান্তে খোলা থাকবে।
// Event listener
function handleMessages(message, sender, sendResponse) {
fetch(message.url)
.then((response) => sendResponse({statusCode: response.status}))
// Since `fetch` is asynchronous, must send an explicit `true`
return true;
}
// Message sender
const {statusCode} = await chrome.runtime.sendMessage({
url: 'https://example.com'
});
কলব্যাকগুলিকে প্রতিশ্রুতিতে রূপান্তরিত করার এবং এক্সটেনশনগুলিতে ব্যবহার করার বিষয়ে তথ্যের জন্য, ম্যানিফেস্ট 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);
})();
আপনি যদি একটি বার্তার সিঙ্ক্রোনাসভাবে প্রতিক্রিয়া জানাতে চান, আপনার প্রতিক্রিয়া পাওয়ার পরে শুধুমাত্র sendResponse
এ কল করুন এবং এটি হয়ে গেছে বলে ইঙ্গিত করতে false
ফেরত দিন। অ্যাসিঙ্ক্রোনাসভাবে প্রতিক্রিয়া জানাতে, আপনি এটি ব্যবহার করার জন্য প্রস্তুত না হওয়া পর্যন্ত sendResponse
কলব্যাক সক্রিয় রাখতে true
ফিরে যান। Async ফাংশন সমর্থিত নয় কারণ তারা একটি প্রতিশ্রুতি প্রদান করে, যা সমর্থিত নয়।
একটি বিষয়বস্তু স্ক্রিপ্টে একটি অনুরোধ পাঠাতে, নিম্নলিখিতটিতে দেখানো হিসাবে অনুরোধটি কোন ট্যাবে প্রযোজ্য তা নির্দিষ্ট করুন৷ এই উদাহরণটি পরিষেবা কর্মী, পপআপ এবং 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"});
});
এক্সটেনশন থেকে একটি কন্টেন্ট স্ক্রিপ্টে একটি অনুরোধ পাঠাতে, আগের উদাহরণে tabs.connect()
দিয়ে runtime.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
ইভেন্টটি শুধুমাত্র সেন্ডিং পোর্টে ফায়ার হয়, অন্য পোর্টে নয়।
ক্রস-এক্সটেনশন মেসেজিং
আপনার এক্সটেনশনের বিভিন্ন উপাদানের মধ্যে বার্তা পাঠানোর পাশাপাশি, আপনি অন্যান্য এক্সটেনশনের সাথে যোগাযোগ করতে মেসেজিং API ব্যবহার করতে পারেন৷ এটি আপনাকে অন্যান্য এক্সটেনশন ব্যবহারের জন্য একটি সর্বজনীন API প্রকাশ করতে দেয়।
অন্যান্য এক্সটেনশন থেকে আগত অনুরোধ এবং সংযোগগুলি শুনতে, runtime.onMessageExternal
বা runtime.onConnectExternal
পদ্ধতিগুলি ব্যবহার করুন৷ এখানে প্রতিটির একটি উদাহরণ:
service-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
// The ID of the extension we want to talk to.
var 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:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);
ওয়েব পেজ থেকে বার্তা পাঠান
এক্সটেনশনগুলি অন্যান্য ওয়েব পৃষ্ঠাগুলি থেকে বার্তাগুলি গ্রহণ এবং প্রতিক্রিয়া জানাতে পারে, কিন্তু ওয়েব পৃষ্ঠাগুলিতে বার্তা পাঠাতে পারে না৷ একটি ওয়েব পৃষ্ঠা থেকে একটি এক্সটেনশনে বার্তা পাঠাতে, "externally_connectable"
ম্যানিফেস্ট কী ব্যবহার করে আপনি কোন ওয়েবসাইটগুলির সাথে যোগাযোগ করতে চান তা আপনার manifest.json
এ উল্লেখ করুন৷ যেমন:
manifest.json
"externally_connectable": {
"matches": ["https://*.example.com/*"]
}
এটি আপনার নির্দিষ্ট করা URL প্যাটার্নের সাথে মেলে এমন যেকোনো পৃষ্ঠায় মেসেজিং এপিআই প্রকাশ করে। URL প্যাটার্নে কমপক্ষে একটি দ্বিতীয়-স্তরের ডোমেন থাকতে হবে; অর্থাৎ হোস্টনাম প্যাটার্ন যেমন "*", "*.com", "*.co.uk", এবং "*.appspot.com" সমর্থিত নয়। Chrome 107 থেকে শুরু করে, আপনি <all_urls>
সব ডোমেন অ্যাক্সেস করতে ব্যবহার করতে পারেন। মনে রাখবেন যে এটি সমস্ত হোস্টকে প্রভাবিত করে, তাই এটি ব্যবহার করে এমন এক্সটেনশনগুলির জন্য Chrome ওয়েব স্টোর পর্যালোচনাগুলি আরও বেশি সময় নিতে পারে ৷
একটি নির্দিষ্ট অ্যাপ বা এক্সটেনশনে একটি বার্তা পাঠাতে 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. var 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! var 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; });