channels/whois: validate +k/+l, cap and case-fold ban lists, honour -n for externals, hide +s/+p/+i from whois/who/names, 301 in whois, conf-key the join/nickflood lockout

This commit is contained in:
Jean Chevronnet 2026-08-16 17:56:24 +00:00
parent 4028cd3c84
commit 579c321670
5 changed files with 90 additions and 25 deletions

View file

@ -161,20 +161,29 @@ pub(crate) fn deliver(s: &mut Server, uid: Uid, params: &[String], notice: bool)
};
if target.starts_with('#') {
let key = target.to_ascii_lowercase();
let member = s
let (member, no_external) = s
.channels
.get(&key)
.map(|c| c.members.contains_key(&uid))
.unwrap_or(false);
.map(|c| (c.members.contains_key(&uid), c.modes.no_external))
.unwrap_or((false, true));
if !member {
if !notice {
s.numeric(
uid,
ERR_CANNOTSENDTOCHAN,
&format!("{target} :Cannot send to channel"),
);
// +n (default): only members may message the channel. With -n an external
// user may — unless banned (+b, not +e-excepted), so -n can't evade a ban.
let banned = s
.channels
.get(&key)
.map(|c| s.ban_list_hit(uid, &c.bans) && !s.ban_list_hit(uid, &c.excepts))
.unwrap_or(true);
if no_external || banned {
if !notice {
s.numeric(
uid,
ERR_CANNOTSENDTOCHAN,
&format!("{target} :Cannot send to channel"),
);
}
return CmdResult::Fail;
}
return CmdResult::Fail;
}
// +U opmoderated — an unprivileged user's message isn't blocked; it's routed
// to channel ops only (below). It also overrides +m's block for that purpose.