chanserv: SET PEACE (block acting against equal-or-higher access)
PEACE stops a channel op from using ChanServ KICK/BAN/DEOP/DEVOICE against someone whose access rank (founder>op>voice) is equal to or above their own. Adds a typed access_rank on ChannelView and a peace_blocks guard in those commands. Same typed-settings path as SIGNKICK/PRIVATE; shown in INFO.
This commit is contained in:
parent
75019c867a
commit
3bf6b2be77
7 changed files with 62 additions and 2 deletions
|
|
@ -157,6 +157,9 @@ pub struct ChanSettings {
|
|||
// Hide the channel from ChanServ LIST.
|
||||
#[serde(default)]
|
||||
pub private: bool,
|
||||
// Forbid using ChanServ to act against someone with equal-or-higher access.
|
||||
#[serde(default)]
|
||||
pub peace: bool,
|
||||
}
|
||||
|
||||
// A registered channel and who owns it.
|
||||
|
|
@ -586,7 +589,7 @@ impl Db {
|
|||
if !c.entrymsg.is_empty() {
|
||||
snapshot.push(Event::ChannelEntryMsgSet { channel: c.name.clone(), msg: c.entrymsg.clone() });
|
||||
}
|
||||
if c.settings.signkick || c.settings.private {
|
||||
if c.settings.signkick || c.settings.private || c.settings.peace {
|
||||
snapshot.push(Event::ChannelSettingsSet { channel: c.name.clone(), settings: c.settings });
|
||||
}
|
||||
}
|
||||
|
|
@ -1115,6 +1118,7 @@ impl Db {
|
|||
match setting {
|
||||
ChanSetting::SignKick => settings.signkick = on,
|
||||
ChanSetting::Private => settings.private = on,
|
||||
ChanSetting::Peace => settings.peace = on,
|
||||
}
|
||||
self.log
|
||||
.append(Event::ChannelSettingsSet { channel: channel.to_string(), settings })
|
||||
|
|
@ -1479,6 +1483,7 @@ fn channel_view(c: &ChannelInfo) -> ChannelView {
|
|||
entrymsg: c.entrymsg.clone(),
|
||||
signkick: c.settings.signkick,
|
||||
private: c.settings.private,
|
||||
peace: c.settings.peace,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1613,6 +1618,21 @@ mod tests {
|
|||
assert!(s.signkick && !s.private, "settings replay from the log");
|
||||
}
|
||||
|
||||
// Access ranks order founder > op > voice > none for PEACE comparisons.
|
||||
#[test]
|
||||
fn access_rank_orders_founder_op_voice() {
|
||||
let mut db = Db::open(&tmp("rank"), "N1");
|
||||
db.register_channel("#c", "boss").unwrap();
|
||||
db.access_add("#c", "op1", "op").unwrap();
|
||||
db.access_add("#c", "v1", "voice").unwrap();
|
||||
let cv = Store::channel(&db, "#c").unwrap();
|
||||
assert_eq!(cv.access_rank(Some("boss")), 3);
|
||||
assert_eq!(cv.access_rank(Some("OP1")), 2, "case-insensitive");
|
||||
assert_eq!(cv.access_rank(Some("v1")), 1);
|
||||
assert_eq!(cv.access_rank(Some("nobody")), 0);
|
||||
assert_eq!(cv.access_rank(None), 0);
|
||||
}
|
||||
|
||||
// A wrong code is tolerated a few times, then the code is burned so it can't
|
||||
// be ground down online even though it is short.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue