النصوص البرمجية للمحتوى

النصوص البرمجية للمحتوى هي ملفات يتم تشغيلها في سياق صفحات الويب. وباستخدام نموذج عنصر المستند (DOM) القياسي، يمكنهم قراءة تفاصيل صفحات الويب التي يزورها المتصفح وإجراء تغييرات عليها وتمرير المعلومات إلى الإضافة الرئيسية.

فهم إمكانيات النصوص البرمجية للمحتوى

يمكن للنصوص البرمجية للمحتوى الوصول إلى واجهات برمجة تطبيقات Chrome التي تستخدمها الإضافة الرئيسية من خلال تبادل الرسائل مع الإضافة. ويمكنهم أيضًا الوصول إلى عنوان URL لملف إضافة باستخدام chrome.runtime.getURL() واستخدام النتيجة نفسها التي تستخدمها عناوين URL الأخرى.

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

بالإضافة إلى ذلك، يمكن للنص البرمجي للمحتوى الوصول إلى واجهات برمجة تطبيقات Chrome التالية مباشرةً:

يتعذّر على النصوص البرمجية للمحتوى الوصول إلى واجهات برمجة التطبيقات الأخرى مباشرةً.

العمل في عوالم منعزلة

تعيش النصوص البرمجية للمحتوى في بيئة معزولة، ما يسمح للنص البرمجي للمحتوى بإجراء تغييرات على بيئة JavaScript بدون التعارض مع الصفحة أو النصوص البرمجية للمحتوى الإضافية.

قد يتم تشغيل إضافة في صفحة ويب ذات رمز مشابه للمثال أدناه.

<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". ويمكن أن تتضمن ملفات JavaScript أو ملفات CSS أو كليهما. يجب أن تحدّد جميع النصوص البرمجية للمحتوى التي يتم تشغيلها تلقائيًا أنماط المطابقة.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
الاسم Type الوصف
matches {: #matches } مصفوفة من السلاسل يجب ملء هذا الحقل. يحدّد الصفحات التي سيتم إدخال نص المحتوى البرمجي فيها. اطّلع على أنماط المطابقة للحصول على مزيد من التفاصيل حول بنية هذه السلاسل والأنماط والجداول الزمنية المطابقة للحصول على معلومات عن كيفية استبعاد عناوين URL.
css {: #css } مصفوفة من السلاسل اختيارية. قائمة ملفات CSS المطلوب إدخالها في الصفحات المطابقة. يتم إدخال هذه العناصر بالترتيب الذي تظهر به في هذه المصفوفة، قبل إنشاء أي نموذج DOM أو عرضه للصفحة.
js {: #js } مصفوفة من السلاسل اختيارية. قائمة ملفات JavaScript التي سيتم إدخالها في الصفحات المطابقة. يتم إدخال هذه البيانات بالترتيب الذي تظهر به في هذه الصفيفة.
match_about_blank {: #match_about_blank } boolean اختيارية. يمكنك اختيار ما إذا كان يجب إدخال النص البرمجي في إطار about:blank حيث يتطابق الإطار الرئيسي أو الإطار المفتوح مع أحد الأنماط الموضَّحة في السمة matches. يكون الإعداد التلقائي هو false.

استبعاد المطابقات والكرة الأرضية

يمكن تخصيص مطابقة الصفحة المحددة من خلال تضمين الحقول التالية في تسجيل البيان.

الاسم Type الوصف
exclude_matches {: #exclusion_matches } مصفوفة من السلاسل اختيارية. تستبعد الصفحات التي كان سيتم إدخال النص البرمجي للمحتوى هذا فيها. اطّلع على أنماط المطابقة للحصول على مزيد من التفاصيل حول بنية هذه السلاسل.
include_globs {: #include_globs } مصفوفة من السلاسل اختيارية. يتم تطبيقه بعد matches لتضمين عناوين URL التي تتطابق أيضًا مع هذه الكرة الأرضية. هذه الميزة مخصَّصة لمحاكاة الكلمة الرئيسية Greasemonkey من @include.
exclude_globs {: #exclusion_globs } صفيف من السلسلة اختيارية. تم تطبيقه بعد matches لاستبعاد عناوين URL التي تتطابق مع هذه الكرة الأرضية. هذه الميزة مخصَّصة لمحاكاة الكلمة الرئيسية @excludeGreasemonkey.

سيتم إدخال النص البرمجي للمحتوى في الصفحة إذا كان عنوان 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"]
    }
  ],
  ...
}

تتبع خصائص 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/ job /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/ التاريخ وليس في 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"]
    }
  ],
  ...
}

وقت التنفيذ

عند إدخال ملفات JavaScript في صفحة الويب، سيتحكّم الحقل run_at في ذلك. الحقل المفضّل والتلقائي هو "document_idle"، ولكن يمكن تحديده أيضًا باعتباره "document_start" أو "document_end" إذا لزم الأمر.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
الاسم Type الوصف
document_idle {: #document_idle } سلسلة الخيار المفضَّل استخدِم "document_idle" كلما أمكن ذلك.

يختار المتصفّح وقتًا لإدخال نصوص برمجية بين "document_end" وبعد تنشيط حدث windowonload مباشرةً. تعتمد لحظة الحقن الدقيقة على مدى تعقيد المستند والمدة التي يستغرِقها التحميل، ويتم تحسينها لتناسب سرعة تحميل الصفحة.

لا تحتاج النصوص البرمجية للمحتوى التي يتم تشغيلها في "document_idle" إلى رصد حدث window.onload، فهي مضمونة ليتم تشغيلها بعد اكتمال DOM. إذا كان النص البرمجي بحاجة بالتأكيد إلى التشغيل بعد window.onload، يمكن للإضافة التحقُّق مما إذا كان قد تم تنشيط onload من قبل باستخدام السمة document.readyState.
document_start {: #document_start } سلسلة يتم إدخال النصوص البرمجية بعد أي ملفات من css، ولكن قبل إنشاء أي DOM آخر أو تشغيل أي نص برمجي آخر.
document_end {: #document_end } سلسلة يتم إدخال النصوص البرمجية مباشرةً بعد اكتمال DOM، ولكن قبل تحميل الموارد الفرعية مثل الصور والإطارات.

تحديد الإطارات

يسمح الحقل "all_frames" للإضافة بتحديد ما إذا كان يجب إدخال ملفات JavaScript وCSS في جميع الإطارات التي تتطابق مع متطلبات عنوان URL المحدّدة أو في الإطار العلوي فقط في علامة تبويب.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
الاسم Type الوصف
all_frames {: #all_frames } boolean اختيارية. يتم ضبط القيمة التلقائية على 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 فقط لتجنب هجمات "man-in-the-middle".

تأكد من التصفية بحثًا عن صفحات الويب الضارة. على سبيل المثال، الأنماط التالية خطيرة:

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