Tachibana

Neo6502 › Articles › Prophet

Créer un serveur Prophet pour le Neo6502

Prophet est le dépôt de programmes de la communauté Neo6502 : un client sur la carte, un serveur quelque part. Nous avons réécrit le serveur en Go, sécurité d'abord, et mis en ligne prophet.3617.fr — avec nos propres programmes dedans.

Par bmarty · Tachibana · 16 septembre 2026

Sur le Neo6502, on installe des programmes depuis la console : prophet.neo, le client communautaire écrit en Mad Pascal par bocianu, parle à un serveur par un modem WiFi (commandes AT) et télécharge le fichier par blocs. Le serveur amont, prophet-server, est écrit en Python/Flask et publié sans fichier de licence ; le client actuel ne sait pas faire de TLS, le serveur public est donc en HTTP. Nous voulions un serveur à nous — pour publier AsteroNeo, pour apprendre le protocole avant d'écrire notre propre client, et pour l'héberger chez nous avec nos règles d'exploitation. Neo6502Prophet est une réimplémentation indépendante en Go, compatible au niveau du protocole, sans une ligne copiée. Quatre sprints en deux jours ; voici ce qu'on a fait.

1. Relever le protocole avant d'écrire une ligne

Première étape : lire le client, pas le serveur. prophet.pas envoie GET avec un en-tête ResponseFormat: cli et parse un texte brut, fin de ligne \n\r comprise : /cat pour les catégories, /list/<cat> paginé, /search, /app/<id> pour la fiche, /dirs et /files pour l'arborescence, puis /files/<id>/<n> par blocs Range avec réponse 206. Deux octets de contrôle (\x83, \x82) encadrent l'identifiant dans les listes. /files/prophet/1 sert à la mise à jour du client lui-même. Le dépôt de données est un arbre de dossiers catégorie/paquet/desc.yaml, versions antérieures en _N/. Tout cela est consigné dans docs/ANALYSE-AMONT.md — avec un merci à bocianu, dont le client, le serveur et le dépôt de données rendent tout cela possible — et avec ce qui n'est pas vérifié : le serveur public peut différer du code publié.

2. Nos choix de sécurité

Un dépôt de programmes est un service HTTP public qui distribue des fichiers que des cartes vont exécuter. Avant d'écrire, nous avons dressé la liste des risques classiques d'un tel service et décidé de répondre à chacun : jamais de mode debug, écoute locale par défaut ; toute action — le rafraîchissement du dépôt, qui fait un git pull — authentifiée ; paramètres validés et bornés, erreurs sans trace ; fichiers servis confinés à leur dossier, liens ignorés ; identifiants filtrés ; journal avec rotation ; aucun état partagé entre requêtes ; catalogue rechargé en mémoire sans fichier intermédiaire ; empreinte de chaque fichier servi. Neuf points, consignés dans SECURITY.md et testés.

3. Le nôtre : Go, lecture seule, sécurité d'abord

Bibliothèque standard et yaml.v3, un binaire statique. Aucune API d'écriture ; /refresh exige un jeton d'au moins 16 caractères comparé en temps constant, respecte un délai minimal, fait git pull --ff-only sans shell et avec délai d'expiration — sans jeton, l'endpoint n'existe pas (404). Identifiants filtrés par expression régulière, entiers bornés, tri par liste blanche, clé de recherche limitée, corps de requête borné ; toute entrée invalide donne un 400 ou un 404 texte, jamais de trace. Les chemins de fichiers sont recalculés depuis la racine et vérifiés : dans le dossier, fichier régulier, pas un lien. Le catalogue est scanné en mémoire et remplacé atomiquement ; chaque fichier expose son SHA-256 dans le JSON. Le serveur écoute 127.0.0.1 par défaut.

Le format texte du client est reproduit octet pour octet et testé comme tel. Un ajout : la console du Neo n'affiche que l'ASCII, les titres et descriptions sont translittérés pour le client, le JSON reste en UTF-8. Et une double écoute : HTTP sur 8998 pour les clients actuels, HTTPS natif (TLS ≥ 1.2) pour les modems qui sauront le faire — le Pico W de PicoWiFiModemUSB, chantier « picowifitls » côté Neo6502drive.

4. Ne pas servir n'importe quoi

Un dépôt de programmes distribue des binaires que des gens vont exécuter. Deux garde-fous. Statique : neocheck lit chaque .neo (en-tête, blocs, bornes, zone du noyau) ; un fichier invalide n'est pas servi, un fichier « brut » est signalé (neo = ok/raw/invalid dans le JSON). Dynamique : neotrace rejoue chaque programme dans Phosphoneo avec la trace des appels API (--api-log) et l'adresse effective de chaque écriture, et reconstruit ce que le programme a fait au noyau. Rejeu du 16 septembre : 56 programmes sur 56 (46 .neo, 10 .bas) s'exécutent, aucune écriture non résolue, aucun comportement malveillant observé ; un point noté, zc.neo écrit dans la zone du noyau (table basée à $FC20) sans effet visible. L'audit a aussi trouvé un bug de Phosphoneo — un bloc graphique $FFFF ignoré au chargement — corrigé depuis.

5. Une interface web, sans casser le client

Servie à / aux navigateurs seulement (Accept: text/html sans ResponseFormat: cli) : grille du catalogue avec jaquette, recherche et filtre, fiche avec description, version, fichiers, taille, statut du .neo, SHA-256 et téléchargement. HTML, CSS et JS embarqués, sans dépendance, CSP stricte. Les jaquettes sont des captures d'écran prises dans Phosphoneo par un script — 42 paquets sur 42. Un test dédié vérifie que le client texte reçoit exactement la même réponse qu'avant.

6. En production : prophet.3617.fr

Un conteneur Debian 13 non privilégié dédié (1 cœur, 512 Mo), service systemd durci (exposition systemd-analyze security 1.3), nftables qui n'accepte le port 8998 que depuis le reverse proxy, mises à jour de sécurité automatiques. Caddy termine le TLS (https://prophet.3617.fr) et relaie aussi le HTTP en clair sur 8998 pour les clients ESP8266, avec Crowdsec ; un timer horaire rafraîchit le miroir du dépôt communautaire via le jeton local. Plusieurs dossiers de données sont servis côte à côte : le miroir de bocianu et notre dépôt propre, où AsteroNeo 0.2.0 est le premier paquet publié (/app/asteroneo, jaquette comprise). Au 16 septembre : 37 jeux, 5 outils, 1 divers.

7. Ce qu'on ne dit pas

Le serveur n'a jamais été interrogé depuis une vraie carte Neo6502 : nous n'en avons pas, et le test de bout en bout par le modem Pico W attend la story TLS de Neo6502drive. Le client amont ne vérifie pas le SHA-256 que nous exposons — seul un client modifié le fera. L'audit dynamique dit ce que les programmes ont fait dans l'émulateur, pas ce qu'ils feraient sur une carte avec d'autres entrées. Le code du serveur n'a pas encore de dépôt public. La suite est un client natif graphique (« B ») pour le Neo6502, avec jaquettes pré-converties, TLS et vérification d'empreinte.

Sources & liens

← Neo6502 · AsteroNeo → · Neo6502 →