סקריפטים של תוכן הם קבצים שפועלים בהקשר של דפי אינטרנט. באמצעות Document Object Model (DOM) רגיל, הוא יכול לקרוא פרטים על דפי האינטרנט שבהם הדפדפן מבקר, לבצע בהם שינויים ולהעביר מידע לתוסף ההורה.
הבנת היכולות של סקריפט התוכן
סקריפטים של תוכן יכולים לגשת לממשקי ה-API של 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;
בנוסף, סקריפט התוכן יכול לגשת ישירות לממשקי ה-API הבאים של Chrome:
סקריפטים של תוכן לא יכולים לגשת ישירות לממשקי API אחרים.
עבודה בעולמות מבודדים
סקריפטים של תוכן שוכנים בעולם מבודד, ומאפשרים לסקריפט תוכן לבצע שינויים בסביבת ה-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"]
}
],
...
}
שם | תיאור | התיאור |
---|---|---|
matches {: #matches } |
חובה. מציין לאילו דפים יוחדר סקריפט התוכן הזה. כדי לקבל מידע נוסף על החרגה של כתובות URL, אפשר לעיין בקטע תבניות התאמה ולקבל פרטים נוספים על התחביר של המחרוזות האלה ותבניות התאמה ועולמות של התאמה. | |
css {: #css } |
אופציונלי. הרשימה של קובצי ה-CSS שיש להחדיר לדפים תואמים. הם מוחדרים לפי הסדר שבו הם מופיעים במערך הזה, לפני ש-DOM כלשהו נוצר או מוצג עבור הדף. | |
js {: #js } |
אופציונלי. רשימת קובצי ה-JavaScript שיש להחדיר לדפים תואמים. הערכים האלה מוחדרים לפי הסדר שבו הם מופיעים במערך הזה. | |
match_about_blank {: #match_about_blank } |
boolean | אופציונלי. האם הסקריפט צריך להזריק למסגרת about:blank שבה מסגרת ההורה או מסגרת הפתיחה תואמות לאחת מהתבניות שהוצהרו ב-matches . ברירת המחדל היא false . |
החרגת התאמות וכדורי תוכן
אפשר להתאים אישית את התאמת הדפים שצוינו על ידי הכללת השדות הבאים ברישום של המניפסט.
שם | תיאור | התיאור |
---|---|---|
exclude_matches {: #exclude_matches } |
אופציונלי. לא כולל דפים שסקריפט התוכן הזה היה מוחדר אליהם בדרך אחרת. למידע נוסף על התחביר של מחרוזות אלה, אפשר לעיין בקטע תבניות התאמה. | |
include_globs {: #include_globs } |
אופציונלי. המערכת מחילה את ההגדרה הזו אחרי matches כדי לכלול רק את כתובות ה-URL שמתאימות גם לכדור הארץ הזה. משמש לאמולציה של מילת המפתח @include Gareasemonkey. |
|
exclude_globs {: #exclude_globs } |
אופציונלי. המערכת החילה אחרי matches כדי להחריג כתובות URL שתואמות לכדור הארץ הזה. משמש לאמולציה של מילת המפתח @exclude Greasemonkey. |
סקריפט התוכן יוכנס לדף אם כתובת ה-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/ 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"]
}
],
...
}
זמן ריצה
כשהקובץ של 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"]
}
],
...
}
שם | תיאור | התיאור |
---|---|---|
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"]
}
],
...
}
שם | תיאור | התיאור |
---|---|---|
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);
במקום זאת, עדיף להשתמש בממשקי 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);