harden: connclass clone-cap at register, ws control-frame limits, uuid recycle-skip, json-escape extjwt/filehost claims, metadata value/key caps, cloak numeric-dotted leak, relaymsg remote-nick, rpc set_oper block validation, isupport 13-token split, multi-hop privmsg routing, connectdelay=0

This commit is contained in:
Jean Chevronnet 2026-08-15 16:27:11 +00:00
parent e935ee7002
commit 35af95fd0f
11 changed files with 129 additions and 27 deletions

View file

@ -79,18 +79,25 @@ impl Server {
/// Mint the next network-wide UID for a local user: our SID + 6 base-26 chars
/// (e.g. `0AAAAAAAB`).
pub fn next_uuid(&mut self) -> String {
let mut x = self.uuid_counter;
self.uuid_counter += 1;
let mut suffix = [b'A'; 6];
for c in suffix.iter_mut().rev() {
*c = b'A' + (x % 26) as u8;
x /= 26;
loop {
let mut x = self.uuid_counter;
self.uuid_counter += 1;
let mut suffix = [b'A'; 6];
for c in suffix.iter_mut().rev() {
*c = b'A' + (x % 26) as u8;
x /= 26;
}
let uuid = format!(
"{}{}",
self.sid,
std::str::from_utf8(&suffix).unwrap_or("AAAAAA")
);
// after 26^6 mints the counter wraps and could re-issue a still-live id;
// skip any that's in use so uuids stay unique
if !self.uuid_local.contains_key(&uuid) && !self.remote_users.contains_key(&uuid) {
return uuid;
}
}
format!(
"{}{}",
self.sid,
std::str::from_utf8(&suffix).unwrap_or("AAAAAA")
)
}
/// Register a new server-link connection. An **outbound** link introduces
@ -966,6 +973,9 @@ impl Server {
.map(|u| u.nick.clone())
.unwrap_or_default();
self.send(dst, format!(":{prefix} {cmd} {nick} :{text}"));
} else {
// a remote target reached via another link (multi-hop) — forward onward
self.forward_to_target(&target, msg, via);
}
}