Third audit pass on the mbweb web console. This article covers
the remaining items from the backlog: bug fixes, full i18n cleanup,
and the major structural refactor of app.js.
/channels missing try/catchThe HTML /channels route had no error handler around the DB calls,
unlike every other route. A DB failure would propagate unhandled.
A try/catch block was added, consistent with the rest of the codebase.
fmtUptime returning French suffixesviewHelpers.js was outputting 2j 3h 14mn instead of 2d 3h 14m.
Suffixes corrected: j β d, mn β m.
lang="fr" in the HTML root elementlib/render.js was declaring <html lang="fr"> on every page.
Corrected to lang="en".
All remaining French strings were translated across app.js,
routes/auth.js, lib/render.js, and lib/sessionUser.js.
This covers page titles, section headers, table headers, error
messages, hero paragraphs, stat card labels, filter bars,
empty states, nav labels, and the login form.
app.js split into dedicated route filesapp.js went from 1867 lines to 134. All route handlers were
extracted into separate files under routes/:
| File | Routes |
|---|---|
routes/home.js |
GET / |
routes/profile.js |
GET /profile, GET /api/me |
routes/channels.js |
GET /channels, GET /channels/:id, GET /api/channels, GET /api/channels/:id |
routes/radio.js |
GET /radio, GET /api/radio/status |
routes/network.js |
GET /network, GET /api/network |
routes/quotes.js |
GET /quotes, GET /api/quotes |
routes/commands.js |
GET /commands, GET /api/commands |
routes/users.js |
GET /users, GET /api/users |
routes/metricsProxy.js |
GET /api/metrics |
The Prometheus helpers (parseMetrics, fetchMetrics, metricVal,
metricSum) were extracted into lib/metrics.js.
app.js now contains only: Express setup, Helmet CSP, session
middleware, static file serving, router mounts, 404 handler,
global error handler, and app.listen.
/users and /channelsBoth routes now load 50 records per page. getAllUsersWithRoles()
and getAllChannels() accept { page, perPage } and return
{ rows, total }. The /api/ variants expose total, page,
perPage, and pages in their JSON response.
For /channels, pagination only applies to Master and above
(non-Master users see all their own channels, volumes are low).
/usersA filter bar with a free-text input (?q=) is now displayed above
the users table. The search filters on nickname and username
via a LIKE query. Pagination preserves the active search term
across pages. The count badge updates to reflect the filtered total.
getKnownChannelRelatedTables()This function was running a full information_schema.tables query
on every channel detail page load. It now caches its result in
memory with a 5-minute TTL. The schema does not change at runtime,
so the cache is effectively always valid in normal operation.
Previously, a level change in the DB (e.g. promoting a user from User to Master via IRC) required the affected user to log out and back in to see their new permissions in the web console.
requireLogin now triggers a silent refreshSessionUser() call
at most once every 2 minutes per session. If the DB profile has
changed, the session is rebuilt and saved transparently. The
request is never blocked β the refresh is fire-and-forget.
GET /login now generates a 32-byte hex token using Node.js native
crypto, stores it in req.session._csrf, and injects it as a
hidden field in the form. POST /login validates the token via a
csrfMiddleware before any authentication logic runs. A missing
or mismatched token redirects back to the login page with an error.
The token is deleted from the session on successful login (one-time use).
No external dependency β crypto is built into Node.js.
| # | Item | Status |
|---|---|---|
| B1 | /channels missing try/catch |
β fixed |
| B2 | fmtUptime French suffixes |
β fixed |
| B3 | lang="fr" in HTML |
β fixed |
| i18n | Remaining French strings | β done |
| R9 | app.js β 9 route files + lib/metrics.js |
β done |
| A | Pagination on /users and /channels |
β done |
| B | Search/filter on /users |
β done |
| C | Cache getKnownChannelRelatedTables() |
β done |
| D | Session user refresh on permission change | β done |
| F | CSRF token on login form | β done |
Remaining long-term items: EJS migration (R12), CSRF on other forms if any are added, Matrix/Discord integration stubs.
You must be logged in to reply.