From 74b77135531ef28deef6e7c91fce2f4a26e709bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Martin?= Date: Wed, 7 Oct 2026 00:06:47 +0200 Subject: [PATCH] Devlog: "It was off", the website and the one firmware with the Debug Console in it (v0.12.0) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT --- .../content/devlog/roro9stack-console/dbg.png | Bin 0 -> 2407 bytes .../devlog/roro9stack-console/index.md | 266 ++++++++++++++++++ .../devlog/roro9stack-console/token.png | Bin 0 -> 4823 bytes 3 files changed, 266 insertions(+) create mode 100644 site/content/devlog/roro9stack-console/dbg.png create mode 100644 site/content/devlog/roro9stack-console/index.md create mode 100644 site/content/devlog/roro9stack-console/token.png diff --git a/site/content/devlog/roro9stack-console/dbg.png b/site/content/devlog/roro9stack-console/dbg.png new file mode 100644 index 0000000000000000000000000000000000000000..426022d2ed3e422d8a181c7853f1744edbe20edb GIT binary patch literal 2407 zcmY*a2~ZPh8tsq?YFI|F0Oc}M5#$u)a1{vG5D-uia5&^tV+IsOKmh}RgiNUnAdCS- zRG=k*qZ}C|h@4^9kqF@&cVLmTB#>wXAqfcyfouoIUAL>c`aiz@zW2TN{_das{f??5 z^^gDnsQY+h0|5Xw3*FytSAkZh*G?S-fE`voSoa^UKU|y)ADlR%_swwBaUDDTdpGd< zO+J!bo3(bl?W^3np;3olZ@JZ&exTZ(VM+O8bS4&Cb*3RYD?7WRf7L=m^G-=?CIXEX z*pAWNu-K>tnRa&eYjy;aLYiNBIoTCc#}%-X3XM{ks~`Fbg?!1}OmDPveyJm$V~`p- zLEM~SDkKWVb5!(HGOI8oHL`FdM980PWA^qtRge#ymd2$_<1(c9Rv&6RQ$l}ZhiubC zIHwiOCC5+AoL?wA*?n#l^+vdt&$b>MGihDlV0AL*cU~wK$Z8)9W{hbM);#gO- zl+`6%llP5;l=l>;cM5le=25z?YKi`k&CyJGt+d_dJPxDqRsBaNM-RdB?flYq(6&VW zG~Xp8fQnoq0nb(^L&_URua;vJEXGBNGoq|6Wo(8uLSu~Ht-~1FVuvF@ofkh|phY;aRfx@Sc=#5_*RooJ?xJm`G(V<~&u$(C4v zB>G&pZyTEw2M=yie1J1SYmuHAiI?S7Wyhbu@+26!v!)P<>%-gX+OA23{hsICsl4=nFAdxpk{btIl71g z=s^1z((g7ho9ygt%vON~=jdIsY!B@DBU`UcpBiQ@y2vy%r5;-u`n5%qu8-nwUmDnl zPU3HYJ1vF6v3_|<5PHy=+qzsvgj}N)@hYyFxYU?`6obp0P0n@7v)1GPbPCVgjbcpr}558#GK~IpX9z%qL4;1>GF~T_w0a zp>3a_i=xv;KP@P37 z(|+j;dj7jo0ngbSvJwykHUP#fmYhTtoXByiFo}kD*F)1vYEpz5Zv+Qht^#2>dIv^1 zLl!KRSs!<}R&y;#iocLyL@j{1xx;_>(|VkE+(j|DhddE540x`(X2;%!29HlclL2iJ z0S8FdseiJO{2*``sb~5jk22W8iSy38J2fqEzT(_{!i?8S z(6Ucxi_87E@=|txDD-6Wu5IyHcgYwH%wl8OWcv!}&lj!?yqQV8HqXc9^G}(yq(TJ~-M zghlgMatoxEr*U(-9NDP&hqqwnLPLL3>fhV~AXyk4A7yr;7L!+H{S~M{oiq?;b+;(;*?b2jKEr+`c8{|)xe}^( zq5eL zSQZ6zfY4ZpRw-g;@J0TRYl}#&({+ET2@1YEuk6UjT@uG&8WWP2LV;*M$Z&s}j|-7) z)lAjTj_zcFV+3j1DJd{74 zjzMXXN&XOyPNtQ%y&G2P>wn=lZM+rip1InM(n5lu30OO*B(O>&JbfM~+sDnXuF0}~ z48mM`e5Hdy%ZWEfCvH+y<4-6dT6Yzrqn>=)d&-b#?+WJ1mrRRDF;9Zod5v0X`^>E$Jy2H*$f-U2+EyQZQ6nnGu8a2oZ0by5e&ud^=p>-Qi}j2=(Rt7RKLp|E%oMr3+Ag fB);Yy077K?89Szq8Bm->$_*b+KWxMIXDI&x>S~g2 literal 0 HcmV?d00001 diff --git a/site/content/devlog/roro9stack-console/index.md b/site/content/devlog/roro9stack-console/index.md new file mode 100644 index 0000000..6b5ceb4 --- /dev/null +++ b/site/content/devlog/roro9stack-console/index.md @@ -0,0 +1,266 @@ ++++ +title = '''It was off''' +description = '''roro9stack gets a website, and writing down how its Debug Console works shows that only one person could ever use it. So the Debug Build is retired: one firmware, with the console in it, off until its owner switches it on. Then an evening of chasing a console that wouldn't come back and a memory leak, neither of which existed.''' +date = 2026-10-07T00:30:00+02:00 + +[extra] +topics = '''ESP32-S3 · Debugging · Security''' +read_label = '''Read what was off →''' +uid = '''debug: on, token set, client connected''' +dek = "A day of writing for [roro9stack](/devlog/roro9stack/), my firmware for the M5Stack Cardputer: a website, a user guide, and developer docs about the thing I like best in it, a console over Wi-Fi. Documenting it properly made one fact hard to miss: nobody else could have it. Fixing that deleted more than it added, and then cost me an evening looking for two bugs that turned out to be a switch in the Off position and TCP minding its own business." +byline = '''designed by interrogation, round twelve: fourteen questions thrown away, eight kept''' + +[extra.sign] +label = "Tokens leaked by the feature built to protect them" +note = "In a screenshot, taken over the console, of the one page that shows the token." +count = "1" +tone = "red" + +[[extra.cast]] +name = "The Debug Build" +role = "retired, v0.3.0 to v0.11.0" +text = "The same firmware plus a console over Wi-Fi, with its builder's token compiled in. Which is why it could never be published, and why the firmware I tested was never the one I released." + +[[extra.cast]] +name = "Port 3232" +role = "the Update Service, in every build since v0.3.0" +text = "Listens on the network in release builds, guarded by a signature. The counter-example to \"in a release, nothing listens\" that had been sitting there all along." + +[[extra.cast]] +name = "The token" +role = "100 bits, 20 characters" +text = "Made by the device, shown on one page of Settings and nowhere else. Read off a 240-pixel screen by a human, which is where the trouble started." + +[[extra.cast]] +name = "The dialog" +role = "\"Switch it on?\"" +text = "Opens with Cancel selected, as a question about a remote control should. Enter, Enter: still off. Works exactly as designed." + +[[extra.cast]] +name = "TIME_WAIT" +role = "two minutes, per closed connection" +text = "What TCP does with a connection it has closed, in case a late packet turns up. About 270 bytes each. Looks exactly like a leak if you only watch for one minute." ++++ + +## TL;DR + +- **roro9stack has a website:** [roro9stack.net](/), with an Install page that flashes a Cardputer from the browser, a [user guide](/guide/), [how-tos](/howto/), an [FAQ](/faq/), [developer docs](/dev/) generated from the repository, and this devlog, which moved here. +- **The Debug Build is gone.** There is one firmware (**v0.12.0**), and the Debug Console is in it: **off** until you switch it on in Settings, with a token the device makes itself. +- **The token never crosses the network.** The device sends a challenge, the client answers with an HMAC. Five wrong answers close the console for a minute. +- **It costs** 30 KB of flash and 88 bytes of RAM over the old release build. Off, nothing listens and nothing is allocated. +- Then I spent an evening on **a console that wouldn't come back on** (it was off) and **a memory leak of 230 bytes per reopening** (it was TCP). Both produced a real fix on the way, and one design change I had to undo. +- 468 host tests, 12 more than last time. The decision is [ADR 0010](/dev/decisions/0010-debug-console-in-every-build/). + +## The cast + +{{ cast() }} + +## A site, in four phases + +The [last post](/devlog/roro9stack-f1-r1/) ended with a device that installs its own releases. That makes it something another person could use, and another person needs somewhere to start that isn't a Gitea README. So the first half of the day was a website: a home page, an Install page, then a guide to each App, how-tos, an FAQ, and developer docs. + +Three things from that half are worth keeping. + +**Flashing from the browser, without a copy of the firmware.** The Install page uses ESP Web Tools and Web Serial. The obvious way is to copy the firmware image next to the page; then every release needs a rebuild of the site. Instead the page asks Gitea's API for the latest release, in the browser, and hands the flasher a manifest it builds on the spot. That only needed one header: Caddy, in front of Gitea, adds `Access-Control-Allow-Origin: https://roro9stack.net` to the release downloads and to the releases API, which are public anyway. A new release shows up on the page the moment it exists. + +**"Generated from the repository" met Zola.** The developer docs were to be built from `docs/`, the README and the firmware's own `help` text, not copied by hand. Zola refuses to read a file outside its own folder, and it resolves symlinks before deciding, so that door is closed too. So a small script writes those pages, they are committed, and CI fails when one is out of date. The command reference is the part I like: it is parsed from the `kHelp` string in `main.cpp`, so the site can't describe a command the firmware doesn't have. + +**The posts you're reading had `