Projets 04 / 04

Thème sombre du portail De Vinci

Une extension Firefox qui repeint le portail de l'école sans avoir accès à son code. Publiée sur le catalogue Firefox, code public.

État
Publiée
Année
2026
Durée
Septembre 2026
Rôle
Projet perso : conception, code, publication
Version
1.1.0, sur addons.mozilla.org
Outils
JavaScript, CSS, WebExtensions (Manifest V3), Python

01 — Contexte

Le point de départ

Sur la page de connexion du portail, mon extension remplissait bien mon adresse mail. Elle s'affichait dans le champ. Mais le bouton « Continuer » restait grisé, comme si le champ était vide.

Le portail de l'école, myDeVinci, sert à tout : emploi du temps, notes, absences, documents. Je l'ouvre plusieurs fois par jour, souvent le soir, et il n'existe qu'en clair. Les extensions qui inversent les couleurs donnent des photos en négatif et des alertes illisibles. J'ai écrit la mienne, sans aucun accès au code du site.

02

Le bouton grisé

La page de connexion est rendue côté client. Le framework de la page intercepte l'écriture de input.value : la valeur s'affiche, mais lui n'est pas prévenu, donc pour lui le champ est toujours vide.

J'ai dû passer par le setter natif de HTMLInputElement, envoyer moi-même les événements input et change, puis attendre que le bouton se réactive avant de cliquer. Au bout de 15 secondes sans réaction, le script abandonne.

03

Comment c'est construit

Une extension Manifest V3 sans script d'arrière-plan : deux scripts injectés à deux moments du chargement, un troisième sur la page de connexion, et une popup de réglages qui écrit dans le stockage synchronisé de Firefox.

Architecture de l'extension La popup écrit les préférences dans le stockage synchronisé. Au chargement de la page, un premier script lit une copie synchrone et pose des attributs sur l'élément racine, ce qui active les feuilles de style. Un second script corrige les styles écrits en dur et suit le contenu chargé ensuite. Sur la page de connexion, un troisième script pré-remplit l'adresse mail. Popup réglages storage.sync préférences PAGE DU PORTAIL early.js document_start <html data-dvx> active 3 feuilles CSS content.js document_end inline-fix.js luminance WCAG MutationObserver contenu AJAX auth-autofill.js page de connexion copie lit lit l'adresse écrit
Les feuilles de style ne font rien tant que la racine ne porte pas l'attribut data-dvx.

04

Les choix

  • Recolorer au lieu d'inverser

    Écarté : inverser toute la page

    Le portail contient environ 270 attributs style="" avec des couleurs claires écrites en dur, qu'aucune feuille de style ne peut surcharger proprement. Un script les relit, calcule leur luminance relative avec la formule du WCAG, et ne réécrit que les couleurs trop claires, en gardant leur teinte : une alerte rouge pâle devient une alerte rouge foncé, pas un gris.

    Le style d'origine est gardé dans une WeakMap. Désactiver l'option remet la page exactement comme avant, sans fuite de mémoire quand des éléments disparaissent.

  • Pas de flash blanc au chargement

    Écarté : attendre le stockage de l'extension

    Le stockage de l'extension répond de façon asynchrone. L'attendre, c'est laisser la page s'afficher en blanc une fraction de seconde. Le premier script lit donc une copie des réglages dans le localStorage de la page, pose les attributs sur <html> avant le premier affichage, et le second remet la copie à jour ensuite.

  • Un CSS qui ne fait rien tout seul

    Écarté : injecter et retirer les feuilles

    Aucune règle ne s'applique sans l'attribut data-dvx="on" sur <html>. Couper l'extension retire l'attribut : les trois feuilles restent chargées mais n'ont plus d'effet, sans recharger la page.

Côté permissions, deux domaines et le stockage, rien d'autre. Aucune requête réseau, aucune télémétrie : rien ne sort du navigateur.

05

Ce qui a coincé

  • Du contenu qui arrive après coupL'agenda et les tableaux du portail se remplissent en AJAX, après le passage du script. Un MutationObserver traite les nouveaux éléments au fil de l'eau, en ne regardant que ce qui vient d'être ajouté. Relire toute la page à chaque fois ralentirait un agenda de plusieurs centaines de cases.
  • Mon adresse mail dans le codeLe premier prototype avait mon adresse mail écrite en dur. Pour moi seul, ça allait. Publiée, elle se serait retrouvée dans chaque copie installée. C'est devenu un réglage de la popup, vide par défaut, et le dépôt exclut la page d'aperçu, qui reproduit mon tableau de bord.

06

La publication

  • ≈ 270styles écrits en dur dans le portail, recolorés un par un
  • 0requête réseau : rien ne sort du navigateur

Firefox n'installe durablement que les extensions signées par Mozilla. J'ai écrit un script Python qui emballe l'extension, l'envoie à l'API d'addons.mozilla.org, attend la validation automatique et récupère le fichier signé. Il n'utilise que la bibliothèque standard : le jeton JWT est signé à la main en HMAC-SHA256, et la requête multipart est construite sans bibliothèque HTTP.

Le même script publie sur deux canaux : non listé, signé en quelques minutes pour mon usage, et listé, qui passe par la revue de Mozilla pour apparaître dans le catalogue. La revue est passée : elle est sur le catalogue Firefox depuis septembre 2026.

07

À reprendre

  • Aucun test automatique.Si l'école change son site, je le découvrirai en l'utilisant. Des tests sur une copie figée des pages du portail me préviendraient avant.

Tous les projets

Contact

Parlons-en

pfery@outlook.fr