কন্টেন্ট স্ক্রিপ্ট হলো এমন ফাইল যা ওয়েব পেজের প্রেক্ষাপটে চলে। স্ট্যান্ডার্ড ডকুমেন্ট অবজেক্ট মডেল (DOM) ব্যবহার করে, এগুলি ব্রাউজার দ্বারা পরিদর্শিত ওয়েব পেজগুলির বিবরণ পড়তে, সেগুলিতে পরিবর্তন আনতে এবং তাদের প্যারেন্ট এক্সটেনশনে তথ্য প্রেরণ করতে সক্ষম হয়।
কন্টেন্ট স্ক্রিপ্টের সক্ষমতা বুঝুন
কন্টেন্ট স্ক্রিপ্টগুলো তাদের প্যারেন্ট এক্সটেনশনের সাথে বার্তা আদান-প্রদানের মাধ্যমে সেই এক্সটেনশন দ্বারা ব্যবহৃত ক্রোম এপিআইগুলো অ্যাক্সেস করতে পারে। এছাড়াও, তারা chrome.runtime.getURL() ব্যবহার করে কোনো এক্সটেনশনের ফাইলের ইউআরএল অ্যাক্সেস করতে পারে এবং প্রাপ্ত ফলাফলটি অন্যান্য ইউআরএলের মতোই ব্যবহার করতে পারে।
// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
এছাড়াও, কন্টেন্ট স্ক্রিপ্ট সরাসরি নিম্নলিখিত ক্রোম এপিআইগুলো অ্যাক্সেস করতে পারে:
কন্টেন্ট স্ক্রিপ্টগুলো সরাসরি অন্যান্য এপিআই অ্যাক্সেস করতে পারে না।
বিচ্ছিন্ন বিশ্বে কাজ করুন
কন্টেন্ট স্ক্রিপ্টগুলো একটি বিচ্ছিন্ন জগতে অবস্থান করে, যার ফলে এটি পেজ বা অন্য কোনো কন্টেন্ট স্ক্রিপ্টের সাথে সংঘাত না ঘটিয়েই তার জাভাস্ক্রিপ্ট পরিবেশে পরিবর্তন আনতে পারে।
একটি এক্সটেনশন নিচের উদাহরণের মতো কোড ব্যবহার করে কোনো ওয়েব পেজে চালানো যেতে পারে।
<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 পারমিশনটি প্রদান করুন। এটি সক্রিয় সাইটের হোস্টে সুরক্ষিত অ্যাক্সেস এবং tabs পারমিশনে অস্থায়ী অ্যাক্সেস প্রদান করে, যার ফলে ক্রস-অরিজিন পারমিশন নির্দিষ্ট না করেই কন্টেন্ট স্ক্রিপ্টটি বর্তমান সক্রিয় ট্যাবে চালানো যায়।
{
"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" ফিল্ডের অধীনে নিবন্ধিত হয়। এগুলোতে জাভাস্ক্রিপ্ট ফাইল, সিএসএস ফাইল অথবা উভয়ই অন্তর্ভুক্ত থাকতে পারে। সমস্ত অটো-রান কন্টেন্ট স্ক্রিপ্টে অবশ্যই ম্যাচ প্যাটার্ন নির্দিষ্ট করতে হবে।
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"css": ["myStyles.css"],
"js": ["contentScript.js"]
}
],
...
}
| নাম | প্রকার | বর্ণনা |
|---|---|---|
matches {: #ম্যাচ } | | আবশ্যক। এটি নির্দিষ্ট করে যে এই কন্টেন্ট স্ক্রিপ্টটি কোন কোন পেজে যুক্ত করা হবে। এই স্ট্রিংগুলির সিনট্যাক্স সম্পর্কে আরও বিস্তারিত জানতে ‘ম্যাচ প্যাটার্নস’ দেখুন এবং কীভাবে ইউআরএল বাদ দিতে হয় সে সম্পর্কে তথ্যের জন্য ‘ম্যাচ প্যাটার্নস অ্যান্ড গ্লোবস’ দেখুন। |
css {: #সিএসএস } | | ঐচ্ছিক। সংশ্লিষ্ট পেজগুলিতে ইনজেক্ট করার জন্য CSS ফাইলগুলির তালিকা। পেজের জন্য কোনো DOM তৈরি বা প্রদর্শিত হওয়ার আগে, এই অ্যারেতে ফাইলগুলি যে ক্রমে রয়েছে, সেই ক্রমেই ইনজেক্ট করা হয়। |
js {: #js } | | ঐচ্ছিক। সংশ্লিষ্ট পৃষ্ঠাগুলিতে ইনজেক্ট করার জন্য জাভাস্ক্রিপ্ট ফাইলগুলির তালিকা। এই ফাইলগুলি এই অ্যারেতে যে ক্রমে রয়েছে, সেই ক্রমেই ইনজেক্ট করা হয়। |
match_about_blank {: #match_about_blank } | বুলিয়ান | ঐচ্ছিক। স্ক্রিপ্টটি এমন একটি about:blank ফ্রেমে ইনজেক্ট করবে কিনা, যেখানে প্যারেন্ট বা ওপেনার ফ্রেমটি matches এ ঘোষিত প্যাটার্নগুলোর কোনো একটির সাথে মেলে। ডিফল্ট মান false । |
ম্যাচ এবং গ্লোব বাদ দিন
ম্যানিফেস্ট রেজিস্ট্রেশনে নিম্নলিখিত ফিল্ডগুলি অন্তর্ভুক্ত করার মাধ্যমে নির্দিষ্ট পেজ ম্যাচিং কাস্টমাইজ করা যায়।
| নাম | প্রকার | বর্ণনা |
|---|---|---|
exclude_matches {: #exclude_matches } | | ঐচ্ছিক। যেসব পৃষ্ঠায় অন্যথায় এই কন্টেন্ট স্ক্রিপ্টটি যুক্ত হতো, সেগুলোকে বাদ দেয়। এই স্ট্রিংগুলোর সিনট্যাক্স সম্পর্কে আরও বিস্তারিত জানতে ম্যাচ প্যাটার্নস দেখুন। |
include_globs {: #include_globs } | | ঐচ্ছিক। matches পর শুধুমাত্র সেইসব URL অন্তর্ভুক্ত করার জন্য এটি প্রয়োগ করা হয়, যেগুলো এই গ্লোবটির সাথেও মেলে। এর উদ্দেশ্য হলো Greasemonkey-এর @include কীওয়ার্ডটির অনুকরণ করা। |
exclude_globs {: #exclude_globs } | | ঐচ্ছিক। এই গ্লোবের সাথে মেলে এমন URL বাদ দেওয়ার জন্য matches পরে এটি প্রয়োগ করা হয়। এর উদ্দেশ্য হলো Greasemonkey-এর @exclude কীওয়ার্ডটির অনুকরণ করা। |
কোনো পৃষ্ঠার URL যদি যেকোনো matches প্যাটার্ন এবং যেকোনো include_globs প্যাটার্নের সাথে মিলে যায়, তবে কন্টেন্ট স্ক্রিপ্টটি সেই পৃষ্ঠায় ইনজেক্ট করা হবে; তবে শর্ত হলো, URL-টি যেন কোনো 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:// ??? .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/arts/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/history- তে ইনজেক্ট করবে, কিন্তু 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"]
}
],
...
}
রান টাইম
ওয়েব পেজে জাভাস্ক্রিপ্ট ফাইল কখন যুক্ত হবে তা run_at ফিল্ড দ্বারা নিয়ন্ত্রিত হয়। এর জন্য পছন্দের এবং ডিফল্ট ফিল্ড হলো "document_idle" , তবে প্রয়োজনে "document_start" বা "document_end" হিসেবেও এটি নির্দিষ্ট করা যেতে পারে।
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"run_at": "document_idle",
"js": ["contentScript.js"]
}
],
...
}
| নাম | প্রকার | বর্ণনা |
|---|---|---|
document_idle {: #ডকুমেন্ট_আইডল } | স্ট্রিং | পছন্দনীয়। সম্ভব হলে "document_idle" ব্যবহার করুন।ব্রাউজার "document_end" এবং windowonload " ইভেন্টটি ফায়ার হওয়ার ঠিক পরের মুহূর্তের মধ্যে স্ক্রিপ্ট ইনজেক্ট করার জন্য একটি সময় বেছে নেয়। ইনজেকশনের সঠিক মুহূর্তটি নির্ভর করে ডকুমেন্টটি কতটা জটিল এবং এটি লোড হতে কত সময় নিচ্ছে তার উপর, এবং এটি পেজ লোডের গতি বাড়ানোর জন্য অপ্টিমাইজ করা হয়।"document_idle" অবস্থায় চলমান কন্টেন্ট স্ক্রিপ্টগুলোর window.onload ইভেন্টের জন্য অপেক্ষা করার প্রয়োজন নেই, কারণ DOM সম্পূর্ণ হওয়ার পরেই সেগুলো নিশ্চিতভাবে রান করে। যদি কোনো স্ক্রিপ্টকে window.onload পরে অবশ্যই রান করতে হয়, তবে এক্সটেনশনটি document.readyState প্রপার্টি ব্যবহার করে যাচাই করতে পারে যে onload ইতোমধ্যেই ফায়ার হয়েছে কি না। |
document_start {: #ডকুমেন্ট_স্টার্ট } | স্ট্রিং | স্ক্রিপ্টগুলো css এর যেকোনো ফাইলের পরে, কিন্তু অন্য কোনো DOM তৈরি হওয়ার বা অন্য কোনো স্ক্রিপ্ট চলার আগে ইনজেক্ট করা হয়। |
document_end {: #ডকুমেন্ট_শেষ } | স্ট্রিং | DOM সম্পূর্ণ হওয়ার ঠিক পরেই, কিন্তু ছবি এবং ফ্রেমের মতো সাবরিসোর্সগুলো লোড হওয়ার আগে স্ক্রিপ্টগুলো ইনজেক্ট করা হয়। |
ফ্রেম নির্দিষ্ট করুন
"all_frames" ফিল্ডটি এক্সটেনশনকে নির্দিষ্ট করতে দেয় যে, জাভাস্ক্রিপ্ট এবং সিএসএস ফাইলগুলো নির্দিষ্ট URL-এর শর্ত পূরণকারী সমস্ত ফ্রেমে ইনজেক্ট করা হবে, নাকি শুধুমাত্র একটি ট্যাবের সর্ববৃহৎ ফ্রেমে ইনজেক্ট করা হবে।
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://*.nytimes.com/*"],
"all_frames": true,
"js": ["contentScript.js"]
}
],
...
}
| নাম | প্রকার | বর্ণনা |
|---|---|---|
all_frames {: #সব_ফ্রেম } | বুলিয়ান | ঐচ্ছিক। ডিফল্টরূপে এর মান false থাকে, যার অর্থ হলো শুধুমাত্র উপরের ফ্রেমটিই মেলানো হবে।যদি true নির্দিষ্ট করা হয়, তবে এটি সমস্ত ফ্রেমে ইনজেক্ট করবে, এমনকি যদি ফ্রেমটি ট্যাবের সবচেয়ে উপরের ফ্রেম নাও হয়। প্রতিটি ফ্রেমের URL-এর প্রয়োজনীয়তা আলাদাভাবে পরীক্ষা করা হয়; URL-এর প্রয়োজনীয়তা পূরণ না হলে এটি চাইল্ড ফ্রেমগুলিতে ইনজেক্ট করবে না। |
এম্বেডিং পৃষ্ঠার সাথে যোগাযোগ
যদিও কন্টেন্ট স্ক্রিপ্টের এক্সিকিউশন এনভায়রনমেন্ট এবং যে পেজগুলো সেগুলোকে হোস্ট করে, সেগুলো একে অপরের থেকে বিচ্ছিন্ন থাকে, তবুও তারা পেজের 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 পাঠানোর মাধ্যমে, তবে তা ইনজেক্ট করার আগে ক্রস-সাইট স্ক্রিপ্টিং আক্রমণ থেকে কন্টেন্ট ফিল্টার করতে সতর্ক থাকুন। "ম্যান-ইন-দ্য-মিডল" আক্রমণ এড়ানোর জন্য শুধুমাত্র HTTPS-এর মাধ্যমেই যোগাযোগ করুন।
ক্ষতিকর ওয়েব পেজগুলো ফিল্টার করতে ভুলবেন না। উদাহরণস্বরূপ, নিম্নলিখিত প্যাটার্নগুলো বিপজ্জনক:
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);