ANetBBS Changelog
Current release: v1.1.53 (October 2026). This file covers v1.0.0
onward, which follows standard semantic versioning — patch releases are
v1.0.1, v1.0.2, and so on. The full internal beta build-number
history (v1.0a1.1 through v1.0b2.239) that got the project to this
release is preserved in
CHANGELOG-beta.md.
v1.1.38 — Web dashboard MRC Stats widget, plus a small internal MRC-theme follow-up (October 2026)
The home page's sidebar can now show a live "MRC Stats" card (BBSes,
Rooms, Users, Activity) reflecting the whole multi-relay-chat network,
not just this BBS's own sessions — reads directly from the public hub
status endpoint, so it works independently of whether the local MRC
bridge is enabled. Cached server-side and refreshed in the browser
once a minute; falls back to the last known reading rather than
erroring out if the remote is briefly unreachable. Off by default
behavior is unaffected — set MRC_NETWORK_STATS_ENABLED=false to hide
the card entirely.
Also rolls in a same-day outside-contributed follow-up
(github.com/anetonline/ANetBBS/pull/24) to the prior release's MRC
budget-parity work: a small internal cleanup (an unused import removed
from a test file) and a correctness fix in the Mystic theme-layout
art-reading helper, which now checks every art segment covering a
screen row instead of stopping at the first match. No bundled theme
currently overlaps segments, so this had no visible effect on any
shipped theme — it closes the gap for a future theme that might.
v1.1.37 — MRC: uMRC prefix budget, per-sender chat pacing, /b broadcast fix, and the same budget parity for ANetBBS's own clients (October 2026)
Two outside contributions (github.com/anetonline/ANetBBS/pull/22 and pull/23) refine the MRC bridge's and clients' handling of message-length limits. The bridge now recognizes uMRC's own client-embedded styled display-name prefix and treats it as overhead on top of the 140-character wire cap rather than counting it against the typed-text budget, matching the real umrc-bridge daemon's behavior. It also adds per-sender pacing between outgoing chat packets to avoid flooding the upstream hub, and fixes a bug where a uMRC /b network-wide broadcast was incorrectly narrowed to the sender's current room.
A follow-up extends the same rule to ANetBBS's own terminal and web MRC clients, so every MRC surface counts a line the same way: the styled display name, DM wrapper, or /me action wrapper (and the client's own typing color) now ride on top of the 140-character typed-text budget instead of being subtracted from it. The style suffix now holds up to 32 characters and an input line up to 280 characters on every client, matching umrc-client. The terminal counter now shows remaining/limit, switching from a plain /140 to a red /280 once a line will be split across multiple packets — a fix for a real display bug where the old countdown could run negative and get clipped by the Mystic themes' fixed-width Buffer field.
v1.1.36 — DOOM/Duke3D follow-up #3: connect-src needed blob: too, plus getting ahead of the pattern (October 2026)
A third same-day follow-up: with the glue script now loading, a sysop browser console showed the actual .wasm binary fetch itself (Emscripten's instantiateAsync/readAsync) also goes through a blob: URL, and connect-src didn't allow it — fetch() to a blob: URL needs explicit connect-src permission, same as any other scheme, independently of the blob: already added to script-src for the glue script. Without it the WASM fetch aborted outright even though every earlier blocker was already fixed.
With four straight rounds of "another EmulatorJS resource type needs blob: too" in the same policy, got ahead of the pattern instead of waiting for a fifth: added a media-src directive (there wasn't one at all before — it silently fell back to default-src 'self', which would reject the same way every other resource type above needed explicit blob: for) and blob: to font-src, since this is a full emulator with audio and embedded fonts are plausible too. These two are proactive, not individually confirmed by a browser error the way everything above was — flagged as such so it's clear which is which if something's still broken.
v1.1.35 — DOOM/Duke3D follow-up #2: the WASM core also loads itself from a blob: URL (October 2026)
A second same-day follow-up: with eval now allowed, a sysop browser console turned up a third CSP gap in the same dos-frame policy — EmulatorJS's game-core loader fetches the WASM core, wraps it in a Blob, and runs it via a dynamically-created <script src="blob:..."> tag (a standard Emscripten pattern). worker-src and img-src already allowed blob: for this same underlying reason; script-src was the one directive still missing it. Added, with the regression test extended to cover it.
v1.1.34 — DOOM/Duke3D follow-up: the WASM core needs real eval too (October 2026)
A same-day follow-up to v1.1.33: with the stylesheet now loading, a
sysop browser console turned up a second CSP gap — EmulatorJS's
Emscripten-generated WASM glue code calls real eval()/new
Function() for some of its dynamic symbol binding (confirmed via the
traceback: Object.cwrap, Emscripten's own runtime wrapper utility),
which 'wasm-unsafe-eval' doesn't cover — that keyword only permits
WebAssembly compilation, not general JS string evaluation. Added
'unsafe-eval' to the dos-frame route's script-src, scoped only to
that one already-isolated route (its own COOP/COEP headers, separate
CSP from the rest of the site) rather than loosened anywhere else —
confirmed by a new test that the site-wide default policy never gets
it.
v1.1.33 — Fix in-browser DOOM/Duke3D: a CSP directive was missing the emulator's own CDN (October 2026)
A real sysop report ("DOOM and Duke Nukem 3D no longer work") traced,
via the browser's own console output, to a single missing origin in
the dos-frame page's Content-Security-Policy: every directive
(script-src, worker-src, connect-src, img-src) allowed the
EmulatorJS CDN except style-src, so the emulator's own stylesheet
load was silently blocked. That cascaded into EmulatorJS's "minified
files missing" fallback path, which then crashed outright — breaking
both games completely, with nothing visible in server-side logs at
all (a pure client-side CSP block never reaches Flask's access log,
which is exactly why this went unnoticed for a while). Fixed by
adding the CDN to style-src too, with a new regression test checking
every directive generically rather than just the one that broke this
time.
v1.1.32 — Login alert vs. doors; Command Deck top/bottom account menu (October 2026)
A real sysop screenshot found the classic " X just logged in/out
" cross-protocol alert (v1.1.1 fixed it sticking on screen inside
ANetBBS's own terminal MRC client) colliding with uMRC's own status
bar when a user ran uMRC as a door — the watchdog that prints this
alert keeps running no matter where a caller currently is in the BBS,
and its raw-write fallback has no way to know a door subprocess
currently owns the screen. Since a door's own screen layout is
unknown to us (unlike MRC chat's own, which the existing fix routes
through safely), the notice is now skipped outright for the exact
window any door or remote-bridged session (door games, rlogin/telnet
game-server bridges) owns the screen, rather than risking a corrupted
write into content we don't control.
Also fixed a real bug in the Command Deck web theme: with the nav
rail docked to the top or bottom of the screen (Profile → Edit → Nav
Position), opening the account menu (click your name) showed only
"Logout" — every other option rendered off-screen. A CSS rule meant
only for the rail's default vertical layout (anchoring that one
dropdown to grow upward from the bottom of its trigger, needed there
since the account group sits at the bottom of a vertical list) was
more specific than the rule meant to redirect it for a horizontal
bar, so it kept winning the cascade and pushed the menu off the top
of the screen. Given its own equally-specific override for both
positions, confirmed with a real before/after browser render.
v1.1.31 — MRC bridge: stop silently dropping long chat messages (October 2026)
A real bug report against a native umrc-client connection
(github.com/codefenix-dev/uMRC issue #27) found that a message
exceeding the MRC bridge's 140-character wire limit had its tail
silently dropped instead of carrying over — whole sentences vanished
with no indication anything was lost. Rather than relying on every
connecting client to pre-chunk its own messages with perfectly
matching overhead math (a different project's own bug, not something
this BBS can fix), the bridge itself now splits any outgoing message
that would exceed the wire cap into multiple properly-sized packets
that together carry the full original text, both for the native
umrc-client TCP listener and the web MRC client's WebSocket path
(room chat, direct messages, and /me actions all covered).
v1.1.30 — fsxNet IBOL: fix pipe-color codes in Author/Source fields (October 2026)
A real sysop screenshot from live fsxNet traffic found that a source
BBS name posted with per-letter rainbow pipe-color codes came through
on the Oneliner wall as literal unconverted |NN text instead of
actual colors — _format_entry() only ever ran the oneliner's body
through the pipe-to-ANSI converter, never the Author/Source fields
themselves, even though those are the same kind of free-text field a
sysop can color exactly like the body. Both fields are now converted,
with right-justification padding corrected to use the post-conversion
visible width rather than raw character count.
Also investigated a report of missing Location data on some ANetBBS
entries in the Last Callers feed — confirmed not a bug: location is
an optional profile field, and other ANetBBS users' entries already
carry it through correctly when set, so a blank Location just means
that particular account hasn't filled one in.
v1.1.29 — fsxNet IBOL + IBLC: real InterBBS Oneliners + Last Callers (October 2026)
Two new optional features that speak the real, externally-defined
Synchronet mod protocols used on fsxNet to exchange data over its
shared FSX_DAT echo area — not ANetBBS's own private InterBBS Wall/
Last Callers format, but the actual wire format other BBS software
(Synchronet, Mystic) already reads and writes, so posts and logins
round-trip with the wider network. IBOL (InterBBS Oneliners) lets
users post a short message to a shared cross-BBS wall; IBLC
(InterBBS Last Callers) broadcasts each login and shows a feed of
every other participating BBS's logins plus a directory of known
systems (calls, last call, OS, telnet address) you can connect
straight to. Both are independent toggles, off by default, with their
own admin settings page (Admin → fsxNet IBOL/IBLC) and their own data
tables — entirely separate from the existing InterBBS Wall/Last
Callers sync. See docs/39-fsxnet-interbbs.md for setup and full
credits — this port implements the real wire format by reading the
actual reference scripts (iblc.js/ibol.js, by Craig Hendricks/
codefenix of ConstructiveChaos BBS, continuing Andrew Pamment/apam's
original IBOL), not a reinvented approximation.
Both are also available as real Logon/Logoff Modules (Admin →
Logon/Logoff Modules, or the anetbbs-cfg terminal tool), the same
way the existing Graffiti Wall and Last Callers already are — pick
fsxnet_ibol/fsxnet_iblc as the module type to show either screen
automatically on login. Recording a login to fsxNet IBLC is never
skipped by Fast Logon, matching the existing Last Callers precedent:
only the display screen is a skippable login module, the actual
FSX_DAT post happens via the same always-runs hook that already writes
the local Caller Log row. The admin settings page also moved from the
main Admin dashboard to Admin → Messages, next to Echomail, since this
is fundamentally an echomail-area feature.
Both terminal screens were redesigned for a cleaner look matching the
real Synchronet reference client: a bordered CP437 header for the
Oneliner wall with pipe-color support and a true scrollable "View All"
mode; a real arrow-key scrollable/selectable BBS directory ([B] from
the Last Callers screen) with live column widths pulled directly from
the real iblc.js source; and explicit word-wrap on the About screens
instead of relying on terminal auto-wrap. Fixed a handful of glyphs
that don't actually exist in the CP437 code page (a malformed escape
sequence and a couple of Unicode-only characters) that would have
rendered as garbage or a bare ? on a real BBS terminal.
Also fixed a real data-loss bug found against live fsxNet traffic:
inbound IBLC message matching was case-sensitive, silently dropping a
meaningful share of real last-caller posts that arrive with different
header capitalization than the reference script uses. Matching is now
case-insensitive for both IBOL and IBLC.
v1.1.28 — update.sh: fix a self-upgrade crash introduced in v1.1.27 (October 2026)
A real live incident: v1.1.27's update.sh hardening of the nginx
self-healing config patches introduced a bash construct (a heredoc
immediately followed by a backslash-continued success/failure chain)
that parsed fine in testing but failed with a bash syntax error on a
production server mid-upgrade — after services had already been
stopped, leaving the site down until manually restarted. Rewritten to
use the same if cmd <<'EOF'; then ... else ... fi heredoc form
already proven elsewhere in this script. A second, unrelated, pre-
existing bug in the same area was also found and fixed while tracking
this down: a port-mismatch check could silently abort the whole script
under set -e/pipefail whenever an older nginx config had no
existing MRC proxy line to match against yet — exactly the situation
where this script's own "add the missing location block" logic is
supposed to run. Both are now covered by a regression test that runs
the real, complete nginx-patching section end to end, under the same
shell options the live script runs under, rather than testing narrower
slices in isolation.
v1.1.27 — Audit pass: dead-connection fix, hardening, doc corrections (October 2026)
A follow-up audit pass covering everything changed since the last full
review (v1.0.76). One dead-connection hang fix: a raw write-then-drain
call in the stock menu-art renderer (used by Game Center, Door Games,
the Chat menu, and a few sysop menus) wasn't going through the same
backpressure-timeout protection every other session-output call site
already has — a client that stopped reading could hang that session
forever instead of being disconnected cleanly. Brought in line with
the existing protection; the same fix also went into the Graffiti Wall
and the terminal IRC client's own write path.
Several smaller hardening fixes: tightened input handling on a couple
of admin-only upload/install code paths (Add-ons installer, TheDraw
font-pack installer), a stricter allowlist check on the Add-ons
installer so it does exactly what its own documentation says, and a
fix to the optional pre-login web page so it can no longer reflect
request data back into the page unescaped. A few install/update script
code-generation steps now pass values through as real environment
variables instead of splicing them into generated source directly.
Also: three stale documentation claims corrected (a "not yet released"
status note on native uMRC support that's actually been live since
v1.1.0; two Add-ons config settings described as empty that now ship
with real working defaults; and a built-in theme count that hadn't
been updated since a thirteenth theme was added). The Enhanced Client
overlay's leftover internal "(TEST)" labeling was also removed now
that it's a real shipped add-on.
v1.1.26 — New web theme: Command Deck (October 2026)
A thirteenth web UI theme, and the first one that changes the page's
actual shape instead of just its colors: a fixed icon rail replaces
the top navbar, with flyout submenus and a hover-to-expand label view,
built around a mission-control palette (cool structural blue, warm
amber status-light badges) and Sora + IBM Plex Mono type. Every other
theme is unaffected — the existing navbar markup is reused as-is,
restyled entirely through CSS, with no page-structure changes outside
this one theme. Real, dedicated mobile support rather than a
squeezed-down desktop layout: a slide-in drawer from the existing
hamburger toggle, plus a new bottom tab bar for quick thumb access to
the most-used sections on phones.
Two real-hardware follow-ups from Pi3 testing, same day: the
account-menu flyout (at the bottom of the rail) was opening downward
and running off the bottom of the screen, cutting off everything past
"Edit Profile" — it now opens upward instead, so all items are always
reachable. The content area also got a real second pass after direct
feedback that it still read as a recolored stock layout: cards now
have HUD-style corner brackets, a diagonal gradient fill, a hover-lift
interaction, and an alternating blue/amber accent rhythm instead of
flat single-tone panels; the page's shared hero banner became an
actual glowing gradient readout with a slow scan-line sweep instead of
a centered logo over a thin line; stat numbers render as bold
monospace readouts; and the layout runs full-bleed next to the rail
instead of floating in a centered column. Selectable from Profile →
Themes. See docs/08-themes.md.
A third Pi3 round found two more real gaps and added a requested
customization feature. First, the two bugs: the secondary search bar
(and anything else using Bootstrap's own .bg-dark utility class)
showed Bootstrap's raw hardcoded gray instead of the active theme's
own background on every theme except the handful with a dedicated
override stylesheet — fixed once in base.html for all thirteen
themes, not just Command Deck. Action-button rows (echomail's Prev/
Next/Reply/Thread/Next Unread/Bookmark, and the same d-flex-of-
buttons shape used across 87 other templates) had no flex-wrap, so on
a phone they crowded together instead of flowing onto new lines — also
fixed once, site-wide, in base.html's shared mobile styles.
Second, the feature: Command Deck's rail can now dock to any of the
four screen edges — left (unchanged default), right (a mirror), or
top/bottom (a horizontal bar in the same visual language, closer to a
traditional navbar shape but still Command Deck's own). Each position
opens its dropdown flyouts in whichever direction actually has room.
Picked per-user from Profile → Edit, right next to the existing Theme
picker; has no effect on any other theme. Mobile is deliberately
unaffected by this setting — phones keep the same drawer + bottom tab
bar regardless of what's picked for desktop.
A fourth Pi3 round fixed two more real gaps. The Nav Position picker
was shown unconditionally with only a small caption explaining it's
Command-Deck-only — looked exactly like a working setting for whatever
theme happened to be selected (e.g. Graphite Teal), since it never
actually disappeared. It's now hidden entirely unless Command Deck is
the currently-selected theme, updating live with no page reload as the
Theme dropdown changes. Separately, mobile action-button rows were
still crowding together even after the earlier flex-wrap fix — that
fix only added spacing between wrapped lines, not between buttons
sharing the same line, which depended entirely on whatever margin
utility class a given template's row happened to add. A real gap (both
axes) now guarantees breathing room between every adjacent button
app-wide regardless of what margin classes a specific row does or
doesn't have.
v1.1.25 — BinkP: a hub slow to start its backlog could get cut off with nothing queued outbound (October 2026)
A real sysop report (full session transcripts, hub-side confirmation
of a stuck backlog) found that when a leaf has nothing of its own
queued outbound, ANetBBS's BinkP poller moved straight to its
post-transfer idle-wait phase — a short 5-second timeout tuned for
detecting a connection that's already finished exchanging files and
gone quiet. Against a hub that's simply slow to begin transmitting its
own backlog (confirmed live: 30-40+ seconds is normal for at least one
real FTN hub), that same 5-second wait fired before the hub ever
offered anything, and the session was logged as a clean success with
the backlog never received — repeating indefinitely on every
subsequent poll. The timeout now only shrinks once a file has actually
been exchanged this session; the very first wait, when nothing has
been sent or received yet, uses the same longer timeout the poller's
own outbound ack-wait already relies on successfully. Every session
that already has outbound mail, hatch items, FREQ requests, or
outbound-dir files queued is unaffected — confirmed via the full
existing BinkP regression suite (267 tests across every file touching
this subsystem), none of which changed behavior.
v1.1.24 — Image Import / Reference Image: fix a silent CSP block (October 2026)
v1.1.23's new Image → ANSI import and reference-image trace mode both
preview a user-selected local file via
URL.createObjectURL()/<img src="blob:...">. The site-wide
Content-Security-Policy's img-src directive didn't include blob:,
so the browser silently blocked the image load — nothing visible
happened, no error shown to the sysop. Fixed by adding blob: to
img-src; confirmed safe since a blob: URL can only ever reference
image data the page's own script created locally, never anything
attacker- or remote-controlled.