Tachibana
Language: English

Building a Prophet server for the Neo6502

#neo6502 #utilities

Prophet is the Neo6502 community's program repository: a client on the board, a server somewhere. We rewrote the server in Go, security first, and put prophet.3617.fr online — with our own programs in it.

By bmarty · Tachibana · 16 September 2026

On the Neo6502, programs are installed from the console: prophet.neo, the community client written in Mad Pascal by bocianu, talks to a server through a WiFi modem (AT commands) and downloads the file in chunks. The upstream server, prophet-server, is written in Python/Flask and published without a licence file; the current client cannot do TLS, so the public server runs over HTTP. We wanted a server of our own — to publish AsteroNeo, to learn the protocol before writing our own client, and to host it ourselves with our own operating rules. Prophet, our server, is an independent Go reimplementation, protocol-compatible, without a single copied line. Four sprints in two days; here is what we did. Follow-up (3 October 2026): Prophet 0.25: play in the browser, and the Oric.

1. Record the protocol before writing a line

First step: read the client, not the server. prophet.pas sends GET with a ResponseFormat: cli header and parses raw text, \n\r line endings included: /cat for categories, paginated /list/<cat>, /search, /app/<id> for the sheet, /dirs and /files for the tree, then /files/<id>/<n> in Range chunks with 206 responses. Two control bytes (\x83, \x82) bracket the id in listings. /files/prophet/1 serves the client's own update. The data repository is a tree of category/package/desc.yaml folders, older versions under _N/. All of it is written down in docs/ANALYSE-AMONT.md — with thanks to bocianu, whose client, server and data repository make all of this possible — along with what is not verified: the public server may differ from the published code.

2. Our security choices

A program repository is a public HTTP service distributing files that boards will execute. Before writing, we listed the classic risks of such a service and decided to answer each one: never a debug mode, local listening by default; every action — refreshing the repository, which runs a git pull — authenticated; validated and bounded parameters, errors without tracebacks; served files confined to their folder, links ignored; filtered ids; a log with rotation; no state shared between requests; catalogue reloaded in memory without an intermediate file; a fingerprint for every file served. Nine points, written down in SECURITY.md and tested.

3. Ours: Go, read-only, security first

Standard library and yaml.v3, one static binary. No write API; /refresh requires a token of at least 16 characters compared in constant time, honours a minimum delay, runs git pull --ff-only without a shell and with a timeout — without a token the endpoint does not exist (404). Ids filtered by regular expression, bounded integers, whitelisted sort fields, limited search key, bounded request body; any invalid input yields a text 400 or 404, never a traceback. File paths are recomputed from the root and checked: inside the folder, regular file, not a link. The catalogue is scanned in memory and swapped atomically; every file exposes its SHA-256 in the JSON. The server listens on 127.0.0.1 by default.

The client's text format is reproduced byte for byte and tested as such. One addition: the Neo's console only displays ASCII, so titles and descriptions are transliterated for the client while the JSON stays UTF-8. And a dual listener: HTTP on 8998 for today's clients, native HTTPS (TLS ≥ 1.2) for the modems that will be able to — the Pico W of the Oric Wi-Fi modem.

4. Do not serve just anything

A program repository distributes binaries people will run. Two safeguards. Static: neocheck reads every .neo (header, blocks, bounds, kernel area); an invalid file is not served, a "raw" file is flagged (neo = ok/raw/invalid in the JSON). Dynamic: neotrace replays every program in Phosphoneo with the API call trace (--api-log) and the effective address of every write, and reconstructs what the program did to the kernel. Replay of 16 September: 56 programs out of 56 (46 .neo, 10 .bas) run, no unresolved write, no malicious behaviour observed; one note, zc.neo writes into the kernel area (table based at $FC20) with no visible effect. The audit also found a Phosphoneo bug — a $FFFF graphics block ignored at load — since fixed.

5. A web interface, without breaking the client

Served at / to browsers only (Accept: text/html without ResponseFormat: cli): catalogue grid with cover, search and filter, sheet with description, version, files, size, .neo status, SHA-256 and download. Embedded HTML, CSS and JS, no dependency, strict CSP. Covers are screenshots taken in Phosphoneo by a script — 42 packages out of 42. A dedicated test checks that the text client receives exactly the same response as before.

6. In production: prophet.3617.fr

A dedicated unprivileged Debian 13 container (1 core, 512 MB), hardened systemd service (systemd-analyze security exposure 1.3), nftables accepting port 8998 from the reverse proxy only, automatic security updates. Caddy terminates TLS (https://prophet.3617.fr) and also relays plain HTTP on 8998 for ESP8266 clients, with Crowdsec; an hourly timer refreshes the mirror of the community repository through the local token. Several data folders are served side by side: bocianu's mirror and our own repository, where AsteroNeo 0.2.0 is the first published package (/app/asteroneo, cover included). As of 16 September: 37 games, 5 tools, 1 other.

7. What we do not claim

Update of 26 September 2026: the server is now queried from a real Neo6502 board, by ProphetGui — the native graphical client announced here ("B") — and the Pico W modem. ProphetGui checks every downloaded file against its CRC-32, which the server exposes (/crc32/<id>); the upstream client checks no fingerprint. Our repository offers Neo6502 programs, all tested on the board, among them Trinity (firmware), NeoDOS, NeoNavigator, ProphetGui, NeoLegacy, Le Tombeau d'Axayacatl, Bus'd Out, NeoTel, Trivia Savant, Poker and AsteroNeo — plus Astéroric and OricTel for the Oric. The dynamic audit says what the programs did in the emulator, not what they would do with other inputs. The server's code has no public repository yet.

Sources & links

← Neo6502 · Prophet 0.25 → · SWD → · AsteroNeo → · Neo6502 →