Mercado de plugins web
La app web tiene un mercado de plugins para instalar plugins de SheetForge en el navegador, más una ruta separada para cargar lateralmente (sideload) un plugin sin revisar desde una URL de GitHub. El mismo mercado, reconstruido en UIToolkit, también se distribuye dentro de Unity.
El registro — un archivo estático, dos lectores
El listado del mercado viene de un único archivo de registro estático (public/registry/plugins.json) que tanto la app web como la ventana de mercado dentro de Unity leen. Hay una sola lista, así que las dos superficies siempre muestran el mismo catálogo.
SheetForge no aloja los binarios de los plugins. Lo hace el propio release de GitHub de cada autor. La entrada del registro es metadatos más un hash fijado — no una copia del plugin.
Hash fijado — integridad antes de que el núcleo vea un solo byte
Cada entrada del registro lleva el SHA-256 capturado cuando el plugin fue aprobado. Al adquirirlo, cada byte recibido se comprueba contra ese hash antes de que llegue nunca al núcleo. Una discrepancia de un solo byte se rechaza.
Esto es lo que hace seguro que "el binario viva en el GitHub de otra persona": el release se puede volver a descargar desde cualquier lugar, pero solo los bytes exactos aprobados llegan a cargarse.
Instalación de un clic mediante el proxy del servidor
Los navegadores no pueden obtener assets de release de GitHub directamente — las reglas de origen cruzado (CORS) lo bloquean. Así que la adquisición pasa por una ruta de proxy del servidor (api/market/artifact, conectada mediante ArtifactProxy en lib/market/install.ts), que obtiene el release del lado del servidor y lo retransmite de vuelta. La instalación es por lo tanto de un clic.
Queda una ruta de descarga y subida manual como respaldo secundario para cuando el proxy no puede alcanzar un release. Pasa por la comprobación de hash idéntica — un archivo subido no es más confiable que uno pasado por el proxy.
La barrera de compatibilidad — después de la integridad, antes del registro
Pasar la comprobación de hash prueba que los bytes son los aprobados. No dice nada sobre si este host puede leer el formato de ese plugin, que es una segunda pregunta separada.
La respuesta viene de la propia DLL verificada: una declaración a nivel de ensamblado que nombra la generación del formato de plugin para la que se construyó, y la versión de host más baja que requiere.
- El listado anuncia, el ensamblado decide. Una entrada del registro lleva los mismos dos valores (
pluginFormat,minHost), así que el catálogo puede mostrarlos antes de que descargues. La propia barrera lee la declaración de los bytes que acaban de pasar la verificación. Un listado puede estar desactualizado; una declaración compilada no puede estarlo. - Una barrera, tres rutas. La instalación desde el mercado, la carga lateral y un simple archivo local preguntan todos al mismo predicado, así que ninguna ruta puede aceptar en silencio lo que otra rechaza.
- Todo o nada por ensamblado. Un ensamblado rechazado no registra nada — nunca la mitad de sus contratos — y el rechazo nombra lo que el ensamblado declaró frente a lo que este host lee.
- Sin declaración está bien. Un plugin construido antes de que existiera el atributo se lee como la generación más antigua sin requisito de host, así que carga exactamente como siempre lo hizo.
Caché y descarga
Los bytes que pasan la comprobación de hash se guardan en caché en el navegador (IndexedDB), así que un plugin habilitado en la lista carga automáticamente en visitas posteriores — lo habilitas una vez.
Deshabilitar o eliminar un plugin tiene efecto de inmediato: la aplicación indica al núcleo que quite ese ensamblado de la composición de plugins y reconstruya la sesión, de modo que sus tipos de celda, enums, plantillas, preajustes de color, acciones del estudio y superposiciones del lienzo desaparecen sin refrescar. (.NET en sí nunca descarga un ensamblado: los bytes permanecen residentes en la página, inertes; si vuelves a habilitar el mismo plugin, el núcleo reactiva el ensamblado residente en lugar de cargarlo una segunda vez.)
Carga lateral de un plugin sin revisar desde una URL de GitHub
Separado del registro curado, puedes entregarle a la app una URL de GitHub arbitraria para cargar lateralmente un plugin sin revisar (lib/market/sideload.ts, servido por api/market/github). Esto es para probar un plugin que no está en el catálogo.
Como este eje toma una URL suministrada por el usuario en lugar de una entrada de registro verificada, es el único lugar que impone defensa SSRF directamente:
- La URL debe resolverse a un host de la familia GitHub —
github.com,raw.githubusercontent.com,release-assets.githubusercontent.comy similares — comparado de forma exacta, en minúsculas. - Las redirecciones que filtrarían hacia una red interna se bloquean en ese límite.
Los artefactos cargados lateralmente se guardan en caché bajo una etiqueta de propietario distinta (sideload:). Así que un plugin sin revisar que resulte compartir bytes con una entrada del registro se mantiene separado del curado — una carga lateral nunca se hace pasar por un plugin aprobado.
GitHub como origen de importación
Ambas rutas dirigen los bytes del plugin a través de la misma canalización:
- La instalación desde el registro obtiene el artefacto alojado en el release de GitHub del autor mediante el proxy del servidor, y luego lo comprueba contra el SHA-256 fijado.
- La carga lateral acepta una URL de GitHub en bruto, protegida a hosts de la familia GitHub, y luego comprueba los bytes de la misma manera.
En ambos casos, la limitación de CORS del navegador sobre los assets de release de GitHub se gestiona del lado del servidor, mientras que la integridad se preserva mediante la comprobación de hash en el cliente antes de que el núcleo cargue nada.
El mercado dentro de Unity
El mercado de plugins de Unity se reconstruyó en UIToolkit para parecerse al mercado web — una cuadrícula de tarjetas junto a un panel de detalle, que lee el mismo registro estático, con el mismo rechazo por discrepancia de hash y el mismo aviso de instalación de confianza total.
El inicio de sesión, y la lista de plugins y los preajustes que guarda el navegador, permanecen solo web; la ventana de Unity es la superficie de catálogo e instalación.
Páginas relacionadas
- SheetForge Web — la app del navegador donde vive el mercado
- Creación de plugins — cómo construir el plugin al que apunta una entrada del mercado