Forum teuk.org

πŸ§™ Expelliarmus Maxima β€” Mediabot v3 Deep Audit Sessions (May 2026)

in Mediabot Β· started by TeuK Β· 1w ago

TeuK Β· 1w ago

πŸ§™ Expelliarmus Maxima β€” Mediabot v3 Deep Audit Sessions (May 2026)

Overview

Over a series of intensive audit sessions covering 43 snapshots, every module in Mediabot v3 was reviewed for bugs, security issues, and improvement opportunities. This post summarises all the work done since the last forum article.


πŸ”΄ Critical Bugs Fixed

πŸ”’ Auth & Security

  • Auth::new() missing bot => β€” noticeConsoleChan in cleanup_stale_sessions was silently broken because $self->{bot} was never set. Fixed in both LoginCommands::init_auth() and User::maybe_autologin().
  • Auth::maybe_autologin missing conf => β€” inconsistency with init_auth(); now passes the full set of named args.
  • _mask_matches_irc regex backtracking β€” IRC wildcard patterns like *!*@* converted to Perl regex without protection against catastrophic backtracking. Wrapped in eval {}.
  • setTMDBLangChannel_ctx unvalidated lang β€” a 1000-char string could be stored as the TMDB language. Now validated against /^[a-z]{2}(-[A-Z]{2})?$/.

🌐 HTTP / Network

  • 11 HTTP calls without eval in External.pm β€” getYoutubeDetails, displayWeather_ctx, _handle_instagram, _handle_spotify, _handle_applemusic, _handle_facebook, _handle_generic_title, fortniteStats_ctx, get_tmdb_info, and two others. HTTP::Tiny can throw exceptions on DNS/network failures; all calls now wrapped in eval {} with a fallback { success => 0 } response.
  • _openai_run_test HTTP synchronous β€” the parent IRC event loop was blocked for up to 20s during OpenAI API calls. Both the primary and fallback calls are now wrapped in eval {} and use External::_make_http() for consistency.
  • _handle_facebook unprotected get() β€” same issue; fixed with eval {}.

πŸ—„οΈ Database

  • purgeChannel_ctx incomplete cascade β€” deleting a channel left orphan rows in CHANNEL_BAN, CHANNEL_SET, CHANNEL_LOG, BADWORDS, and QUOTES. The deletion is now wrapped in a begin_work/commit/rollback transaction with full cascade.
  • purgeChannel_ctx wrong send_message("PART", ...) syntax β€” the channel name was passed as the prefix rather than the first argument.
  • delUser_ctx no cascade on USER_SEEN β€” deleting a user left entries in USER_SEEN. Now cleaned up atomically.
  • delUser_ctx no transaction β€” three sequential do() calls with no error handling. Wrapped in begin_work/commit/rollback.
  • _birthday_valid_date no days-per-month check β€” February 31st was accepted. Now validates against a per-month days array with leap-year support.
  • mbQuoteAdd no length limit β€” quote text was stored without any size constraint. Now capped at 512 chars.
  • $search_limit ignored in mbDbSearchCommand_ctx SQL β€” the variable was parsed but LIMIT 50 was hardcoded. Now uses LIMIT ? with $search_limit.
  • Yomomma_ctx and mbQuoteRand β€” LIMIT 1 OFFSET $offset used direct interpolation. Fixed to use ? placeholder.

πŸ€– Partyline

  • auth_stage not cleared after login β€” all commands typed after login were logged as ***** (masked as passwords). Fixed by setting auth_stage = undef after successful authentication.
  • .schedule double dispatch β€” two elsif blocks with different regexes; the second was dead code. Merged into a single regex (?:\s+(\S+)(?:\s+(\S+))?)?.
  • .uptime and _cmd_uptime both duplicated β€” stale merge artefacts. Removed.
  • .eval pipe read blocking β€” while (<$pipe>) in the parent blocked the IO::Async event loop. Replaced with IO::Async::Stream + IO::Async::Timer::Countdown watchdog.
  • if ($pid == 0) {} empty block β€” dead code vestige before the real child block.

🧩 Misc

  • _openai_run_test used HTTP::Tiny->new directly β€” inconsistent with External::_make_http(). Fixed.
  • AdminCommands mbExec_ctx command length unchecked β€” any-length shell command accepted. Capped at 512 chars.
  • channelSet_ctx chanmode/key unvalidated β€” arbitrary strings could be stored. chanmode now validated against /^[+-]?[a-zA-Z]+$/ ≀ 32 chars; key validated as no-spaces ≀ 64 chars.
  • set_hailo_channel_ratio no range check β€” ratio stored without [0, 100] validation.
  • mbDbAddCommand_ctx action text after wrong shift β€” $action_text was calculated before $sType and $sCategory were extracted.

🟠 Improvements

πŸ”§ Robustness

  • botNotice now truncates at 400 chars β€” same as botPrivmsg.
  • botAction double-encode simplified β€” redundant if/else around a single encode() call removed.
  • use Encode moved to header in Helpers.pm β€” was declared mid-file after first use.
  • cleanup_stale_sessions wired to Scheduler β€” runs every hour; notifies noticeConsoleChan when sessions are pruned.
  • _birthday_add_ctx, _birthday_del_ctx, _birthday_next_ctx implemented β€” were called from UserCommands but never defined.
  • delUser_ctx two-step confirmation β€” permanent deletion requires repeating the command within 30 seconds.
  • checkAuth prefers Auth::verify_credentials β€” falls back to legacy make_password_hash path when BCrypt is unavailable.

🌐 HTTP / External

  • All HTTP::Tiny->new(...) in External.pm replaced by _make_http() β€” centralises SSL options and timeout settings.
  • displayWeather_ctx now uses _make_http(verify_SSL => 1).
  • _repair_utf8_mojibake detection broadened β€” now catches [\xC0-\xFF]{2,} sequences in addition to [ÃÂÒ].
  • openai.TIMEOUT configurable in mediabot.conf (min 5s, max 60s, default 20s).
  • chromium.VIRTUAL_TIME_BUDGET and chromium.ALARM_TIMEOUT configurable in mediabot.conf.
  • Radio::Icecast::new accepts ua => β€” callers can inject a pre-built _make_http() handle.

πŸ› οΈ Partyline

  • .schedule restart <name> β€” calls Scheduler::restart() to stop and restart a task without restarting the bot.
  • .schedule list/status β€” shows all tasks with interval, status, and tick count in a tabular format.
  • .uptime β€” shows bot uptime formatted as Xd Xh Xm Xs.
  • .log [n] β€” opens the log file with <:utf8 encoding.
  • .bans #chan β€” shows N active ban(s) (showing M) with in Xh Ym expiry deltas.
  • .whois <nick> added to .help output.
  • noticeConsoleChan for .eval β€” logs a truncated summary (60 chars + total length).

πŸ—„οΈ Database

  • purge_channel_log and purge_user_seen β€” daily Scheduler tasks with configurable retention via CHANNEL_LOG_RETENTION_DAYS / USER_SEEN_RETENTION_DAYS. Use ensure_connected() to survive DB reconnects.
  • mbTimers_ctx β€” Scheduler tasks shown in aligned columns alongside DB timers.
  • !timers β€” $sth->finish added after the fetch loop.
  • mbDbAddCommand_ctx β€” command name validated: /^[a-zA-Z0-9_-]+$/ ≀ 64 chars; action ≀ 512 chars.
  • mbDbAddCategoryCommand_ctx β€” category name validated ≀ 64 chars + alphanumeric.
  • !searchcmd <term> [limit] β€” limit parameter (1–20, default 5) parsed and passed to LIMIT ?.
  • list_active_bans($id, $limit) β€” accepts an optional limit; callers now pass 11 to detect overflow without loading all bans.

πŸ” Auth

  • _password_matches β€” comment documents all supported formats (MySQL PASSWORD(), BCrypt) and explicitly notes that SHA1 #prefix is not supported by design.

🧹 Code Quality

  • 21 emoji characters removed from log(0,...) and log(1,...) across 7 modules β€” em-dashes (β€”), arrows (β†’), and emoji (πŸ” 🚫 ⚠️ βœ… ℹ️) replaced with ASCII equivalents in production-level log messages.
  • Conf.pm warn β€” only emitted once before logger is attached (_warned_no_logger flag).
  • DB.pm em-dash in log(0) β€” β€” β†’ --.

πŸ“¦ Files Changed

Module Key changes
Auth.pm bot => in new(), cleanup_stale_sessions, _password_matches docs
AdminCommands.pm OpenAI eval+timeout, exec length, blacklist, configurable timeouts
ChannelBan.pm list_active_bans($id, $limit), _mask_matches_irc anti-ReDoS
ChannelCommands.pm purgeChannel cascade+txn, chanmode/key validation, bans limit=11
Channel.pm set_chanmode/set_key defence-in-depth validation, ensure_connected()
DBCommands.pm mbTimers_ctx tabular, mbQuoteRand OFFSET, mbAddTimer name validation
External.pm 11 HTTP eval wrappers, _make_http() everywhere, configurable Chromium timeouts
Hailo.pm set_hailo_channel_ratio 0-100 validation, em-dash fix
Helpers.pm botNotice truncation, botAction encode, use Encode header, emoji cleanup
LoginCommands.pm init_auth passes bot =>, checkAuth β†’ verify_credentials
Mediabot.pm purge_* via ensure_connected, !help filtered by level, !uptime
Partyline.pm .eval async pipe, .schedule restart, .bans limits, .whois in help
Quotes.pm mbQuoteAdd 512-char limit, mbQuoteRand OFFSET placeholder
Radio/Icecast.pm ua => injectable, configurable timeout
Scheduler.pm restart($name) method
User.pm maybe_autologin passes bot => + conf => to Auth::new
UserCommands.pm birthday implementation + days-per-month, delUser cascade+txn+confirm
mediabot.pl dbh sync in timer, LIMIT ? for random quote OFFSET, auth Scheduler task

β€œThe spells have been cast. The Dark Lord of race conditions has been banished.” πŸͺ„

You must be logged in to reply.