Gérer les cas de non-respect du code hébergé à distance

Le code hébergé à distance, ou RHC, est ce que le Chrome Web Store appelle tout ce qui est exécuté par le navigateur et chargé depuis un autre emplacement que les fichiers de l'extension. Des éléments tels que JavaScript et WASM. Il n'inclut pas de données ni d'éléments tels que JSON ou CSS.

Pourquoi les centres d'intérêt réciproque ne sont-ils plus autorisés ?

Avec Manifest V3, les extensions doivent désormais regrouper tout le code qu'elles utilisent dans l'extension elle-même. Auparavant, vous pouviez injecter dynamiquement des tags de script à partir de n'importe quelle URL sur le Web.

On m'a dit que mon extension était RHC. Que se passe-t-il ?

Si votre extension a été refusée lors de l'examen avec une erreur Blue Argon, cela signifie que nos examinateurs considèrent que votre extension utilise du code hébergé à distance. Cela est généralement dû à une extension qui tente d'ajouter un tag de script avec une ressource distante (à partir du Web ouvert plutôt que des fichiers inclus dans l'extension) ou qui extrait une ressource à exécuter directement.

Identifier les centres d'intérêt réciproque

Il n'est pas particulièrement difficile de le détecter une fois que vous savez quoi chercher. Tout d'abord, recherchez les chaînes "http://" ou "https://" dans votre projet. En cas de non-respect des règles RHC, vous pourrez probablement les identifier. Si vous disposez d'un système de compilation complet ou si vous utilisez des dépendances de npm ou d'autres sources tierces, veillez à effectuer une recherche dans la version compilée du code, car c'est ce qui est évalué par le store. Si vous ne trouvez toujours pas le problème, l'étape suivante consiste à contacter l'assistance One Stop. Ils seront en mesure de décrire les cas de non-respect spécifiques et les éléments nécessaires pour publier l'extension dès que possible.

Que faire si une bibliothèque demande le code ?

Quelle que soit la provenance du code, il n'est pas autorisé à avoir un RHC. Cela inclut le code que vous n'avez pas créé, mais qui est simplement utilisé en tant que dépendance dans votre projet. Certains développeurs utilisant Firebase ont rencontré ce problème lorsque du code distant était inclus pour être utilisé dans Firebase Auth. Même s'il s'agit d'une bibliothèque propriétaire (c'est-à-dire détenue par Google), aucune exception n'est accordée pour RHC. Vous devez configurer le code pour supprimer le RHC ou mettre à jour votre projet afin de ne pas inclure le code de départ. Si vous rencontrez un problème où votre code ne charge pas le RHC, mais une bibliothèque que vous utilisez, la meilleure solution consiste à contacter l'auteur de la bibliothèque. Informez-le de ce problème et demandez-lui une solution de contournement ou des mises à jour de code pour le supprimer.

Que faire si vous avez hâte que votre bibliothèque soit mise à jour ?

Certaines bibliothèques envoient une mise à jour presque immédiatement après avoir reçu la notification, mais d'autres peuvent être abandonnées ou prendre du temps pour résoudre le problème. En fonction du problème constaté lors de la violation spécifique, vous n'aurez peut-être pas besoin d'attendre que leur déplacement soit débloqué et que leur examen soit satisfaisant. Plusieurs options s'offrent à vous pour être opérationnel rapidement.

Auditer le code

Êtes-vous certain que le code à l'origine de la requête est nécessaire ? Si vous pouvez simplement la supprimer ou si la bibliothèque qui est à l'origine de son problème peut en être supprimée, supprimez ce code pour terminer la tâche.

Sinon, existe-t-il une autre bibliothèque qui offre les mêmes fonctionnalités ? Essayez de rechercher npmjs.com, GitHub ou d'autres sites pour trouver d'autres options répondant aux mêmes cas d'utilisation.

Tremblements d'arbres

Si le code à l'origine du non-respect des règles RHC n'est pas utilisé, il peut être supprimé automatiquement par les outils. Les outils de compilation modernes tels que webpack, Rollup et Vite (pour n'en nommer que quelques-uns) disposent d'une fonctionnalité appelée tree-shaking. Une fois activé sur votre système de compilation, cet outil doit supprimer tous les chemins de code inutilisés. Cela peut signifier que vous disposez non seulement d'une version plus conforme de votre code, mais aussi d'une version plus simple et plus rapide. Il est important de noter que les bibliothèques ne peuvent pas toutes être agitées, mais elles le sont pour beaucoup. Pour certains outils, tels que Rollup et Vite, le tree shaking est activé par défaut. Webpack doit être configuré pour être activé. Si vous n'utilisez pas de système de compilation dans votre extension, mais que vous utilisez des bibliothèques de code, nous vous encourageons vivement à ajouter un outil de compilation à votre workflow. Les outils de compilation vous aident à écrire des projets plus sûrs, plus fiables et plus faciles à gérer.

Les spécificités de votre projet dépendent de votre projet. Toutefois, pour prendre un exemple simple avec Rollup, il vous suffit de compiler le code de votre projet pour ajouter une traque d'arbre. Par exemple, si vous disposez d'un fichier "main.js" qui ne se connecte qu'à Firebase Auth:

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

chrome.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);
  }
});

Ensuite, il vous suffit d'indiquer au rattachement le fichier d'entrée, un plug-in nécessaire pour charger les fichiers de nœud @rollup/plugin-node-resolve, ainsi que le nom du fichier de sortie qu'il génère.

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

En exécutant cette commande dans une fenêtre de terminal, vous recevrez une version générée du fichier main.js, compilée dans un seul fichier nommé compiled.js.

La propriété de consolidation peut être simple, mais elle est également très configurable. Vous pouvez ajouter toutes sortes de logiques et de configurations complexes. Consultez simplement leur documentation. L'ajout d'outils de compilation de ce type permet de réduire la taille du code et de gagner en efficacité. Dans ce cas, cela résout le problème lié au code hébergé à distance.

Modification automatique des fichiers

Un moyen de plus en plus courant d'intégrer du code hébergé à distance à votre codebase est en tant que sous-dépendance d'une bibliothèque que vous incluez. Si la bibliothèque X souhaite import bibliothèque Y à partir d'un CDN, vous devrez quand même la mettre à jour pour la charger à partir d'une source locale. Avec les systèmes de compilation modernes, vous pouvez facilement créer des plug-ins pour extraire une référence à distance et l'intégrer directement dans votre code.

Le code donné se présente donc comme suit:

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

Vous pouvez créer un petit plug-in de cumul.

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
    }
  }]
};

Une fois que vous avez exécuté la compilation avec le nouveau plug-in, chaque URL import distante est découverte, qu'il s'agisse ou non de notre code, d'une sous-dépendance, ou de tout autre élément.

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

Modifier des fichiers manuellement

L'option la plus simple consiste simplement à supprimer le code à l'origine du RHC. Ouvrez l'éditeur de texte de votre choix et supprimez les lignes non conformes. Ce n'est généralement pas cela recommandé, car il est fragile et peut être oublié. La maintenance de votre projet est donc plus difficile lorsqu'un fichier appelé "library.min.js" n'est pas réellement library.min.js. Au lieu de modifier les fichiers bruts, une option un peu plus facile à gérer consiste à utiliser un outil tel que patch-package. Il s'agit d'une option très puissante qui vous permet d'enregistrer les modifications apportées à un fichier plutôt que dans le fichier lui-même. Il est basé sur des fichiers de correctif, du même type d'éléments que ceux utilisés par des systèmes de contrôle des versions tels que Git ou Subversion. Il vous suffit de modifier manuellement le code non conforme, d'enregistrer le fichier de différences et de configurer le correctif avec les modifications à appliquer. Vous pouvez consulter un tutoriel complet dans le fichier README du projet. Si vous appliquez un correctif à un projet, nous vous encourageons vraiment à contacter le projet en question pour demander que les modifications soient effectuées en amont. Si le package "patch-package" facilite grandement la gestion des correctifs, il est encore plus efficace de n'avoir rien à corriger.

Que faire si le code n'est pas utilisé ?

À mesure que le codebase se développe, les dépendances (ou la dépendance d'une dépendance, ou de...) peuvent conserver les chemins de code qui ne sont plus utilisés. Si l'une de ces sections inclut du code permettant de charger ou d'exécuter un RHC, elle devra être supprimée. Peu importe s'il est mort ou inutilisé. Si vous ne l'utilisez pas, vous devez la supprimer, soit par le biais d'une attaque de restructuration, soit en corrigeant la bibliothèque pour la supprimer.

Existe-t-il une solution de contournement ?

D'une manière générale, non, les centres d'aide à la réactivité ne sont pas autorisés. Toutefois, dans quelques rares cas, cela est autorisé. Ce sont presque toujours des cas où aucune autre option ne peut être envisagée.

API User Scripts

Les scripts utilisateur sont de petits extraits de code généralement fournis par l'utilisateur. Ils sont destinés aux gestionnaires de scripts comme TamperMonkey et Conflictmonkey. Ces gestionnaires ne peuvent pas regrouper le code écrit par les utilisateurs. L'API User Script propose donc un moyen d'exécuter le code fourni par l'utilisateur. Il ne remplace pas chrome.scripting.executeScript ni d'autres environnements d'exécution de code. Les utilisateurs doivent activer le mode développeur pour pouvoir exécuter quoi que ce soit. Si l'équipe d'examinateurs du Chrome Web Store estime que la fiche n'est pas utilisée à des fins autres que celles prévues (c'est-à-dire avec le code fourni par l'utilisateur), la fiche peut être refusée ou être retirée du Play Store.

chrome.debugger

L'API chrome.debugger permet aux extensions d'interagir avec le protocole d'outils pour les développeurs Chrome. Il s'agit du même protocole que celui utilisé pour les outils de développement Chrome, ainsi que pour un nombre incroyable d'autres outils. Elle permet à une extension de demander et d'exécuter du code à distance. Tout comme les scripts utilisateur, il ne remplace pas chrome.scripting et offre une expérience utilisateur beaucoup plus remarquable. Pendant son utilisation, l'utilisateur verra une barre d'avertissement en haut de la fenêtre. Si la bannière est fermée ou ignorée, la session de débogage sera interrompue.

Capture d'écran de la barre d'adresse de Chrome affichant le message "Debugger Extension commencé à déboguer ce navigateur"
Capture d'écran de la barre d'adresse de Chrome affichant le message "Debugger Extension commencé à déboguer ce navigateur"

iFrames en bac à sable

Si vous devez évaluer une chaîne en tant que code et que vous vous trouvez dans un environnement DOM (par exemple, un script de contenu et non un service worker d'extension), une autre option consiste à utiliser un iFrame en bac à sable. Par mesure de sécurité, les extensions ne sont pas compatibles avec des fonctionnalités telles que eval() par défaut. Un code malveillant pourrait compromettre la sécurité des utilisateurs. Toutefois, lorsque le code n'est exécuté que dans un environnement sécurisé connu, tel qu'un iFrame isolé dans un bac à sable du reste du Web, ces risques sont considérablement réduits. Dans ce contexte, la Content Security Policy qui bloque l'utilisation de l'évaluation peut être levée, ce qui vous permet d'exécuter n'importe quel code JavaScript valide.

Si votre cas d'utilisation n'est pas couvert, n'hésitez pas à contacter l'équipe à l'aide de la liste de diffusion chromium-extensions pour obtenir des commentaires, ou ouvrez une nouvelle demande pour demander des conseils à l'assistance One Stop.

Que faire si vous n'êtes pas d'accord avec un verdict

L'application des règles peut être nuancée et l'examen implique une saisie manuelle, ce qui signifie que l'équipe du Chrome Web Store peut parfois accepter de modifier une décision d'examen. Si vous pensez qu'une erreur a été commise lors de l'examen, vous pouvez faire appel du refus via l'assistance One Stop.