Neo6502 › Artículos › Prophet
Crear un servidor Prophet para el Neo6502
Prophet es el repositorio de programas de la comunidad Neo6502: un cliente en la placa, un servidor en algún sitio. Reescribimos el servidor en Go, seguridad primero, y pusimos en línea prophet.3617.fr — con nuestros propios programas dentro.
En el Neo6502 los programas se instalan desde la consola: prophet.neo, el cliente comunitario escrito en Mad Pascal por bocianu, habla con un servidor a través de un módem WiFi (comandos AT) y descarga el archivo por bloques. El servidor original, prophet-server, está escrito en Python/Flask y publicado sin archivo de licencia; el cliente actual no sabe hacer TLS, así que el servidor público funciona en HTTP. Queríamos un servidor propio — para publicar AsteroNeo, para aprender el protocolo antes de escribir nuestro propio cliente, y para alojarlo nosotros con nuestras reglas de explotación. Neo6502Prophet es una reimplementación independiente en Go, compatible a nivel de protocolo, sin una sola línea copiada. Cuatro sprints en dos días; esto es lo que hicimos.
1. Registrar el protocolo antes de escribir una línea
Primer paso: leer el cliente, no el servidor. prophet.pas envía GET con una cabecera ResponseFormat: cli y parsea texto bruto, finales de línea \n\r incluidos: /cat para las categorías, /list/<cat> paginado, /search, /app/<id> para la ficha, /dirs y /files para el árbol, y luego /files/<id>/<n> por bloques Range con respuesta 206. Dos bytes de control (\x83, \x82) enmarcan el identificador en las listas. /files/prophet/1 sirve la actualización del propio cliente. El repositorio de datos es un árbol de carpetas categoría/paquete/desc.yaml, versiones anteriores en _N/. Todo está anotado en docs/ANALYSE-AMONT.md — con un agradecimiento a bocianu, cuyo cliente, servidor y repositorio de datos hacen posible todo esto — junto con lo no verificado: el servidor público puede diferir del código publicado.
2. Nuestras decisiones de seguridad
Un repositorio de programas es un servicio HTTP público que distribuye archivos que las placas van a ejecutar. Antes de escribir, hicimos la lista de los riesgos clásicos de un servicio así y decidimos responder a cada uno: nunca modo debug, escucha local por defecto; toda acción — el refresco del repositorio, que hace un git pull — autenticada; parámetros validados y acotados, errores sin traza; archivos servidos confinados a su carpeta, enlaces ignorados; identificadores filtrados; registro con rotación; ningún estado compartido entre peticiones; catálogo recargado en memoria sin archivo intermedio; huella de cada archivo servido. Nueve puntos, anotados en SECURITY.md y probados.
3. El nuestro: Go, solo lectura, seguridad primero
Biblioteca estándar y yaml.v3, un binario estático. Sin API de escritura; /refresh exige un token de al menos 16 caracteres comparado en tiempo constante, respeta un retardo mínimo, hace git pull --ff-only sin shell y con tiempo límite — sin token, el endpoint no existe (404). Identificadores filtrados por expresión regular, enteros acotados, ordenación por lista blanca, clave de búsqueda limitada, cuerpo de petición acotado; toda entrada inválida da un 400 o un 404 en texto, nunca una traza. Las rutas de archivo se recalculan desde la raíz y se verifican: dentro de la carpeta, archivo regular, no un enlace. El catálogo se escanea en memoria y se sustituye atómicamente; cada archivo expone su SHA-256 en el JSON. El servidor escucha en 127.0.0.1 por defecto.
El formato de texto del cliente se reproduce byte a byte y se prueba como tal. Un añadido: la consola del Neo solo muestra ASCII, así que títulos y descripciones se transliteran para el cliente mientras el JSON sigue en UTF-8. Y doble escucha: HTTP en el 8998 para los clientes actuales, HTTPS nativo (TLS ≥ 1.2) para los módems que sepan hacerlo — el Pico W de PicoWiFiModemUSB, historia «picowifitls» del lado de Neo6502drive.
4. No servir cualquier cosa
Un repositorio de programas distribuye binarios que la gente va a ejecutar. Dos salvaguardas. Estática: neocheck lee cada .neo (cabecera, bloques, límites, zona del núcleo); un archivo inválido no se sirve, un archivo «bruto» se señala (neo = ok/raw/invalid en el JSON). Dinámica: neotrace reproduce cada programa en Phosphoneo con la traza de llamadas a la API (--api-log) y la dirección efectiva de cada escritura, y reconstruye lo que el programa hizo al núcleo. Repetición del 16 de septiembre: 56 programas de 56 (46 .neo, 10 .bas) se ejecutan, ninguna escritura sin resolver, ningún comportamiento malicioso observado; un apunte: zc.neo escribe en la zona del núcleo (tabla basada en $FC20) sin efecto visible. La auditoría también encontró un bug de Phosphoneo — un bloque gráfico $FFFF ignorado al cargar — ya corregido.
5. Una interfaz web, sin romper el cliente
Servida en / solo a los navegadores (Accept: text/html sin ResponseFormat: cli): cuadrícula del catálogo con carátula, búsqueda y filtro, ficha con descripción, versión, archivos, tamaño, estado del .neo, SHA-256 y descarga. HTML, CSS y JS embebidos, sin dependencias, CSP estricta. Las carátulas son capturas tomadas en Phosphoneo por un script — 42 paquetes de 42. Un test dedicado comprueba que el cliente de texto recibe exactamente la misma respuesta que antes.
6. En producción: prophet.3617.fr
Un contenedor Debian 13 no privilegiado dedicado (1 núcleo, 512 MB), servicio systemd endurecido (exposición systemd-analyze security 1.3), nftables que solo acepta el puerto 8998 desde el proxy inverso, actualizaciones de seguridad automáticas. Caddy termina el TLS (https://prophet.3617.fr) y también retransmite el HTTP en claro en el 8998 para los clientes ESP8266, con Crowdsec; un temporizador horario refresca el espejo del repositorio comunitario mediante el token local. Se sirven varias carpetas de datos en paralelo: el espejo de bocianu y nuestro propio repositorio, donde AsteroNeo 0.2.0 es el primer paquete publicado (/app/asteroneo, carátula incluida). A 16 de septiembre: 37 juegos, 5 herramientas, 1 otro.
7. Lo que no decimos
El servidor nunca ha sido consultado desde una placa Neo6502 real: no tenemos ninguna, y la prueba de extremo a extremo por el módem Pico W espera a la historia TLS de Neo6502drive. El cliente original no verifica el SHA-256 que exponemos — solo lo hará un cliente modificado. La auditoría dinámica dice lo que los programas hicieron en el emulador, no lo que harían en una placa con otras entradas. El código del servidor aún no tiene repositorio público. Lo siguiente es un cliente nativo gráfico («B») para el Neo6502, con carátulas preconvertidas, TLS y verificación de huella.