Registration only validated username with NotBlank, so a username
like "../../../../public/x" got concatenated directly into a
filesystem path for both writing (game activity logs) and reading
(admin log viewer) - reachable from the public webroot since public/
is a few directories up from where those logs are stored.
Adds a character-set validator (letters, numbers, underscore, hyphen)
to registration and admin user editing going forward, and sanitizes
at the point of use (Player::getLogFileBasename()) so any
already-stored unsafe username can't escape the log directory either.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Admins can now see the full lobby chat transcript (who said what,
when) at the top of a session's log view, alongside the existing
per-player terminal logs. Also swaps the log tabs' inline onclick
handler for a data attribute, in prep for moving the tab-switching
script out of the template.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>