Aller au contenu
SheetForge

Marché de plugins Web

L'application web dispose d'un marché de plugins pour installer des plugins SheetForge dans le navigateur, plus un chemin séparé pour sideloader un plugin non revu depuis une URL GitHub. Le même marché, reconstruit en UIToolkit, est aussi livré à l'intérieur d'Unity.

Le registre — un fichier statique, deux lecteurs

Le listing du marché provient d'un unique fichier de registre statique (public/registry/plugins.json) que l'application web et la fenêtre de marché intégrée à Unity lisent toutes deux. Il n'y a qu'une seule liste, si bien que les deux surfaces montrent toujours le même catalogue.

SheetForge n'héberge pas les binaires de plugin. C'est la propre release GitHub de chaque auteur qui le fait. L'entrée du registre est de la métadonnée plus un hash épinglé — pas une copie du plugin.

Verrouillage par hash — l'intégrité avant que le cœur ne voie un octet

Chaque entrée du registre porte le SHA-256 capturé au moment où le plugin a été approuvé. À l'acquisition, chaque octet reçu est vérifié contre ce hash avant même d'atteindre le cœur. Un désaccord d'un seul octet est refusé.

C'est ce qui rend sûr le fait que « le binaire vit sur le GitHub de quelqu'un d'autre » : la release peut être retéléchargée depuis n'importe où, mais seuls les octets exacts approuvés sont jamais chargés.

Installation en un clic via le proxy serveur

Les navigateurs ne peuvent pas récupérer directement les assets de release GitHub — les règles cross-origin (CORS) le bloquent. L'acquisition passe donc par une route de proxy serveur (api/market/artifact, câblée via l'ArtifactProxy dans lib/market/install.ts), qui récupère la release côté serveur et la retransmet en flux. L'installation tient donc en un clic.

Un chemin de téléchargement puis import manuel demeure comme repli secondaire pour quand le proxy ne peut pas atteindre une release. Il passe par la même vérification de hash — un fichier importé n'est pas davantage digne de confiance qu'un fichier passé par le proxy.

La barrière de compatibilité — après l'intégrité, avant l'enregistrement

Réussir la vérification de hash prouve que les octets sont ceux approuvés. Cela ne dit rien sur si cet hôte peut lire le format de ce plugin, ce qui est une seconde question, séparée.

La réponse vient de la DLL vérifiée elle-même : une déclaration au niveau de l'assembly nommant la génération de format de plugin pour laquelle elle a été compilée, et la version d'hôte minimale qu'elle veut.

  • La fiche annonce, l'assembly décide. Une entrée de registre porte les deux mêmes valeurs (pluginFormat, minHost), si bien que le catalogue peut les montrer avant que vous ne téléchargiez. La barrière elle-même lit la déclaration dans les octets qui viennent de passer la vérification. Une fiche peut être obsolète ; une déclaration compilée ne peut pas l'être.
  • Une barrière, trois chemins. L'installation depuis le marché, le sideload et un simple fichier local interrogent tous le même prédicat, si bien qu'aucune route ne peut accepter en silence ce qu'une autre refuse.
  • Tout ou rien par assembly. Un assembly refusé n'enregistre rien — jamais la moitié de ses contrats — et le refus nomme ce que l'assembly a déclaré face à ce que cet hôte lit.
  • Aucune déclaration, c'est très bien. Un plugin compilé avant que l'attribut n'existe est lu comme la première génération, sans exigence d'hôte, si bien qu'il se charge exactement comme il l'a toujours fait.

Mise en cache et déchargement

Les octets qui passent la vérification de hash sont mis en cache dans le navigateur (IndexedDB), si bien qu'un plugin activé dans la liste se charge automatiquement lors des visites suivantes — vous l'activez une fois.

Désactiver ou retirer un plugin prend effet immédiatement : l'application demande au noyau de retirer cet assembly de la composition des plugins et de reconstruire la session, de sorte que ses types de cellule, enums, modèles, préréglages de couleur, actions du studio et calques du canevas disparaissent sans actualisation. (.NET lui-même ne décharge jamais un assembly : les octets restent résidents dans la page, inertes ; si vous réactivez le même plugin, le noyau réactive l'assembly résident au lieu de le charger une seconde fois.)

Sideloader un plugin non revu depuis une URL GitHub

Séparément du registre organisé, vous pouvez remettre à l'application une URL GitHub arbitraire pour sideloader un plugin non revu (lib/market/sideload.ts, servi par api/market/github). Ceci sert à essayer un plugin qui n'est pas dans le catalogue.

Comme cet axe prend une URL fournie par l'utilisateur plutôt qu'une entrée de registre validée, c'est l'unique endroit qui impose directement une défense SSRF :

  • L'URL doit se résoudre vers un hôte de la famille GitHubgithub.com, raw.githubusercontent.com, release-assets.githubusercontent.com et similaires — mis en correspondance exactement, en minuscules.
  • Les redirections qui fuiraient vers un réseau interne sont bloquées à cette frontière.

Les artefacts sideloadés sont mis en cache sous une étiquette de propriétaire distincte (sideload:). Un plugin non revu qui partagerait par hasard ses octets avec une entrée du registre reste donc séparé de celui organisé — un sideload ne se fait jamais passer pour un plugin approuvé.

GitHub comme source d'import

Les deux chemins font transiter les octets du plugin par le même pipeline :

  • L'installation depuis le registre récupère l'artefact hébergé sur la release GitHub de l'auteur via le proxy serveur, puis le vérifie contre le SHA-256 épinglé.
  • Le sideload accepte une URL GitHub brute, restreinte aux hôtes de la famille GitHub, puis vérifie les octets de la même façon.

Dans les deux cas, la limitation CORS du navigateur sur les assets de release GitHub est gérée côté serveur, tandis que l'intégrité est préservée par la vérification de hash côté client avant que le cœur ne charge quoi que ce soit.

Le marché à l'intérieur d'Unity

Le marché de plugins Unity a été reconstruit en UIToolkit pour ressembler au marché web — une grille de cartes à côté d'un panneau de détail, lisant le même registre statique, avec le même rejet de désaccord de hash et le même avis d'installation en pleine confiance.

La connexion, ainsi que la liste de plugins et les préréglages conservés par le navigateur, restent réservés au web ; la fenêtre Unity est la surface de catalogue et d'installation.

Pages associées