diff --git a/modules/chanserv/src/access.rs b/modules/chanserv/src/access.rs index 5728e0d..836da55 100644 --- a/modules/chanserv/src/access.rs +++ b/modules/chanserv/src/access.rs @@ -69,6 +69,7 @@ fn is_founder(me: &str, from: &Sender, chan: &str, ctx: &mut ServiceCtx, db: &dy ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change access.")); false } - Some(_) => true, + // Founder, but a staff-suspended channel is frozen — no access changes. + Some(_) => !super::suspended_block(me, from, chan, ctx, db), } } diff --git a/modules/chanserv/src/flags.rs b/modules/chanserv/src/flags.rs index 0b00ebe..651b6bd 100644 --- a/modules/chanserv/src/flags.rs +++ b/modules/chanserv/src/flags.rs @@ -45,6 +45,9 @@ pub fn handle(me: &str, from: &Sender, chan: &str, args: &[&str], ctx: &mut Serv ctx.notice(me, from.uid, format!("You need the founder or the \x02a\x02 flag to change access on \x02{chan}\x02.")); return; } + if super::suspended_block(me, from, chan, ctx, db) { + return; // a staff-suspended channel is frozen: no flag changes either + } if info.founder.eq_ignore_ascii_case(target) { ctx.notice(me, from.uid, "The founder's access is set with \x02SET FOUNDER\x02, not flags."); return; diff --git a/modules/chanserv/src/lib.rs b/modules/chanserv/src/lib.rs index 0157a2a..939f3e4 100644 --- a/modules/chanserv/src/lib.rs +++ b/modules/chanserv/src/lib.rs @@ -378,7 +378,12 @@ fn peace_blocks(me: &str, from: &Sender, chan: &str, target_uid: &str, ctx: &mut if target_uid == from.uid { return false; } - if info.access_rank(net.account_of(target_uid)) >= info.access_rank(from.account) { + // Group-aware rank: channel_caps resolves !group access (and founder), so PEACE + // protects a member whose access comes via a group, not just direct entries — + // ChannelView::access_rank is group-blind and let a plain op act against a + // group-SOP it should protect. + let rank = |account: Option<&str>| account.map_or(echo_api::Rank::None, |a| db.channel_caps(chan, a).rank); + if rank(net.account_of(target_uid)) >= rank(from.account) { ctx.notice(me, from.uid, "\x02PEACE\x02 is set: you can't act against someone with equal or higher access."); return true; } diff --git a/modules/chanserv/src/mode.rs b/modules/chanserv/src/mode.rs index f2a3fec..19a42f1 100644 --- a/modules/chanserv/src/mode.rs +++ b/modules/chanserv/src/mode.rs @@ -24,6 +24,9 @@ pub fn handle(me: &str, from: &Sender, args: &[&str], ctx: &mut ServiceCtx, db: ctx.notice(me, from.uid, format!("Only \x02{chan}\x02's founder can change its modes.")); return; } + if super::suspended_block(me, from, chan, ctx, db) { + return; // a staff-suspended channel is frozen: no mode changes either + } // Reject an extban the network has turned off, before relaying anything. for mask in ban_masks(&args[2..], |m, adding| db.chanmode_takes_param(m, adding)) { let core = mask.strip_prefix('!').unwrap_or(mask); // extbans may be inverted