fix(irc): linear OSC stripping, bounded joins and CAP state, no cleartext passwords

- ircformat: an unterminated OSC made the stripper advance two bytes and
  rescan the rest, so one hostile 1 MiB line of ESC ] froze the UI thread
  for minutes. It now stops at the first OSC with no terminator (none can
  follow), which is linear.
- Server lines are capped at 64 KiB (512 bytes + 8 KiB of tags is the
  real ceiling) instead of 1 MiB.
- Spoofed self-JOINs can't grow channel state past 500 rooms (they were
  also persisted and auto-joined next time); CAP LS is ignored after
  registration and its gathered list is capped.
- PASS, SASL PLAIN and NickServ IDENTIFY are only sent over TLS, an SSH
  tunnel or a loopback server; otherwise the Server tab says why.
- TcpConn: a local close no longer races the reader into reporting a
  spurious read error (regression from 00f110f, which shut the socket
  down before taking the stream).
This commit is contained in:
Andy Dixon
2026-10-13 06:46:38 +01:00
parent d6f8f3306b
commit 7f3704e890
3 changed files with 87 additions and 12 deletions
+12 -4
View File
@@ -224,10 +224,10 @@ fn strip_terminal_escapes(value: &str) -> String {
s.push_str(&rest[..pos]);
rest = &body[end..];
}
None => {
s.push_str(&rest[..pos + 2]);
rest = body;
}
// No terminator anywhere after this OSC, so none after any later OSC either:
// keep the rest as is. (Advancing two bytes and searching again was quadratic, and
// one hostile 1 MiB line of "\x1b]" froze the UI for minutes.)
None => break,
}
}
s.push_str(rest);
@@ -425,6 +425,14 @@ mod tests {
assert_eq!(plain_text("\x02bold\x02 \x0304red\x03"), "bold red");
}
#[test]
fn unterminated_osc_runs_are_linear() {
let start = std::time::Instant::now();
let out = plain_text(&"\x1b]".repeat(500_000));
assert!(start.elapsed() < std::time::Duration::from_secs(2), "{:?}", start.elapsed());
assert!(!out.contains('\x1b'));
}
#[test]
fn untrusted_terminal_sequences_are_removed() {
assert_eq!(plain_text("before\x1b[31munsafe\x1b]0;title\x07after"), "beforeunsafeafter");