Sunfish.Core con configuración INI (conserva comentarios), shares y locations, validación de rutas, motor HTTP propio (0.9/1.0/1.1, keep-alive, rangos, 304) y web de solo lectura (índice, ?$list, navegador de directorios clásico/moderno/texto, perfiles de cliente, recursos GIF, autodescarga). sunfish-cli con serve y modo rápido, sin TUI. Probado en un navegador moderno y con peticiones de cliente antiguo.a/t antes del fichero) y PUT por trozos (Content-Range + X-Sunfish-Upload), crear carpeta, renombrar y borrar con página de confirmación, tokens anti-CSRF sin cookies, usuarios con HTTP Basic (PBKDF2, caché y bloqueo por intentos), ZIP en flujo (Stored, CRC previo, Content-Length; nombres CP437 para clientes antiguos y UTF-8 para modernos). sunfish-cli user add|passwd|del|list. dotnet test: 140 pruebas en verde. AOT win-x64: ~3,8 MB sin avisos. Probado en un navegador moderno (arrastrar y soltar, borrado con confirmación), con usuario y contraseña, y ZIP descargado como cliente antiguo.Sunfish.exe (WinForms): interruptor y puerto, lista de shares con activar/desactivar, alta (también arrastrando carpetas a la ventana o sobre el .exe), edición, borrado, menú con abrir en el navegador y copiar URL por IP, usuarios, registro, área de notificación e instancia única (una segunda instancia pasa sus carpetas a la primera por una tubería).sunfish-cli (pestañas Estado con icono, Shares, Usuarios y Registro; formularios y preguntas en recuadros) y subcomandos share add|set|del|list.SunfishHost: reinicio al cambiar de puerto, guardado y recarga del fichero si lo cambia otro programa (conservando las opciones de línea de comandos como -p).build.ps1, build.sh, run.cmd, run-cli.cmd y run.sh.dotnet test: 149 pruebas en verde.Sunfish.exe autocontenido ~49 MB, ligero ~0,5 MB; sunfish-cli.exe AOT ~3,9 MB.share y recarga en caliente con serve. build.ps1 y build.sh se han comprobado solo en sintaxis (ejecutarlos hace git pull); las publicaciones que lanzan sí se han ejecutado a mano.LIST/NLST/MLSD/MLST, RETR/STOR/APPE/REST, carpetas, renombrar y mover, borrar, SIZE/MDTM, TYPE A, juegos de caracteres antiguos, perfiles por sufijo de usuario o SITE PROFILE, ABOR. El host arranca y para HTTP y FTP por separado y comparte con la web el bloqueo por intentos fallidos. GUI (fila «FTP en puerto»), TUI (teclas F y T) y serve muestran las direcciones ftp://. dotnet test: 173 pruebas en verde. AOT win-x64: ~4,1 MB. Probado con curl y con ftp.exe de Windows en modo activo.dotnet test: 189 pruebas en verde (incluida una búsqueda mDNS real que se salta si el 5353 no está disponible). AOT win-x64: ~8,3 MB. Probado con el redirector WebDAV de Windows (leer y escribir) y con la ventana Explorar de la GUI contra el propio servidor.Sunfish.Core/Mac; las subidas (formulario, PUT por trozos, STOR) se decodifican; descarga en MacBinary automática para el perfil mac y enlaces [.bin]/[.hqx] para los demás; FTP +mac con nombre.bin. Alias 8.3 estables (Shares/ShortNames.cs) en listados, enlaces, descargas y FTP +dos/+win16; las rutas se resuelven también por alias. El ._ sigue al fichero al renombrar, mover y borrar. dotnet test: 210 pruebas en verde. AOT win-x64: ~8,4 MB, sin avisos. Probado con el binario AOT por web y FTP (curl).Web/WebAdmin.cs, WEB.md), AllowFrom con redes CIDR (Net/AddressRules.cs), importación de la 2.0 (Config/LegacyImport.cs, SHARES-Y-RUTAS.md) y generador de QR propio (Qr/, APLICACIONES.md). GUI: ventana de QR, diálogo del panel web e importación al crear la configuración. CLI: admin, import-v2 y tecla C (QR) en la TUI. dotnet test: 252 pruebas en verde; el QR se comprueba leyéndolo con ZXing.Net (dependencia solo del proyecto de pruebas). AOT win-x64: ~8,7 MB, sin avisos. Probado con el binario AOT: import-v2, admin enable/allow/status, el panel con curl (401/200, QR, guardar que reinicia FTP sin cortar HTTP) y en un navegador.2.0 (LEGACY-2.0.md).master en un remoto privado. El README ya da las instrucciones para GitHub (rama main), para cuando se publique allí.| Proyecto | Salida | Propiedades |
|---|---|---|
Sunfish.Core |
biblioteca | IsAotCompatible, TreatWarningsAsErrors para avisos de AOT/trimming |
Sunfish.Cli |
sunfish-cli / sunfish-cli.exe |
PublishAot, InvariantGlobalization, StripSymbols |
Sunfish.WinForms |
Sunfish.exe |
OutputType=WinExe, UseWindowsForms, PublishSingleFile, IncludeNativeLibrariesForSelfExtract; autocontenido + EnableCompressionInSingleFile o dependiente del framework (pendiente, ver ARQUITECTURA.md) |
win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, osx-arm64.sunfish-cli se compila en su sistema.sunfish-cli (AOT):
clang, ld y las cabeceras de zlib.Sunfish.exe: solo el SDK.| Script | Función |
|---|---|
build.ps1 |
Windows. Detecta el RID, comprueba requisitos (no instala nada; da el comando), usa el repo actual o clona/actualiza, publica Sunfish.exe y sunfish-cli.exe, los deja en la raíz y explica cómo poner sunfish-cli en el PATH. Pendiente: si faltan las herramientas de C++, ¿falla o compila solo la GUI? |
build.sh |
Linux y macOS. Lo mismo para sunfish-cli (sugerencias para apt, dnf, pacman y brew) |
run.cmd |
dotnet run de Sunfish.WinForms, para doble clic |
run-cli.cmd |
dotnet run de Sunfish.Cli, para doble clic |
run.sh |
dotnet run de Sunfish.Cli en Linux y macOS |
SUNFISH_REPO_URL.publish aparte: build.* ya publica..gitignore: /Sunfish.exe, /sunfish-cli, /sunfish-cli.exe, /sunfish.conf, publish/.dotnet build dotnet test dotnet run --project src/Sunfish.WinForms dotnet run --project src/Sunfish.Cli -- [argumentos] dotnet publish src/Sunfish.Cli -c Release -r <RID> dotnet publish src/Sunfish.WinForms -c Release -r win-x64
tests/Sunfish.Tests)xUnit sobre net10.0, con InternalsVisibleTo desde Sunfish.Core. Las pruebas que tocan variables de entorno van en una colección sin paralelismo. Las de servidor arrancan SunfishHost en localhost con puertos libres y hablan con él por sockets.
| Área | Qué se prueba |
|---|---|
| HTTP | HTTP/0.9, 1.0 sin Host, LF solo, cabeceras raras, límites, keep-alive, chunked, Range, 304, HEAD |
| Multipart | Límites partidos entre búferes, varios ficheros, nombres con ruta de Windows o de Mac, subida cortada (no deja restos) |
| Locations | Prefijo más largo, comparación por segmentos, ocultación, directorios virtuales, raíz con y sin menú, /$sunfish |
| Rutas | .., %2e%2e, \, :, nombres reservados, enlaces que salen del share (con ramas por SO) |
| Permisos | Matriz operación × opción de share × web/FTP/WebDAV; usuarios |
| HTML | Escapado, entidades Latin-1, enlaces %XX en UTF-8, modo clásico sin <script> |
| CSRF / Auth | Tokens válidos, caducados y de otra ruta; PBKDF2; caché; bloqueo por intentos |
| FTP | Comandos, LIST en formato ls -l, MLSD, PASV/EPSV, PORT hacia otra IP rechazado, REST, TYPE A, juegos de caracteres |
| WebDAV | PROPFIND 0/1, infinity rechazado, MKCOL, MOVE/COPY, LOCK simulado, XML con DTD rechazado |
| Mac | Ver MAC-CLASICO.md |
| ZIP | Lo generado se lee con System.IO.Compression; Stored y Deflate; nombres CP437/UTF-8 |
| Config | Lectura, escritura conservando comentarios, errores con línea, importación de sunfish2 |
| QR | Matrices frente a vectores de referencia |
| Clientes | Perfil por User-Agent, ?p= propagado en los enlaces, sufijos +dos/+mac y SITE PROFILE en FTP |
| Alias 8.3 | Estabilidad al añadir y quitar ficheros, colisiones, transliteración, resolución alias → nombre real |
?$list |
Listado con índice presente, sin Listing, y webs con sus propios parámetros |
| DNS-SD | Formato de los anuncios y respuestas mDNS |
| Cliente WebDAV | Contra el propio servidor: listar, copiar en los dos sentidos, renombrar |
ftp.exe en modo activo; Carpetas web (WebDAV)..bin/.hqx, subidas MacBinary/BinHex, nombres con acentos..exe, bandeja, instancia única.build.ps1 con | iex; build.sh en Linux y macOS.