Enforce channel keys, invites, +s and +H on the IRC listener (closes #122)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The IRC listener's JOIN now passes the channel key on, INVITE records the invite, LIST and WHOIS hide +s channels from non-members with the queries the HTTP API uses, and PRIVMSG to a +H channel gets 404. The INVITE checks and the channel hashcash check move from the HTTP handlers into the service, so both transports run the same code. An IRC client cannot attach a stamp, so its PRIVMSG to a +H channel always fails that check. The unfiltered channel list query, now unused, is removed. Model: opus-5-5
This commit is contained in:
@@ -1277,17 +1277,17 @@ Inspired by IRC, simplified. See [MODE](#mode--query-and-change-modes) for how
|
||||
to set them; `b`, `k` and `l` can be set only over the HTTP API, and `n` only on
|
||||
the IRC listener.
|
||||
|
||||
| Mode | Name | Meaning | Status |
|
||||
| ---- | ----------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
||||
| `+b` | Ban | Prevents matching hostmasks from joining or sending (parameter: `nick!user@host` mask with wildcards) | **Enforced** |
|
||||
| `+i` | Invite-only | Only invited users can join; use `INVITE` to invite | **Enforced**; only an invite made over the HTTP API lets a user in |
|
||||
| `+k` | Channel key | Requires a password to join (parameter: key string) | **Enforced**; the IRC listener sends no key, so its users cannot join a channel that has one |
|
||||
| `+l` | User limit | Maximum number of members allowed in the channel (parameter: integer) | **Enforced** |
|
||||
| `+m` | Moderated | Only voiced (`+v`) users and operators (`+o`) can send | **Enforced** |
|
||||
| `+n` | No external | Only channel members can send messages to the channel (default: ON) | Shown only: non-members can never send to a channel, whether or not `+n` is set |
|
||||
| `+s` | Secret | Channel hidden from LIST and WHOIS for non-members | **Enforced** by `LIST` and `WHOIS` over the HTTP API; not by `GET /api/v1/channels` or the IRC listener |
|
||||
| `+t` | Topic lock | Only operators can change the topic (default: ON) | **Enforced** |
|
||||
| `+H` | Hashcash | Requires proof-of-work for PRIVMSG (parameter: bits, e.g. `+H 20`) | **Enforced** over the HTTP API only |
|
||||
| Mode | Name | Meaning | Status |
|
||||
| ---- | ----------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
||||
| `+b` | Ban | Prevents matching hostmasks from joining or sending (parameter: `nick!user@host` mask with wildcards) | **Enforced** |
|
||||
| `+i` | Invite-only | Only invited users can join; use `INVITE` to invite | **Enforced** |
|
||||
| `+k` | Channel key | Requires a password to join (parameter: key string) | **Enforced** |
|
||||
| `+l` | User limit | Maximum number of members allowed in the channel (parameter: integer) | **Enforced** |
|
||||
| `+m` | Moderated | Only voiced (`+v`) users and operators (`+o`) can send | **Enforced** |
|
||||
| `+n` | No external | Only channel members can send messages to the channel (default: ON) | Shown only: non-members can never send to a channel, whether or not `+n` is set |
|
||||
| `+s` | Secret | Channel hidden from LIST and WHOIS for non-members | **Enforced** by `LIST` and `WHOIS`; not by `GET /api/v1/channels` |
|
||||
| `+t` | Topic lock | Only operators can change the topic (default: ON) | **Enforced** |
|
||||
| `+H` | Hashcash | Requires proof-of-work for PRIVMSG (parameter: bits, e.g. `+H 20`) | **Enforced**; the IRC listener refuses every PRIVMSG to the channel, as it cannot carry a stamp |
|
||||
|
||||
**User channel modes (set per-user per-channel):**
|
||||
|
||||
@@ -1312,10 +1312,9 @@ bans. Bans prevent both joining and sending messages.
|
||||
These ban all users from example.com, remove that ban, and list all bans
|
||||
(RPL_BANLIST 367, RPL_ENDOFBANLIST 368).
|
||||
|
||||
**Invite-only (+i):** When set, users must be invited before joining. Over the
|
||||
HTTP API, `INVITE` records an invite that is consumed on JOIN; any member can
|
||||
invite, and on a `+i` channel only an operator can. `INVITE` on the IRC listener
|
||||
tells the user about the invite but records none.
|
||||
**Invite-only (+i):** When set, users must be invited before joining. `INVITE`
|
||||
records an invite that is consumed on JOIN; any member can invite, and on a `+i`
|
||||
channel only an operator can.
|
||||
|
||||
```json
|
||||
{"command": "MODE", "to": "#channel", "body": ["+i"]}
|
||||
@@ -1323,7 +1322,9 @@ tells the user about the invite but records none.
|
||||
```
|
||||
|
||||
**Channel key (+k):** Requires a password to join the channel. Over the HTTP API
|
||||
the key is `body[0]` of the `JOIN`.
|
||||
the key is `body[0]` of the `JOIN`. On the IRC listener it follows the channel
|
||||
name, as in `JOIN #channel secretpass`; `JOIN #a,#b keya,keyb` gives each
|
||||
channel its own key.
|
||||
|
||||
```json
|
||||
{"command": "MODE", "to": "#channel", "body": ["+k", "secretpass"]}
|
||||
@@ -1338,9 +1339,8 @@ the key is `body[0]` of the `JOIN`.
|
||||
{"command": "MODE", "to": "#channel", "body": ["-l"]}
|
||||
```
|
||||
|
||||
**Secret (+s):** The HTTP API's `LIST` hides the channel from non-members, and
|
||||
its `WHOIS` leaves it out of the channel list when the querier is not in the
|
||||
same channel.
|
||||
**Secret (+s):** `LIST` hides the channel from non-members, and `WHOIS` leaves
|
||||
it out of the channel list when the querier is not in the same channel.
|
||||
|
||||
**Join errors:** a user who is banned gets ERR_BANNEDFROMCHAN (474), one not
|
||||
invited to a `+i` channel ERR_INVITEONLYCHAN (473), one with a missing or wrong
|
||||
@@ -1351,10 +1351,10 @@ key ERR_BADCHANNELKEY (475), and one joining a full channel ERR_CHANNELISFULL
|
||||
`KICK #channel nick [:reason]`. The kicked user and all channel members receive
|
||||
the KICK message.
|
||||
|
||||
**NOTICE:** Over the HTTP API, a NOTICE gets no RPL_AWAY and no hashcash check
|
||||
on `+H` channels, but it gets the same error numerics as PRIVMSG (411, 412, 401,
|
||||
403, 404). The IRC listener handles NOTICE exactly as PRIVMSG, so a NOTICE to a
|
||||
user who is away gets RPL_AWAY there.
|
||||
**NOTICE:** A NOTICE gets no hashcash check on `+H` channels, but it gets the
|
||||
same error numerics as PRIVMSG (411, 412, 401, 403, 404). Over the HTTP API it
|
||||
gets no RPL_AWAY; the IRC listener sends RPL_AWAY for a NOTICE to a user who is
|
||||
away, as it does for PRIVMSG.
|
||||
|
||||
**ISUPPORT:** The server advertises `PREFIX=(ov)@+` in RPL_ISUPPORT (005), with
|
||||
`CHANMODES=b,k,Hl,imnst` over the HTTP API and `CHANMODES=,,H,imnst` on the IRC
|
||||
@@ -1362,10 +1362,11 @@ listener.
|
||||
|
||||
### Per-Channel Hashcash (Anti-Spam)
|
||||
|
||||
Channels can require hashcash proof-of-work for every `PRIVMSG` sent over the
|
||||
HTTP API; the IRC listener does not check it. This is an anti-spam mechanism:
|
||||
channel operators set a difficulty level, and clients must compute a
|
||||
proof-of-work stamp bound to the specific channel and message before sending.
|
||||
Channels can require hashcash proof-of-work for every `PRIVMSG`. This is an
|
||||
anti-spam mechanism: channel operators set a difficulty level, and clients must
|
||||
compute a proof-of-work stamp bound to the specific channel and message before
|
||||
sending. An IRC listener client has no way to attach a stamp, so its `PRIVMSG`
|
||||
to such a channel always gets ERR_CANNOTSENDTOCHAN (404).
|
||||
|
||||
**Setting the requirement:**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user