Add the tier 3 utility IRC commands (closes #87)
check / check (push) Waiting to run

USERHOST, VERSION, ADMIN, INFO, TIME, KILL and WALLOPS work on the
HTTP API and on the IRC listener. The USERHOST reply, the VERSION,
ADMIN and INFO text, KILL and WALLOPS are each one service function
that both transports call. User mode +w selects who receives WALLOPS.
MODE on your own nick queries or changes your user modes through one
parser on both transports: the whole mode string is checked before
anything is stored, and both flags are stored in one transaction. KILL
closes the victim's IRC connection after sending it KILL and ERROR,
without the operator waiting on it. The sessions table gains
is_wallops in 001_initial.sql, as the pre-1.0 rule in REPO_POLICIES.md
asks.

Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
This commit was merged in pull request #96.
This commit is contained in:
2026-10-08 07:31:37 +02:00
committed by clawbot
parent b119b094f5
commit 0f2e63d0cc
19 changed files with 2552 additions and 129 deletions
+56 -26
View File
@@ -1575,24 +1575,31 @@ reference with all required and optional fields.
**Command dispatch table:**
| Command | Required Fields | Optional | Response Status |
| --------- | --------------- | -------- | --------------- |
| `PRIVMSG` | `to`, `body` | `meta` | 200 OK |
| `NOTICE` | `to`, `body` | `meta` | 200 OK |
| `JOIN` | `to` | | 200 OK |
| `PART` | `to` | `body` | 200 OK |
| `NICK` | `body` | | 200 OK |
| `PASS` | `body` | | 200 OK |
| `TOPIC` | `to`, `body` | | 200 OK |
| `MODE` | `to` | | 200 OK |
| `NAMES` | `to` | | 200 OK |
| `LIST` | | | 200 OK |
| `WHOIS` | `to` or `body` | | 200 OK |
| `WHO` | `to` | | 200 OK |
| `LUSERS` | | | 200 OK |
| `OPER` | `body` | | 200 OK |
| `QUIT` | | `body` | 200 OK |
| `PING` | | | 200 OK |
| Command | Required Fields | Optional | Response Status |
| ---------- | --------------- | -------- | --------------- |
| `PRIVMSG` | `to`, `body` | `meta` | 200 OK |
| `NOTICE` | `to`, `body` | `meta` | 200 OK |
| `JOIN` | `to` | | 200 OK |
| `PART` | `to` | `body` | 200 OK |
| `NICK` | `body` | | 200 OK |
| `PASS` | `body` | | 200 OK |
| `TOPIC` | `to`, `body` | | 200 OK |
| `MODE` | `to` | `body` | 200 OK |
| `NAMES` | `to` | | 200 OK |
| `LIST` | | | 200 OK |
| `WHOIS` | `to` or `body` | | 200 OK |
| `WHO` | `to` | | 200 OK |
| `LUSERS` | | | 200 OK |
| `USERHOST` | `body` | | 200 OK |
| `VERSION` | | | 200 OK |
| `ADMIN` | | | 200 OK |
| `INFO` | | | 200 OK |
| `TIME` | | | 200 OK |
| `OPER` | `body` | | 200 OK |
| `KILL` | `body` | | 200 OK |
| `WALLOPS` | `body` | | 200 OK |
| `QUIT` | | `body` | 200 OK |
| `PING` | | | 200 OK |
All IRC commands return HTTP 200 OK. IRC-level success and error responses are
delivered as **numeric replies** through the message queue (see
@@ -1619,7 +1626,11 @@ auth cookies (401), and server errors (500).
| 433 | ERR_NICKNAMEINUSE | NICK target is taken |
| 442 | ERR_NOTONCHANNEL | Not a member of the target channel |
| 461 | ERR_NEEDMOREPARAMS | Missing required fields (to, body) |
| 481 | ERR_NOPRIVILEGES | KILL or WALLOPS by a non-operator |
| 483 | ERR_CANTKILLSERVER | KILL of yourself |
| 491 | ERR_NOOPERHOST | Failed OPER authentication |
| 501 | ERR_UMODEUNKNOWNFLAG | User MODE string not accepted |
| 502 | ERR_USERSDONTMATCH | User MODE for a nick other than your own |
**IRC numeric success replies (delivered via message queue):**
@@ -1630,11 +1641,13 @@ auth cookies (401), and server errors (500).
| 003 | RPL_CREATED | Sent on session creation/login |
| 004 | RPL_MYINFO | Sent on session creation/login |
| 005 | RPL_ISUPPORT | Sent on session creation/login |
| 221 | RPL_UMODEIS | In response to user MODE query |
| 221 | RPL_UMODEIS | In response to user MODE |
| 251 | RPL_LUSERCLIENT | On connect or LUSERS command |
| 252 | RPL_LUSEROP | On connect or LUSERS command |
| 254 | RPL_LUSERCHANNELS | On connect or LUSERS command |
| 255 | RPL_LUSERME | On connect or LUSERS command |
| 256–259 | RPL_ADMINME etc. | ADMIN info |
| 302 | RPL_USERHOST | USERHOST reply |
| 311 | RPL_WHOISUSER | WHOIS user info |
| 312 | RPL_WHOISSERVER | WHOIS server info |
| 313 | RPL_WHOISOPERATOR | WHOIS target is oper |
@@ -1642,6 +1655,10 @@ auth cookies (401), and server errors (500).
| 318 | RPL_ENDOFWHOIS | End of WHOIS list |
| 319 | RPL_WHOISCHANNELS | WHOIS channels list |
| 338 | RPL_WHOISACTUALLY | WHOIS client IP (oper-only) |
| 351 | RPL_VERSION | VERSION reply |
| 371 | RPL_INFO | INFO line |
| 374 | RPL_ENDOFINFO | End of INFO |
| 391 | RPL_TIME | TIME reply |
| 322 | RPL_LIST | Channel in LIST response |
| 323 | RPL_LISTEND | End of LIST |
| 324 | RPL_CHANNELMODEIS | Channel mode query response |
@@ -2384,13 +2401,13 @@ IRC_LISTEN_ADDR=
### Supported Commands
| Category | Commands |
| ---------- | ------------------------------------------------------------------ |
| Connection | `NICK`, `USER`, `PASS`, `QUIT`, `PING`/`PONG`, `CAP` |
| Channels | `JOIN`, `PART`, `MODE`, `TOPIC`, `NAMES`, `LIST`, `KICK`, `INVITE` |
| Messaging | `PRIVMSG`, `NOTICE` |
| Info | `WHO`, `WHOIS`, `LUSERS`, `MOTD`, `AWAY` |
| Operator | `OPER` (requires `NEOIRC_OPER_NAME` and `NEOIRC_OPER_PASSWORD`) |
| Category | Commands |
| ---------- | ---------------------------------------------------------------------------------------- |
| Connection | `NICK`, `USER`, `PASS`, `QUIT`, `PING`/`PONG`, `CAP` |
| Channels | `JOIN`, `PART`, `MODE`, `TOPIC`, `NAMES`, `LIST`, `KICK`, `INVITE` |
| Messaging | `PRIVMSG`, `NOTICE` |
| Info | `WHO`, `WHOIS`, `LUSERS`, `MOTD`, `AWAY`, `USERHOST`, `VERSION`, `ADMIN`, `INFO`, `TIME` |
| Operator | `OPER`, `KILL`, `WALLOPS` (requires `NEOIRC_OPER_NAME` and `NEOIRC_OPER_PASSWORD`) |
### Protocol Details
@@ -2406,6 +2423,15 @@ IRC_LISTEN_ADDR=
operator status (`@`).
- **Channel modes**: `+m` (moderated), `+t` (topic lock), `+o` (operator), `+v`
(voice)
- **User modes**: `+o` (operator, set only via `OPER`), `+w` (receives
`WALLOPS`). `MODE` for any nick other than your own is rejected with
`ERR_USERSDONTMATCH` (502), for both queries and changes. Nick comparison is
case-insensitive.
- **KILL**: an operator's `KILL` broadcasts the victim's `QUIT` to its channel
peers, deletes its session, and then sends the victim a `KILL` and
`ERROR :Closing Link` before closing its socket. This applies to victims on
the IRC listener regardless of whether the `KILL` arrived over IRC or the HTTP
API.
### Bridge to HTTP API
@@ -2946,6 +2972,10 @@ guess is borne by the server (bcrypt), not the client.
from additional devices via `POST /api/v1/login`
- [x] **Cookie-based auth** — HttpOnly cookies replace Bearer tokens for all API
authentication
- [x] **Tier 3 utility commands** — `USERHOST` (302), `VERSION` (351), `ADMIN`
(256–259), `INFO` (371/374), `TIME` (391), `KILL` (operator-only forced
disconnect), `WALLOPS` (operator-only broadcast to `+w` users)
- [x] **User mode +w** — receive `WALLOPS`, set with `MODE <nick> +w` / `-w`
### Future (1.0+)