stats: oper-gate the sensitive letters, add e/q/shun x-lines and l (links)

This commit is contained in:
Jean Chevronnet 2026-08-08 20:21:27 +00:00
parent f5cc12e809
commit cb2ac3de81
2 changed files with 29 additions and 2 deletions

View file

@ -213,6 +213,20 @@ impl Command for Stats {
}
fn handle(&self, s: &mut Server, uid: Uid, params: &[String]) -> CmdResult {
let letter = params[0].chars().next().unwrap_or(' ');
// everything but uptime exposes server internals — opers only
if letter != 'u' && !s.is_oper(uid) {
s.numeric(
uid,
ERR_NOPRIVILEGES,
":Permission Denied- You're not an IRC operator",
);
s.numeric(
uid,
RPL_ENDOFSTATS,
&format!("{letter} :End of /STATS report"),
);
return CmdResult::Fail;
}
match letter {
'u' => {
let up = now().saturating_sub(s.created);
@ -229,11 +243,14 @@ impl Command for Stats {
s.numeric(uid, RPL_STATSOLINE, &format!("O * * {n} :oper"));
}
}
'k' | 'g' | 'z' => {
'k' | 'g' | 'z' | 'e' | 'q' | 's' => {
let kind = match letter {
'k' => XKind::Kline,
'g' => XKind::Gline,
_ => XKind::Zline,
'z' => XKind::Zline,
'e' => XKind::Eline,
'q' => XKind::Qline,
_ => XKind::Shun,
};
let rows: Vec<String> = s
.xlines
@ -254,6 +271,15 @@ impl Command for Stats {
s.numeric(uid, RPL_STATSXLINE, &r);
}
}
'l' => {
for sv in s.servers.values() {
s.numeric(
uid,
RPL_STATSLINKINFO,
&format!("{} 0 0 0 0 :{}", sv.name, sv.desc),
);
}
}
_ => {}
}
s.numeric(

View file

@ -2,6 +2,7 @@
pub const RPL_MAP: u16 = 6;
pub const RPL_MAPEND: u16 = 7;
pub const RPL_STATSLINKINFO: u16 = 211; // STATS l — a server link
pub const RPL_STATSCOMMANDS: u16 = 212;
pub const RPL_ENDOFSTATS: u16 = 219;
pub const RPL_STATSUPTIME: u16 = 242;