Premiers pas dans la création d’une extension Chrome

1

Chrome inclut un mécanisme d’extension assez puissant permettant d’utiliser tout ce que le Web peut nous offrir : HTML5 / CSS3 / Javascript mais aussi quelques APIs spécifiques aux extensions. Dans cet article, nous allons créer une première extension dans le but de bloquer l’accès internet à certains sites (exemple d’un contrôle parental).

Premiers pas

Pour comprendre et créer sa première extension Chrome, il suffit de suivre le “Getting Started” du site officiel Chrome. Il décrit qu’une extension se compose d’un fichier manifest.json contenant des informations générales mais aussi des permissions. On nous montre également comment initialiser une première popup en HTML avec le JS associé.

Voilà notre premier manifest.json :

On déclare donc un nom, une description ainsi que des permissions. Ensuite on spécifie l’icône de notre extension ainsi qu’un fichier HTML. Ce fichier sera affiché en popup dès que l’on cliquera sur notre extension.

Pour bloquer notre navigateur, nous allons demander un mot de passe qui sera redemandé au déblocage. Voici le fichier popup.html (très simpliste) :

Pour ajouter notre extension, il suffit d’aller dans la page des extensions Chrome puis de cliquer sur “Developer Mode” :chrome1

Cela ouvre de nouvelles options dont “Load unpacked extension…” et on peut aller chercher notre projet dans notre workspace…chrome2

Enfin, nous voyons notre projet bien chargé : notre icône est affichée dans la barre des extensions et la popup s’affiche bien.

zen3.png

zen4.png

Remarque : dans la page des extensions, un lien “Reload” est présenté : très pratique pour recharger notre extension (suite à des modifications de code) !

Ajout de comportements

Maintenant que notre extension et notre popup s’affichent correctement, nous allons ajouter un peu de comportement. Pour cela, nous allons créer “block.js” qui va permettre :

  • de changer de l’icône ok.png à block.png
  • de changer le texte dans la popup
  • de changer le texte du bouton
  • de vérifier que les 2 mots de passe saisies sont identiques (avant blocage).

La première chose à faire est donc de rajouter l’insertion de notre fichier JS : <script src="block.js"></script>

Ensuite, on se créé une fonction “block” que l’on va appeler sur le click du bouton. Pour changer l’icône, on peut se baser sur la documentation et les exemples fournis sur le site Chrome Extension. Il faut utiliser la fonction suivante : chrome.browserAction.setIcon({path:"ok.png"}); Nous rajoutons en même temps le code JS pour tester les passwords et changer le texte.

Naturellement, nous changeons le code de notre bouton en :

<input type="button" id="block" value="Block Web Access" onclick="block();"/>.

Là, nous faisons un petit “reload”, on va sur notre bouton et RIEN ! Pourquoi ? Comment ? Que faire ?… Là où faire des extensions Chrome est vraiment sympa, c’est que l’on développe une appli Web. Un petit clic droit sur l’icône puis sur “Inspect Popup” et nous pouvons lancer les “Chrome Dev Tools” : à nous le debugging !!

Pour réafficher notre popup, nous pouvons lancer dans la console un location.reload(true) :

zen8.png

Nous avons accès aux sources :

zen9.png

Et quand on clique sur notre bouton, voici ce que la console affiche :

zen10.png

Génial, nous avons une explication : Chrome, avec ses politiques de sécurité par défaut, n’autorise pas l’exécution de javascript dans le fichier HTML. Il faut absolument binder les évènements dans le fichier JS associé. Voilà un petit lien explicatif pour les plus curieux ici

Voilà le fichier JS au complet :

Du coup, on reload notre application et voilà ce que cela donne si on ne saisit pas de mot de passe.

zen5.png

Quand on valide notre petit formulaire, nous avons bien notre nouvelle l’icône et le texte qui change :

zen6.png

Voici une capture d’écran avec les Dev Tools : on peut ajouter des breakpoints, faire du pas à pas et par exemple utiliser le “Watch Expression” du debugger pour voir le mot de passe saisi :

zen12.png

Ajout du blocage

Pour déterminer si on peut bloquer les URL et quelle api il faut utiliser, il faut jeter un coup d’oeil sur la documentation des APIs Chrome.

Pour bloquer des URL, la documentation officielle nous indique qu’il faut utiliser les permissions “webRequest” et “webRequestBlocking”. Nous ajoutons donc ces permissions dans le fichier manifest.json

En s’inspirant des exemples de la doc, nous nous apercevons que les droits “optionnels” nécessitent un requête supplémentaire pour demander ce droit à l’utilisateur. Une fois la documentation parcourue, voici le code JS produit :

Nous noterons les deux bouts de code importants :

– la requête de permission

– le blocage de toutes les URL

Il ne nous reste plus qu’à tester notre code…

En entrant dans le mode bloqué, le site gdgnantes.com est bloqué alors que le site https://news.google.fr continue de fonctionner :

zen13.png

Ensuite, on clique sur “Stop blocking” et les sites refonctionnent :

zen14.png

Gestion du blocage : utilisation en background

Un premier bug est vite détecté… dès que la popup est fermée, le contrôle de blocage des URL n’est plus actif… On comprend rapidement que cela vient du fait que la popup étant fermée, tous nos contrôles effectués dans le JS de la page ne sont pas actifs. Pour contourner cela, Chrome propose la notion de background : un script qui tourne en tâche de fond.

Pour diffuser le passage de “bloqué” à “non bloqué”, notre popup va devoir mettre à jour notre script qui tourne en background. Pour cela, la fonction suivante permet d’accéder à notre script background.js :

chrome.extension.getBackgroundPage()

Pour ajouter le script, il faut modifier le manifest.json :

Pour stocker le mot de passe de façon permanente, nous allons le stocker dans background.js. Voici le code obtenu :

… Et le code de notre JS block.js

Pour faire plus joli, nous allons en profiter po
ur ajouter quelques CSS… au hasard, nous allons mettre du twitter bootstrap :)

Voilà ce que devient notre page popup.html

Après rechargement, nous obtenons une extension plutôt jolie et intéressante qui bloque bien toutes les pages exceptées “google.fr”.

zen15.png

zen16.png

zen17.png

Résumé

Nous avons vu comment créer une extension Chrome et utiliser les outils Chrome pour la débugger. La liste des APIs Chrome est assez importante (et il y a même une partie sur les APIs expérimentales).

Dans un monde idéal, il faudrait prendre le temps d’encoder le mot de passe et peut-être l’écrire de façon discrète dans le filesystem ou dans le localStorage (pour un stockage persistent)… Et puis… il faut noter un gros défaut de l’extension créée : tout le monde peut désactiver une extension. Il existe une api “management” mais on ne peut pas piloter sa propre extension.

Pour finir, nous n’avons pas abordé la partie déploiement sur le chrome web store mais ce n’est pas bien compliqué : il suffit d’avoir un compte “developer” -5$ tout de même- et d’uploader son application. Tout est décrit ici.

Partagez cet article.

A propos de l'auteur

Julien est Directeur Technique et consultant Java / Web à Zenika Nantes. Il intervient sur des missions de formation et d'architecture autour des technos Web frontend et backend tout en accompagnant les clients vers une démarche agile. Passionné, il aimera challenger les technologies en place et s'intéressera aux problématiques de performance. Très intéressé par les technologies Cloud (PAAS), il est certifié « Google App Engine Certified Developer », est formateur officiel sur « Pivotal Cloud Foundry » et a suivi la formation officielle Docker. Julien a co-fondé en Janvier 2011 le GDG Nantes, une communauté de développeurs des technologies Google, participe depuis 5 ans au Google I/O à San Francisco et organise le DevFest Nantes chaque année.

Un commentaire

  1. Bonjour j’essaye de creer une extension qui bloque plus de 2millions d’urls dans mon background.js
    mon application marche tres bien, mais le problemme c’est que chrome devient extremement lent

    dans mon background.js j’ai ceci:

    chrome.webRequest.onBeforeRequest.addListener(
    function(details) {

    }, { urls:
    [ “*://*.urls/*”,
    ] }, “blocking”);

Ajouter un commentaire