اسکریپت های محتوا

اسکریپت های محتوا فایل هایی هستند که در متن صفحات وب اجرا می شوند. با استفاده از Document Object Model (DOM)، آنها می توانند جزئیات صفحات وب را که مرورگر بازدید می کند بخوانند، تغییراتی در آنها ایجاد کنند و اطلاعات را به برنامه افزودنی والد خود منتقل کنند.

قابلیت های اسکریپت محتوا را درک کنید

اسکریپت‌های محتوا می‌توانند با تبادل پیام با افزونه، به APIهای Chrome مورد استفاده توسط افزونه والد خود دسترسی داشته باشند. آن‌ها همچنین می‌توانند با chrome.runtime.getURL() به URL فایل افزونه دسترسی پیدا کنند و از نتیجه مشابه سایر URL‌ها استفاده کنند.

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

علاوه بر این، اسکریپت محتوا می‌تواند مستقیماً به APIهای کروم زیر دسترسی داشته باشد:

اسکریپت های محتوا قادر به دسترسی مستقیم به سایر API ها نیستند.

در جهان های منزوی کار کنید

اسکریپت‌های محتوا در دنیایی منزوی زندگی می‌کنند و به یک اسکریپت محتوا اجازه می‌دهند تا بدون تضاد با صفحه یا اسکریپت‌های محتوای اضافی، تغییراتی در محیط جاوا اسکریپت خود ایجاد کند.

یک برنامه افزودنی ممکن است در یک صفحه وب با کدی شبیه به مثال زیر اجرا شود.

<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" ثبت می‌شوند. آنها می توانند شامل فایل های جاوا اسکریپت، فایل های CSS یا هر دو باشند. همه اسکریپت های محتوای اجرای خودکار باید الگوهای مطابقت را مشخص کنند.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
نام تایپ کنید توضیحات
matches {: #مطابقات } آرایه ای از رشته ها مورد نیاز. مشخص می کند که این اسکریپت محتوا به چه صفحاتی تزریق شود. برای اطلاعات بیشتر در مورد نحو این رشته‌ها و الگوها و گلوب‌ها را برای اطلاعات در مورد نحوه حذف نشانی‌های وب، به الگوهای مطابقت مراجعه کنید.
css {: #css } آرایه ای از رشته ها اختیاری. لیستی از فایل های CSS که باید به صفحات منطبق تزریق شوند. اینها به ترتیبی که در این آرایه ظاهر می شوند تزریق می شوند، قبل از اینکه DOM برای صفحه ساخته یا نمایش داده شود.
js {: #js } آرایه ای از رشته ها اختیاری. لیستی از فایل های جاوا اسکریپت برای تزریق به صفحات مطابقت. اینها به ترتیبی که در این آرایه ظاهر می شوند تزریق می شوند.
match_about_blank {: #match_about_blank } بولی اختیاری. اینکه آیا اسکریپت باید در یک قاب about:blank تزریق شود که در آن قاب اصلی یا بازکننده با یکی از الگوهای اعلام شده در matches مطابقت دارد. پیش فرض ها به false .

مسابقات و گلوب ها را حذف کنید

مطابقت صفحه مشخص شده با گنجاندن فیلدهای زیر در ثبت مانیفست قابل تنظیم است.

نام تایپ کنید توضیحات
exclude_matches {: #exclude_matches } آرایه ای از رشته ها اختیاری. صفحاتی را که این اسکریپت محتوا در غیر این صورت به آنها تزریق می شد، استثنا نمی کند. برای جزئیات بیشتر در مورد نحو این رشته ها به Match Patterns مراجعه کنید.
include_globs {: #include_globs } آرایه ای از رشته ها اختیاری. پس از matches اعمال می‌شود تا فقط نشانی‌هایی را شامل شود که با این glob مطابقت دارند. در نظر گرفته شده برای تقلید از کلمه کلیدی @include Greasemonkey.
exclude_globs {: #exclude_globs } آرایه رشته اختیاری. برای حذف نشانی‌های وب که با این glob مطابقت دارند، پس از matches اعمال می‌شود. در نظر گرفته شده برای تقلید از کلمه کلیدی @exclude Greasemonkey.

اسکریپت محتوا در صورتی که URL آن با هر الگوی matches و هر الگوی include_globs مطابقت داشته باشد، به صفحه تزریق می‌شود، تا زمانی که URL با الگوی exclude_matches یا exclude_globs مطابقت نداشته باشد.

از آنجایی که ویژگی matches الزامی است، exclude_matches ، include_globs و exclude_globs فقط می توانند برای محدود کردن صفحاتی که تحت تأثیر قرار می گیرند استفاده شوند.

برنامه افزودنی زیر اسکریپت محتوا را به http://www.nytimes.com/ سلامتی تزریق می کند اما به http://www.nytimes.com/ business تزریق نمی کند.

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

ویژگی‌های Glob از نحو متفاوت و انعطاف‌پذیرتری نسبت به الگوهای مطابقت پیروی می‌کنند. رشته‌های glob قابل قبول URLهایی هستند که ممکن است حاوی ستاره‌های "عام" و علامت سوال باشند. ستاره * با هر رشته ای با هر طولی از جمله رشته خالی مطابقت دارد در حالی که علامت سوال ? با هر شخصیت منطبق است.

مثلا glob 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 / علم .

{
  "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_idle" استفاده کنید.

مرورگر زمانی را برای تزریق اسکریپت‌ها بین "document_end" و بلافاصله پس از روشن شدن رویداد windowonload انتخاب می‌کند. لحظه دقیق تزریق بستگی به پیچیدگی سند و مدت زمان بارگذاری آن دارد و برای سرعت بارگذاری صفحه بهینه شده است.

اسکریپت‌های محتوایی که در "document_idle" اجرا می‌شوند، نیازی به گوش دادن به رویداد window.onload ندارند، آنها تضمین می‌شوند که پس از تکمیل DOM اجرا شوند. اگر یک اسکریپت قطعاً باید بعد از window.onload اجرا شود، برنامه افزودنی می‌تواند با استفاده از ویژگی document.readyState بررسی کند که آیا onload قبلاً اجرا شده است یا خیر.
document_start {: #document_start } رشته اسکریپت ها بعد از هر فایلی از css تزریق می شوند، اما قبل از اینکه هر DOM دیگری ساخته شود یا هر اسکریپت دیگری اجرا شود.
document_end {: #document_end } رشته اسکریپت ها بلافاصله پس از تکمیل DOM، اما قبل از بارگیری منابع فرعی مانند تصاویر و فریم ها، تزریق می شوند.

قاب ها را مشخص کنید

فیلد "all_frames" به برنامه افزودنی اجازه می‌دهد تا مشخص کند که فایل‌های جاوا اسکریپت و CSS باید به همه فریم‌های مطابق با الزامات URL مشخص شده تزریق شوند یا فقط به بالاترین فریم در یک برگه تزریق شوند.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
نام تایپ کنید توضیحات
all_frames {: #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);

در عوض، API های امن تری را ترجیح دهید که اسکریپت ها را اجرا نمی کنند:

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