exemptchanops +X: per-rank exemptions from flood/anticaps/repeat/censor/blockcolor/etc

This commit is contained in:
Jean Chevronnet 2026-08-09 07:34:42 +00:00
parent 789c2ca14f
commit 80cc61e7f8
6 changed files with 74 additions and 22 deletions

View file

@ -275,10 +275,11 @@ pub struct Channel {
pub rmembers: HashMap<String, Member>, // remote members, by network uuid (S2S)
pub modes: ChanModes,
pub bans: Vec<Ban>,
pub excepts: Vec<Ban>, // +e ban exceptions
pub invex: Vec<Ban>, // +I invite exceptions
pub filters: Vec<Ban>, // +g word/glob message filters (mask = the glob)
pub invites: HashSet<Uid>, // uids allowed past +i
pub excepts: Vec<Ban>, // +e ban exceptions
pub invex: Vec<Ban>, // +I invite exceptions
pub filters: Vec<Ban>, // +g word/glob message filters (mask = the glob)
pub exemptchanops: Vec<Ban>, // +X exemptions (mask = "restriction:rankchar")
pub invites: HashSet<Uid>, // uids allowed past +i
pub created: u64,
// --- ephemeral flood counters (not modes; never rendered or synced) -------
pub msgflood_hits: HashMap<Uid, Vec<u64>>, // +f per-user message times
@ -306,6 +307,7 @@ impl Channel {
excepts: Vec::new(),
invex: Vec::new(),
filters: Vec::new(),
exemptchanops: Vec::new(),
invites: HashSet::new(),
created: now(),
msgflood_hits: HashMap::new(),
@ -355,6 +357,32 @@ impl Server {
.unwrap_or(false)
}
/// +X exemptchanops — is `uid` exempt from `restriction` in this channel? True
/// when a `+X <restriction>:<rankchar>` entry names a rank they meet or exceed.
pub fn chanop_exempt(&self, uid: Uid, key: &str, restriction: &str) -> bool {
let Some(ch) = self.channels.get(key) else {
return false;
};
let rank = self.rank(uid, key);
ch.exemptchanops.iter().any(|e| {
let Some((r, prefix)) = e.mask.split_once(':') else {
return false;
};
if !r.eq_ignore_ascii_case(restriction) {
return false;
}
let need = match prefix.chars().next() {
Some('q') => RANK_OWNER,
Some('a') => RANK_ADMIN,
Some('o') => RANK_OP,
Some('h') => RANK_HALFOP,
Some('v') => RANK_VOICE,
_ => return false,
};
rank >= need
})
}
/// Lift any expired TBAN timed bans, announcing `MODE -b` to each channel.
/// Called from the background tick.
pub fn purge_tbans(&mut self) {