טיפול בהפרות של קוד באירוח מרוחק

קוד שמתארח מרחוק, או RHC, הוא השם שחנות האינטרנט של Chrome נותנת לכל דבר שמופעל על ידי הדפדפן ונטען ממקום אחר ולא מהקבצים של התוסף עצמו. למשל JavaScript ו-WASM. היא לא כוללת נתונים או דברים כמו JSON או CSS.

למה כבר אי אפשר להשתמש ב-RHC?

ב-Manifest V3, תוספים צריכים עכשיו לכלול את כל הקוד שהם משתמשים בו בתוך התוסף עצמו. בעבר, הייתה אפשרות להחדיר באופן דינמי תגי סקריפט מכל כתובת URL באינטרנט.

נאמר לי שהתוסף שלי כולל RHC. מה הבעיה?

אם התוסף שלך נדחה במהלך הבדיקה עם השגיאה Blue Argon, המשמעות היא שהבודקים שלנו סבורים שהתוסף שלך משתמש בקוד שמתארח מרחוק. בדרך כלל, השגיאה הזו מתרחשת כשתוסף מנסה להוסיף תג סקריפט עם משאב מרוחק (כלומר, מהאינטרנט הפתוח ולא מהקבצים שנכללים בתוסף), או לאחזר משאב כדי להפעיל אותו ישירות.

איך מזהים RHC

לא קשה לזהות RHC אם יודעים מה לחפש. קודם כול, בודקים אם המחרוזות http://‎ או https://‎ מופיעות בפרויקט. אם יש לכם הפרה של RHC, סביר להניח שתוכלו לאתר אותה. אם יש לכם מערכת build מלאה, או אם אתם משתמשים בתלויות מ-npm או ממקורות אחרים של צד שלישי, הקפידו לחפש את הגרסה המהודרת של הקוד, כי זו הגרסה שנבדקת על ידי החנות. אם עדיין לא הצלחתם לזהות את הבעיה, השלב הבא הוא לפנות אל One Stop Support. הם יוכלו לפרט את ההפרות הספציפיות ולציין מה צריך לעשות כדי לפרסם את התוסף בהקדם האפשרי.

מה עושים אם ספרייה מבקשת את הקוד

לא משנה מאיפה הקוד מגיע, אסור שהוא יכלול RHC. זה כולל קוד שלא כתבתם, אבל אתם משתמשים בו כתלות בפרויקט שלכם. חלק מהמפתחים שמשתמשים ב-Firebase נתקלו בבעיה הזו כשקוד מרוחק נכלל לשימוש ב-Firebase Auth. למרות שמדובר בספרייה של צד ראשון (כלומר בבעלות Google), לא ניתן חריג ל-RHC. כדי להתחיל, צריך להגדיר את הקוד כך שה-RHC יוסר, או לעדכן את הפרויקט כך שהקוד לא ייכלל בו מלכתחילה. אם נתקלתם בבעיה שבה לא קוד שלכם טוען את RHC, אלא ספרייה שבה אתם משתמשים, הפעולה הכי טובה היא לפנות ליוצר הספרייה. צריך להודיע להם על כך ולבקש פתרון עקיף או עדכוני קוד כדי להסיר את הבעיה.

מה קורה אם לא רוצים לחכות לעדכון של ספרייה

חלק מהספריות ישלחו עדכון כמעט מיד אחרי קבלת ההודעה, אבל יכול להיות שספריות אחרות לא יטפלו בבעיה או שיעבור זמן עד שהבעיה תיפתר. בהתאם למה שקורה בהפרה הספציפית, יכול להיות שלא תצטרכו לחכות עד שההפרה תועבר לבדיקה ותאושר כדי שהחסימה תוסר. יש כמה אפשרויות שיעזרו לכם לחזור לפעילות במהירות.

ביקורת על הקוד

האם אתם בטוחים שהקוד שגורם לבקשה נחוץ? אם אפשר פשוט למחוק את הקוד או להסיר את הספרייה שגורמת לבעיה, אז מוחקים את הקוד וזהו.

לחלופין, האם יש ספרייה אחרת שמציעה את אותן תכונות? אפשר לנסות לבדוק ב-npmjs.com, ב-GitHub או באתרים אחרים כדי למצוא אפשרויות אחרות שמתאימות לאותם תרחישי שימוש.

Tree shaking

אם הקוד שגורם להפרה של כללי המדיניות בנושא RHC לא נמצא בשימוש בפועל, יכול להיות שהכלי יוכל למחוק אותו באופן אוטומטי. בכלי build מודרניים כמו webpack,‏ Rollup ו-Vite (אלה רק כמה דוגמאות) יש תכונה שנקראת tree-shaking. אחרי שמפעילים את התכונה tree shaking במערכת build, היא אמורה להסיר את כל נתיבי הקוד שלא נמצאים בשימוש. יכול להיות שתקבלו לא רק גרסה תואמת יותר של הקוד, אלא גם גרסה יעילה ומהירה יותר. חשוב לציין שלא כל הספריות ניתנות לניעור עצים, אבל רבות כן. בכמה כלים, כמו Rollup ו-Vite, האפשרות tree-shaking מופעלת כברירת מחדל. כדי להפעיל אותה ב-webpack, צריך להגדיר את הכלי. אם אתם לא משתמשים במערכת build כחלק מהתוסף, אבל כן משתמשים בספריות קוד, מומלץ מאוד לבדוק אפשרות להוסיף כלי build לתהליך העבודה. כלי Build עוזרים לכם לכתוב פרויקטים בטוחים, אמינים וקלים יותר לתחזוקה.

הפרטים הספציפיים של אופן ההטמעה של treeshaking תלויים בפרויקט הספציפי שלכם. אבל כדי לתת דוגמה פשוטה עם Rollup, אפשר להוסיף treeshaking רק על ידי קומפילציה של קוד הפרויקט. לדוגמה, אם יש לכם קובץ שמתעד רק כניסה ל-Firebase Auth, שנקרא main.js:

import { GoogleAuthProvider, initializeAuth } from "firebase/auth";

browser.identity.getAuthToken({ 'interactive': true }, async (token) => {
  const credential = GoogleAuthProvider.credential(null, token);
  try {
    const app = initializeApp({ ... });
    const auth = initializeAuth(app, { popupRedirectResolver: undefined, persistence: indexDBLocalPersistence });
    const { user } = await auth.signInWithCredential(credential)
    console.log(user)
  } catch (e) {
    console.error(error);
  }
});

לאחר מכן, כל מה שצריך לעשות הוא לציין ל-Rollup את קובץ הקלט, פלאגין שנדרש לטעינת קבצי צומת ‎@rollup/plugin-node-resolve ואת השם של קובץ הפלט שהוא יוצר.

npx rollup --input main.js --plugin '@rollup/plugin-node-resolve' --file compiled.js

אם מריצים את הפקודה הזו בחלון טרמינל, מקבלים גרסה שנוצרה של קובץ main.js, שכולה מקומפלת לקובץ אחד בשם compiled.js.

הסיכום יכול להיות פשוט, אבל הוא גם ניתן להגדרה מאוד. אפשר להוסיף כל מיני הגדרות ולוגיקה מורכבת. כדאי לעיין במסמכים שלהם. הוספת כלי בנייה כאלה תביא לקוד קטן ויעיל יותר, ובמקרה הזה, תפתור את הבעיה בקוד באירוח מרוחק.

עריכת קבצים באופן אוטומטי

דרך נפוצה יותר ויותר שבה קוד שמתארח מרחוק יכול להיכנס לבסיס הקוד שלכם היא כ-subdependency של ספרייה שאתם כוללים. אם ספרייה X רוצה לטעון ספרייה import מספריית Y מ-CDN, עדיין צריך לעדכן אותה כדי שהיא תיטען ממקור מקומי. במערכות בנייה מודרניות, אפשר ליצור בקלות פלאגינים לחילוץ הפניה מרחוק ולהטמיע אותה ישירות בקוד.

כלומר, אם יש קוד שנראה כך:

import moment from "https://unpkg.com/moment@2.29.4/moment.js"
console.log(moment())

אפשר ליצור תוסף קטן של Rollup.

import { existsSync } from 'fs';
import fetch from 'node-fetch';

export default {
  plugins: [{
    load: async function transform(id, options, outputOptions) {
      // this code runs over all of out javascript, so we check every import
      // to see if it resolves as a local file, if that fails, we grab it from
      // the network using fetch, and return the contents of that file directly inline
      if (!existsSync(id)) {
        const response = await fetch(id);
        const code = await response.text();

        return code
      }
      return null
    }
  }]
};

אחרי שמריצים את ה-build עם הפלאגין החדש, כל כתובת URL מרוחקת של import מתגלה, בלי קשר לשאלה אם היא הייתה הקוד שלנו, תלות משנית, תלות משנית משנית או בכל מקום אחר.

npx rollup --input main.js --config ./rollup.config.mjs --file compiled.js

עריכה ידנית של קבצים

האפשרות הכי פשוטה היא פשוט למחוק את הקוד שגורם ל-RHC. פותחים את הקובץ בכלי לעריכת טקסט ומוחקים את השורות שמכילות את ההפרה. בדרך כלל לא מומלץ לעשות את זה, כי זה לא אמין ויכול להיות שתשכחו מזה. כשקובץ בשם library.min.js הוא לא באמת library.min.js, קשה יותר לתחזק את הפרויקט. במקום לערוך את הקבצים הגולמיים, אפשר להשתמש בכלי כמו patch-package. זו אפשרות מאוד שימושית שמאפשרת לשמור שינויים בקובץ, ולא את הקובץ עצמו. הוא מבוסס על קבצי תיקון, כמו מערכות לניהול גרסאות כמו Git או Subversion. פשוט משנים ידנית את הקוד שמפר את המדיניות, שומרים את קובץ ה-diff ומגדירים את patch-package עם השינויים שרוצים להחיל. אפשר לקרוא הדרכה מלאה במסמך ה-Readme של הפרויקט. אם אתם מבצעים תיקון בפרויקט, אנחנו ממליצים מאוד לפנות לפרויקט ולבקש לבצע שינויים במעלה הזרם. הכלי patch-package מקל מאוד על ניהול תיקונים, אבל הכי טוב זה לא להצטרך לתקן כלום.

מה עושים אם הקוד לא נמצא בשימוש

ככל שבסיסי הקוד גדלים, יחסי תלות (או תלות בתלות, או תלות ב…) יכולים לשמור על נתיבי קוד שלא נמצאים יותר בשימוש. אם אחד מהקטעים האלה כולל קוד לטעינה או להפעלה של RHC, צריך להסיר אותו. לא משנה אם הוא לא פעיל או לא בשימוש. אם לא נעשה בו שימוש, צריך להסיר אותו באמצעות treeshaking או באמצעות תיקון של הספרייה.

האם יש פתרון עקיף כלשהו?

באופן כללי, לא. אסור להשתמש ב-RHC. עם זאת, יש מספר קטן של מקרים שבהם מותר להשתמש בשיטה הזו. כמעט תמיד מדובר במקרים שבהם אף אפשרות אחרת לא מתאימה.

User Scripts API

סקריפטים של משתמשים הם קטעי קוד קטנים שבדרך כלל מסופקים על ידי המשתמש, ומיועדים למנהלי סקריפטים של משתמשים כמו TamperMonkey ו-Violentmonkey. מנהלי התוספים האלה לא יכולים לאגד קוד שנכתב על ידי משתמשים, ולכן User Script API חושף דרך להריץ קוד שסופק על ידי המשתמש. האפשרות הזו לא מחליפה את browser.scripting.executeScript או סביבות אחרות להרצת קוד. כדי להריץ משהו, המשתמשים צריכים להפעיל את מצב הפיתוח. אם צוות הבדיקה של חנות האינטרנט של Chrome יחשוב שהתוסף משמש למטרה אחרת מזו שהוא נועד לה (כלומר, קוד שסופק על ידי המשתמש), יכול להיות שהתוסף יידחה או שהרישום שלו יוסר מהחנות.

browser.debugger

ממשק ה-API‏ browser.debugger מאפשר לתוספים לבצע אינטראקציה עם פרוטוקול כלי הפיתוח ל-Chrome. זהו אותו פרוטוקול שמשמש את כלי הפיתוח של Chrome ומספר עצום של כלים אחרים. באמצעות ההרשאה הזו, תוסף יכול לבקש ולהריץ קוד מרחוק. בדומה לסקריפטים של משתמשים, הוא לא תחליף ל-browser.scripting, והוא מספק חוויית משתמש הרבה יותר משמעותית. בזמן השימוש, המשתמש יראה סרגל אזהרה בחלק העליון של החלון. אם הבאנר ייסגר או יידחה, סשן הניפוי באגים יסתיים.

צילום מסך של סרגל הכתובות ב-Chrome עם ההודעה 'התוסף של כלי ניפוי הבאגים התחיל בניפוי הבאגים בדפדפן הזה'
צילום מסך של סרגל הכתובות ב-Chrome שמופיעה בו ההודעה 'Debugger Extension started debugging this browser' (התוסף Debugger התחיל לנפות באגים בדפדפן הזה)

מסגרות iframe שפועלות בארגז חול

אם אתם צריכים להעריך מחרוזת כקוד, ואתם נמצאים בסביבת DOM (לדוגמה, סקריפט תוכן, בניגוד ל-service worker של תוסף), אפשרות נוספת היא להשתמש ב-iframe עם ארגז חול. כאמצעי זהירות, תוספים לא תומכים בדברים כמו eval() כברירת מחדל. קוד זדוני עלול לסכן את הבטיחות והאבטחה של המשתמשים. אבל אם הקוד מופעל רק בסביבה בטוחה מוכרת, כמו iframe שמוגבלת לארגז חול משאר האינטרנט, הסיכונים האלה מצטמצמים מאוד. בהקשר הזה, אפשר לבטל את מדיניות אבטחת התוכן שחוסמת את השימוש ב-eval, וכך להפעיל כל קוד JavaScript תקין.

אם יש לכם תרחיש שימוש שלא מכוסה, אתם יכולים לפנות לצוות באמצעות רשימת התפוצה chromium-extensions כדי לקבל משוב, או לפתוח כרטיס חדש כדי לבקש הדרכה מOne Stop Support.

מה עושים אם לא מסכימים עם פסק הדין

אכיפת המדיניות היא תהליך מורכב, והבדיקה כוללת קלט ידני. לכן, יכול להיות שבמקרים מסוימים צוות חנות האינטרנט של Chrome יסכים לשנות החלטה לגבי ביקורת. אם לדעתכם חלה טעות בבדיקה, אתם יכולים לערער על הדחייה באמצעות One Stop Support.