Skip to content

Latest commit

 

History

119 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IRCaBot v3 (reborn)

An undemanding IRC chat logger with a JS-free web interface. A fresh take written from scratch - not an evolution of v2, whose code was a pile of horrors from back when I was learning to program and doing it desperately.

Key points

  • Storage format is fully compatible with v1/v2: plain text files data/<server>/<channel>/yyyy/MM/dd.txt with [nick] message lines. An existing production data folder is picked up as is, no conversion needed.
  • Configuration is plain JSON (./ircabot --example config.json writes a documented template). Top-level keys: data_path, log_local_time (day rotation timezone: false/default = UTC, true = server local time), log_cache_mb (RAM budget for the archive log cache, default 30, 0 disables), web{} (address, port, service name/emoji, realtime_disabled), voicegate{} (enabled, set_moderated, captcha_url, captcha_length, connect_delay_seconds, offline_ttl_hours, pm_interval_hours (0 disables the automatic PM), private_message), defaults{} (nick/user/real_name/ password for all servers), triggers{} (request -> answer) and servers[] (name, address, port, optional ssl, channels, per-server overrides). Keys starting with _ are ignored and can be used as comments.
  • Per-channel language: a channels[] entry is either "#name" or {"name": "#name", "lang": "ru"}. The tag (default en) becomes the <html lang> of that channel's log pages, so a browser offers to translate a chat known to be held in that language; the interface and the nicks are marked lang="en" and stay untouched. A channel object with a missing name, an unknown key or a malformed language tag stops the service at startup.
  • Moderation-only channels: {"name": "#staff", "moderation_only": true} joins the channel for the voice gate alone. Nothing said there is logged - no directory under data/, no line on disk, not even a console echo - and the channel is absent from the sidebar and from every log URL. It is named once, at the end of the channel list on the server description page, marked (moderation only).
  • URL scheme is compatible with v1/v2: old links to /<server>/<channel>/yyyy/MM/dd (and .txt), /~realtime/..., /~images/... keep working.
  • No JavaScript anywhere in the interface. The only exception is the real time reading page (/~realtime/<server>/<channel>), which uses a small polling script. It can be turned off entirely with realtime_disabled = true.
  • Multithreaded asynchronous web server: QHttpServer, heavy handlers run on the global thread pool (QFuture<QHttpServerResponse>), the IRC event loop is never blocked. Search is bounded by a time budget and a hit limit, so a greedy regexp cannot hang the service (the main v1 disease). Archive day logs (every day except today's, which keeps growing) are served from a shared, size-bounded LRU cache in RAM, so active reading and repeated searches barely touch the disk.
  • No worker threads for IRC, no blocking waitFor*() calls: every connection is event-driven, reconnects are timer-based.
  • No X server or offscreen platform hacks: pure QCoreApplication console binary.

Features

  • Dark and light themes: the default follows the browser (prefers-color-scheme), the manual choice (sidebar switcher) is stored in a persistent cookie server-side - still no JavaScript;
  • Mobile friendly: collapsible menu and adaptive log layout, pure CSS;
  • Unlimited servers and channels, current online and topic per channel;
  • Connection status in real time (green/red dot);
  • Scoped search, plain substring or regular expression: the grep box searches from wherever you are - the whole channel, a single year, month or day - so a large history stays reachable instead of the hit limit being spent on recent matches alone;
  • Plain text day log: append .txt to the day URL;
  • Messages starting with a dot are stored as "Blinded message";
  • CTCP ACTION (/me) is stored as *** text ***;
  • Customizable triggers: the bot answers when addressed (botnick, webui), %CHANNEL_FOR_URL% and %VERSION% are substituted automatically;
  • NickServ authorization, busy nickname fallback and automatic recovery;
  • Voice gate (on by default): on moderated (+m) channels where the bot is an operator, a newly joined user is given connect_delay_seconds to settle, then PMed a link to a JS-free captcha (/~captcha/<nick>). Solving it voices the user (+v) on every gated channel of that server. The grant is bound to nick + an md5 of the host and stored under data/_voicegate/<server>/; it survives a reconnect (the bot re-voices automatically) and is dropped after offline_ttl_hours offline. pm_interval_hours is the minimum delay between two captcha PMs to the same user; 0 turns the automatic PM off completely, leaving the rest of the gate (+m, voicing, the link sent in answer to a user's own PM) working. The captcha is stateless - the challenge lives in an AES-256 encrypted, signed nonce in the form, so no challenge database is kept. Every challenge handed out counts against a per-client limit (10 a minute, then a minute's pause), so fetching images until an easy one turns up costs exactly as much as answering them. The bot announces the mode with /me Voice gate mode activated; an operator who takes a voice back by hand (-v) overrules the gate: the grant is deleted instead of re-issued, the channel is told with /me Voice of <nick> revoked by a moderator of this channel, and the next captcha invitation waits out the usual pm_interval_hours;
  • Customizable pages: data/_ircabot/web/main_page.txt (with %LOCAL_TIME% and %DAILY_REQUESTS% placeholders) and a per-server page data/<server>/about_server.txt - plain HTML, edited on disk. Custom images go to data/_ircabot/web/images/ and are served via /~images/<name>. All of these (and the config) are read once and kept in RAM for the whole runtime, so the disk is never touched per request; applying an edit needs a restart.

Build

sudo apt install qt6-base-dev qt6-httpserver-dev cmake g++
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

The version reported by --version, the startup banner and the web footer is taken from the nearest v* git tag (git describe --tags), falling back to the CMake project version when built outside a tagged checkout. Override explicitly with -DIRCABOT_VERSION=x.y.z.

Run

# Create a configuration file template:
./build/ircabot --example ./config.json

# Edit config.json, then:
./build/ircabot --config ./config.json

Install

From a .deb (Debian 13)

Download the package from the Releases page (or build it locally with cd build && cpack -G DEB) and install:

sudo apt install ./ircabot_<version>_amd64.deb

The package:

  • installs the binary to /usr/bin/ircabot and a systemd unit to /usr/lib/systemd/system/ircabot.service;
  • creates the ircabot system user and the data directory /srv/ircabot/data;
  • writes a starter config to /etc/ircabot/config.json only if it does not already exist - your configuration is never overwritten on upgrades;
  • starts the service on first install and restarts it on upgrade.

Edit /etc/ircabot/config.json, then sudo systemctl restart ircabot.

Manual (from source)

sudo cmake --install build --prefix /usr
ircabot --example /etc/ircabot/config.json   # then edit it
sudo systemctl daemon-reload
sudo systemctl enable --now ircabot.service

License

GPLv3 (c) acetone, 2021-2026. Source: https://github.com/freeacetone/ircabot

About

IRC logger with web UI and CAPTCHA to +voice

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages