From d495fd0f3039c0e68d9f4ab4052a712e946136bc Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 01:22:32 +0000 Subject: [PATCH] =?UTF-8?q?channel:=20cap=20the=20per-channel=20invite=20s?= =?UTF-8?q?et=20(maxinvites,=20default=20100)=20=E2=80=94=20it=20only=20sh?= =?UTF-8?q?rank=20when=20the=20invitee=20joined,=20so=20an=20op=20could=20?= =?UTF-8?q?grow=20it=20unboundedly;=20re-inviting=20an=20already-listed=20?= =?UTF-8?q?nick=20still=20works?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coremods/core_channel.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/coremods/core_channel.rs b/src/coremods/core_channel.rs index 57ec9f9..7700b11 100644 --- a/src/coremods/core_channel.rs +++ b/src/coremods/core_channel.rs @@ -309,6 +309,17 @@ impl Command for Invite { ); return CmdResult::Fail; } + // cap the per-channel invite set — it only grows until the invitee joins, so + // without a bound an op could grow it indefinitely (like maxbans caps +b). + let maxinv = s.conf_num("maxinvites", 100usize); + if s.channels[&key].invites.len() >= maxinv && !s.channels[&key].invites.contains(&tuid) { + let nick = s.users.get(&uid).map(|u| u.nick.clone()).unwrap_or_default(); + s.send( + uid, + format!(":{} NOTICE {nick} :{chan} :Channel invite list is full", s.name), + ); + return CmdResult::Fail; + } if let Some(ch) = s.channels.get_mut(&key) { ch.invites.insert(tuid); }