Neo6502 › Artikel › Prophet
Einen Prophet-Server für den Neo6502 bauen
Prophet ist das Programm-Repository der Neo6502-Gemeinschaft: ein Client auf der Platine, ein Server irgendwo. Wir haben den Server in Go neu geschrieben, Sicherheit zuerst, und prophet.3617.fr online gestellt — mit unseren eigenen Programmen darin.
Auf dem Neo6502 installiert man Programme von der Konsole aus: prophet.neo, der von bocianu in Mad Pascal geschriebene Community-Client, spricht über ein WLAN-Modem (AT-Befehle) mit einem Server und lädt die Datei blockweise herunter. Der Upstream-Server prophet-server ist in Python/Flask geschrieben und ohne Lizenzdatei veröffentlicht; der heutige Client kann kein TLS, der öffentliche Server läuft daher über HTTP. Wir wollten einen eigenen Server — um AsteroNeo zu veröffentlichen, um das Protokoll zu lernen, bevor wir unseren eigenen Client schreiben, und um ihn selbst mit unseren Betriebsregeln zu hosten. Neo6502Prophet ist eine unabhängige Neuimplementierung in Go, protokollkompatibel, ohne eine einzige kopierte Zeile. Vier Sprints in zwei Tagen; das haben wir gemacht.
1. Das Protokoll aufnehmen, bevor eine Zeile geschrieben wird
Erster Schritt: den Client lesen, nicht den Server. prophet.pas sendet GET mit dem Header ResponseFormat: cli und parst Rohtext, Zeilenenden \n\r inklusive: /cat für die Kategorien, paginiertes /list/<cat>, /search, /app/<id> für den Steckbrief, /dirs und /files für den Baum, dann /files/<id>/<n> in Range-Blöcken mit 206-Antworten. Zwei Steuerbytes (\x83, \x82) umschließen die ID in Listen. /files/prophet/1 liefert das Update des Clients selbst. Das Daten-Repository ist ein Baum aus Ordnern Kategorie/Paket/desc.yaml, ältere Versionen unter _N/. All das steht in docs/ANALYSE-AMONT.md — mit Dank an bocianu, dessen Client, Server und Daten-Repository das alles erst möglich machen — samt dem, was nicht verifiziert ist: der öffentliche Server kann vom veröffentlichten Code abweichen.
2. Unsere Sicherheitsentscheidungen
Ein Programm-Repository ist ein öffentlicher HTTP-Dienst, der Dateien verteilt, die Platinen ausführen werden. Vor dem Schreiben haben wir die klassischen Risiken eines solchen Dienstes aufgelistet und beschlossen, jedes zu beantworten: nie ein Debug-Modus, standardmäßig lokales Lauschen; jede Aktion — das Aktualisieren des Repositorys, das ein git pull ausführt — authentifiziert; validierte und begrenzte Parameter, Fehler ohne Stacktrace; ausgelieferte Dateien auf ihren Ordner beschränkt, Links ignoriert; gefilterte IDs; ein Log mit Rotation; kein zwischen Anfragen geteilter Zustand; Katalog im Speicher ohne Zwischendatei neu geladen; ein Fingerabdruck für jede ausgelieferte Datei. Neun Punkte, in SECURITY.md festgehalten und getestet.
3. Unserer: Go, nur lesend, Sicherheit zuerst
Standardbibliothek und yaml.v3, eine statische Binary. Keine Schreib-API; /refresh verlangt ein Token von mindestens 16 Zeichen, in konstanter Zeit verglichen, hält eine Mindestverzögerung ein, führt git pull --ff-only ohne Shell und mit Timeout aus — ohne Token existiert der Endpunkt nicht (404). IDs per regulärem Ausdruck gefiltert, begrenzte Ganzzahlen, Sortierung per Whitelist, begrenzter Suchschlüssel, begrenzter Anfragekörper; jede ungültige Eingabe liefert einen textuellen 400 oder 404, nie einen Stacktrace. Dateipfade werden von der Wurzel aus neu berechnet und geprüft: im Ordner, reguläre Datei, kein Link. Der Katalog wird im Speicher gescannt und atomar ersetzt; jede Datei zeigt ihren SHA-256 im JSON. Der Server lauscht standardmäßig auf 127.0.0.1.
Das Textformat des Clients ist byteweise nachgebildet und so getestet. Eine Ergänzung: die Konsole des Neo zeigt nur ASCII, daher werden Titel und Beschreibungen für den Client transliteriert, während das JSON UTF-8 bleibt. Und ein doppelter Listener: HTTP auf 8998 für die heutigen Clients, natives HTTPS (TLS ≥ 1.2) für die Modems, die es können werden — der Pico W von PicoWiFiModemUSB, die Story „picowifitls“ auf Seiten von Neo6502drive.
4. Nicht alles ausliefern
Ein Programm-Repository verteilt Binaries, die Leute ausführen werden. Zwei Leitplanken. Statisch: neocheck liest jede .neo-Datei (Header, Blöcke, Grenzen, Kernelbereich); eine ungültige Datei wird nicht ausgeliefert, eine „rohe“ wird markiert (neo = ok/raw/invalid im JSON). Dynamisch: neotrace spielt jedes Programm in Phosphoneo mit der Spur der API-Aufrufe (--api-log) und der effektiven Adresse jedes Schreibzugriffs ab und rekonstruiert, was das Programm mit dem Kernel gemacht hat. Wiederholung vom 16. September: 56 von 56 Programmen (46 .neo, 10 .bas) laufen, kein unaufgelöster Schreibzugriff, kein bösartiges Verhalten beobachtet; eine Notiz: zc.neo schreibt in den Kernelbereich (Tabelle ab $FC20) ohne sichtbare Wirkung. Das Audit fand auch einen Phosphoneo-Bug — ein beim Laden ignorierter Grafikblock $FFFF — inzwischen behoben.
5. Eine Weboberfläche, ohne den Client zu brechen
Unter / nur an Browser ausgeliefert (Accept: text/html ohne ResponseFormat: cli): Katalograster mit Cover, Suche und Filter, Steckbrief mit Beschreibung, Version, Dateien, Größe, .neo-Status, SHA-256 und Download. Eingebettetes HTML, CSS und JS, keine Abhängigkeit, strikte CSP. Die Cover sind Screenshots, die ein Skript in Phosphoneo aufnimmt — 42 von 42 Paketen. Ein eigener Test prüft, dass der Text-Client exakt dieselbe Antwort erhält wie zuvor.
6. In Produktion: prophet.3617.fr
Ein eigener unprivilegierter Debian-13-Container (1 Kern, 512 MB), gehärteter systemd-Dienst (systemd-analyze security Exposition 1.3), nftables, das Port 8998 nur vom Reverse-Proxy annimmt, automatische Sicherheitsupdates. Caddy terminiert TLS (https://prophet.3617.fr) und reicht auch unverschlüsseltes HTTP auf 8998 für ESP8266-Clients durch, mit Crowdsec; ein stündlicher Timer aktualisiert den Spiegel des Community-Repositorys über das lokale Token. Mehrere Datenordner werden nebeneinander ausgeliefert: der Spiegel von bocianu und unser eigenes Repository, in dem AsteroNeo 0.2.0 das erste veröffentlichte Paket ist (/app/asteroneo, Cover inklusive). Stand 16. September: 37 Spiele, 5 Werkzeuge, 1 Sonstiges.
7. Was wir nicht behaupten
Der Server wurde nie von einer echten Neo6502-Platine abgefragt: wir haben keine, und der Ende-zu-Ende-Test über das Pico-W-Modem wartet auf die TLS-Story von Neo6502drive. Der Upstream-Client prüft den SHA-256, den wir ausgeben, nicht — das wird erst ein modifizierter Client tun. Das dynamische Audit sagt, was die Programme im Emulator getan haben, nicht, was sie auf einer Platine mit anderen Eingaben tun würden. Der Code des Servers hat noch kein öffentliches Repository. Als Nächstes kommt ein nativer grafischer Client („B“) für den Neo6502, mit vorkonvertierten Covern, TLS und Fingerabdruckprüfung.