From 16ea4b5a232c51fe047c02a2bd62153b96b8c0ab Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 02:29:59 +0000 Subject: [PATCH] =?UTF-8?q?core=5Fmessage:=20compute=20the=20sender's=20ch?= =?UTF-8?q?annel=20rank=20once=20per=20message=20(mrank)=20instead=20of=20?= =?UTF-8?q?recomputing=20s.rank(uid,&key)=20up=20to=207x=20in=20the=20chan?= =?UTF-8?q?nel=20PRIVMSG/NOTICE=20gate=20and=20once=20more=20in=20TAGMSG?= =?UTF-8?q?=20=E2=80=94=20rank=20is=20fixed=20for=20a=20single=20message?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coremods/core_message.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/coremods/core_message.rs b/src/coremods/core_message.rs index 93ad272..1b3b23f 100644 --- a/src/coremods/core_message.rs +++ b/src/coremods/core_message.rs @@ -203,6 +203,8 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) }; if target.starts_with('#') { let key = target.to_ascii_lowercase(); + // rank is fixed for this message — compute it once instead of on every check + let mrank = s.rank(uid, &key); let (member, no_external) = s .channels .get(&key) @@ -234,7 +236,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) .get(&key) .map(|c| c.modes.opmoderated) .unwrap_or(false) - && s.rank(uid, &key) < RANK_VOICE; + && mrank < RANK_VOICE; // +m: only voiced-or-above may speak let moderated = s .channels @@ -242,7 +244,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) .map(|c| c.modes.moderated) .unwrap_or(false); if moderated - && s.rank(uid, &key) < RANK_VOICE + && mrank < RANK_VOICE && !op_only && !s.chanop_exempt(uid, &key, "moderated") { @@ -262,7 +264,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) .map(|c| c.modes.reg_moderated) .unwrap_or(false); if reg_moderated - && s.rank(uid, &key) < RANK_VOICE + && mrank < RANK_VOICE && !s.is_logged_in(uid) && !s.chanop_exempt(uid, &key, "regmoderated") { @@ -277,7 +279,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) } // +d delaymsg — a just-joined unprivileged user must wait before speaking if let Some(secs) = s.channels.get(&key).and_then(|c| c.modes.delaymsg) { - if s.rank(uid, &key) < RANK_VOICE && !s.chanop_exempt(uid, &key, "delaymsg") { + if mrank < RANK_VOICE && !s.chanop_exempt(uid, &key, "delaymsg") { let joined = s .channels .get(&key) @@ -297,7 +299,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) } } // extban `m:` mute — matched users can't speak unless voiced-or-above - if s.extban_active(uid, &key, 'm') && s.rank(uid, &key) < RANK_VOICE { + if s.extban_active(uid, &key, 'm') && mrank < RANK_VOICE { if !notice { s.numeric( uid, @@ -308,7 +310,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) return CmdResult::Fail; } // +f message flood — ops/half-ops and opers are exempt; others get kicked - let flood_exempt = s.rank(uid, &key) >= RANK_HALFOP + let flood_exempt = mrank >= RANK_HALFOP || s.users.get(&uid).map(|u| u.flags.oper).unwrap_or(false); if !flood_exempt && !s.chanop_exempt(uid, &key, "flood") { if let Some(ban) = s.messageflood_hit(uid, &key) { @@ -422,7 +424,7 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool) } // +K repeat — reject a line the sender just repeated; else remember it (ops exempt) if let Some(n) = s.channels.get(&key).and_then(|c| c.modes.repeat) { - if s.rank(uid, &key) < RANK_HALFOP && !s.chanop_exempt(uid, &key, "repeat") { + if mrank < RANK_HALFOP && !s.chanop_exempt(uid, &key, "repeat") { let repeated = s .channels .get(&key) @@ -718,6 +720,7 @@ impl Command for TagMsg { let msgid = s.next_msgid(); // shared across this TAGMSG's recipients if target.starts_with('#') { let key = target.to_ascii_lowercase(); + let mrank = s.rank(uid, &key); if !s .channels .get(&key) @@ -732,7 +735,7 @@ impl Command for TagMsg { .get(&key) .map(|c| c.modes.moderated) .unwrap_or(false); - if moderated && s.rank(uid, &key) < RANK_VOICE { + if moderated && mrank < RANK_VOICE { return CmdResult::Fail; } let echo = s