Proof of concept mechanical port of ircnet/ircd to Rust as part of a bit about C being insecure for network services
0

Configure Feed

Select the types of activity you want to include in your feed.

refactor(mode): factor operator check into mode::is_oper

The compound operator test modes & (Oper.bit() | LocalOp.bit()) != 0
was hand-inlined at ~34 sites across the command and s2s planes, so any
change to what counts as an operator meant editing all of them and
risking drift. Add mode::is_oper beside the existing is_deaf/is_restricted
/is_operwall predicates and route every site (both != 0 and == 0
polarities) through it. Semantics-preserving.

+84 -89
+2 -1
leveva/src/command/chghost.rs
··· 32 32 33 33 use crate::command::*; 34 34 use crate::ident::{HostName, UserName}; 35 + #[cfg(test)] 35 36 use crate::UserMode; 36 37 37 38 /// `CHGHOST <newuser> <newhost>` — change the issuing operator's own `user@host`. 38 39 pub(crate) fn chghost(client: &mut Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 39 40 // Operator-gated (the oracle `m_nopriv`), exactly as KILL — no per-`ACL_*` privilege. 40 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 41 + if !crate::mode::is_oper(client.modes) { 41 42 return vec![no_privileges(ctx, &client.nick)]; 42 43 } 43 44 let params = msg.params();
+2 -5
leveva/src/command/etrace.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 - 4 - /// The oper-status bits (`+o`/`+O`): a record carrying either is an operator, so its 5 - /// `708` line is labelled `Oper` rather than `User`. 6 - const OPER_BITS: u32 = UserMode::Oper.bit() | UserMode::LocalOp.bit(); 7 4 8 5 /// `ETRACE [<target>]` — the **extended** trace: a full per-local-person report with the 9 6 /// `user`/`host`/`ip`/`realname` columns. ··· 69 66 to: &str, 70 67 rec: &crate::registry::ClientRecord, 71 68 ) -> Message { 72 - let label = if rec.modes & OPER_BITS != 0 { 69 + let label = if crate::mode::is_oper(rec.modes) { 73 70 "Oper" 74 71 } else { 75 72 "User"
+2 -1
leveva/src/command/findforwards.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// A conservative width (bytes) for one `NOTICE` payload line of forwarder names. Well under the ··· 49 50 } 50 51 // Member of the channel, or an operator (the operspy-equivalent bypass). 51 52 let is_member = ctx.channels.member_status(chan, &client.uid).is_some(); 52 - let is_oper = client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 53 + let is_oper = crate::mode::is_oper(client.modes); 53 54 if !is_member && !is_oper { 54 55 return vec![Message::builder(Numeric::ErrNotonchannel) 55 56 .prefix(&ctx.name)
+1 -2
leveva/src/command/join.rs
··· 1 1 use crate::command::*; 2 - use crate::UserMode; 3 2 4 3 /// The numeric for a [`JoinReject`] from `check_join`. 5 4 fn join_reject(ctx: &ServerContext, nick: &str, chan: &str, reject: JoinReject) -> Message { ··· 139 138 // +O (oper-only) admits only IRC operators (`+o` global or `+O` local usermode); the 140 139 // whole `check_join` mode gate is skipped under an oper override (`bypass`). 141 140 if !bypass { 142 - let is_oper = joiner.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 141 + let is_oper = crate::mode::is_oper(joiner.modes); 143 142 // RESV (slice 272): a reserved channel is unavailable to non-operators — `437`, and it 144 143 // never `+f`-forwards (the channel is simply unavailable, not redirected). Operators 145 144 // bypass, exactly as they bypass every other JOIN gate (`bypass`/`is_oper`). This is the
+2 -1
leveva/src/command/kill.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `KILL <nick> <comment>` — an operator forcibly disconnects a client. ··· 35 36 /// truncation. Self-kill is permitted (faithful — it is a local kill of a local user). 36 37 pub(crate) fn kill(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 37 38 // Privilege gate first: only operators may KILL. 38 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 39 + if !crate::mode::is_oper(client.modes) { 39 40 return vec![Message::builder(Numeric::ErrNoprivileges) 40 41 .prefix(&ctx.name) 41 42 .param(&client.nick)
+1 -2
leveva/src/command/knock.rs
··· 1 1 use crate::command::*; 2 - use crate::UserMode; 3 2 4 3 /// `KNOCK <channel> [<reason>]` — ask a restricted channel's operators for an invite. 5 4 /// ··· 82 81 // Run the JOIN gate from the knocker's perspective (no key). Build the extban subject 83 82 // attributes from the registry exactly as the JOIN path does, so `$a`/`$z`/`$r`/`$x` bans 84 83 // bite identically. 85 - let is_oper = client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 84 + let is_oper = crate::mode::is_oper(client.modes); 86 85 let record = ctx.registry.record_of(&client.uid); 87 86 let account = record.as_ref().and_then(|r| r.account.as_deref()); 88 87 let is_ssl = record.as_ref().is_some_and(|r| r.certfp.is_some());
+1 -1
leveva/src/command/locops.rs
··· 23 23 /// recipients' mailboxes, like a channel `PRIVMSG`. 24 24 pub(crate) fn locops(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 25 25 // Privilege gate first: only operators may locops. 26 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 26 + if !crate::mode::is_oper(client.modes) { 27 27 return vec![Message::builder(Numeric::ErrNoprivileges) 28 28 .prefix(&ctx.name) 29 29 .param(&client.nick)
+2 -2
leveva/src/command/message.rs
··· 69 69 .record_of(&sender.uid) 70 70 .and_then(|r| r.account) 71 71 .is_some(); 72 - let oper = sender.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 72 + let oper = crate::mode::is_oper(sender.modes); 73 73 let accepted = ctx.registry.callerid().is_accepted(target, &sender.uid); 74 74 crate::callerid::regonly_msg_blocks(target_regonly, identified, oper, accepted) 75 75 } ··· 172 172 // IRCv3 oper-tag: an operator (`+o`/`+O`) sender's outgoing messages carry a valueless 173 173 // `draft/oper` tag — but only to recipients that negotiated `draft/oper-tag` (read once). 174 174 // Also gates the `$$`/`$#` mask broadcast below (only an oper may mask-broadcast). 175 - let sender_is_oper = client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 175 + let sender_is_oper = crate::mode::is_oper(client.modes); 176 176 // IRCv3 account-tag: a sender signed in to a services account has its account name stamped 177 177 // as `@account` on each delivery to a recipient with `account-tag` (read the sender's 178 178 // registry-record account once). A not-signed-in sender stamps nothing.
+2 -2
leveva/src/command/metadata.rs
··· 150 150 /// Whether `client` is an IRC operator (`+o`/`+O`) — the gate for setting/viewing an 151 151 /// oper-restricted metadata key (slice 223). 152 152 fn is_oper(client: &Registered) -> bool { 153 - client.modes & (crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit()) != 0 153 + crate::mode::is_oper(client.modes) 154 154 } 155 155 156 156 /// Whether `client` may set/clear metadata on `rt`: on itself, or on a channel it ops. ··· 429 429 /// — the per-recipient gate for delivering an oper-restricted metadata push (slice 223). 430 430 fn member_is_oper(ctx: &ServerContext, uid: &Uid) -> bool { 431 431 ctx.registry.record_of(uid).is_some_and(|r| { 432 - r.modes & (crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit()) != 0 432 + crate::mode::is_oper(r.modes) 433 433 }) 434 434 } 435 435
+2 -3
leveva/src/command/mod.rs
··· 295 295 kicker: &Registered, 296 296 victim: &Uid, 297 297 ) -> bool { 298 - let oper_bits = crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit(); 299 - let kicker_is_oper = kicker.modes & oper_bits != 0; 300 - let victim_is_oper = ctx.registry.modes_of(victim) & oper_bits != 0; 298 + let kicker_is_oper = crate::mode::is_oper(kicker.modes); 299 + let victim_is_oper = crate::mode::is_oper(ctx.registry.modes_of(victim)); 301 300 crate::channel::operpeace_blocks( 302 301 ctx.channels.operpeace_enabled(display), 303 302 kicker_is_oper,
+4 -4
leveva/src/command/mode.rs
··· 268 268 /// target (`SAMODE <nick>`) passes straight through to [`umode`] — the override has no 269 269 /// meaning there, so it behaves identically to `MODE`. 270 270 pub(crate) fn samode(client: &mut Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 271 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 271 + if !crate::mode::is_oper(client.modes) { 272 272 return vec![Message::builder(Numeric::ErrNoprivileges) 273 273 .prefix(&ctx.name) 274 274 .param(&client.nick) ··· 339 339 let setter_attrs = crate::extban::SubjectAttrs { 340 340 realname: &client.realname, 341 341 account: setter_record.as_ref().and_then(|r| r.account.as_deref()), 342 - is_oper: client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0, 342 + is_oper: crate::mode::is_oper(client.modes), 343 343 is_ssl: setter_record.as_ref().is_some_and(|r| r.certfp.is_some()), 344 344 server: &ctx.name, 345 345 umodes: client.modes, ··· 755 755 // snomask parameter. Clearing `-s` is always permitted and zeroes the mask. 756 756 's' => { 757 757 if adding { 758 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0 { 758 + if crate::mode::is_oper(client.modes) { 759 759 modes |= snobit; 760 760 plus_s_seen = true; 761 761 if i + 1 < changes.len() { ··· 805 805 'z' | 'l' => { 806 806 let bit = UserMode::from_char(c).expect("z/l are user modes").bit(); 807 807 if adding { 808 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0 { 808 + if crate::mode::is_oper(client.modes) { 809 809 modes |= bit; 810 810 } 811 811 } else {
+1 -2
leveva/src/command/nick.rs
··· 1 1 use crate::command::*; 2 - use crate::UserMode; 3 2 4 3 /// Post-registration `NICK <newnick>`: validate, then update the shared registry 5 4 /// and the connection's own identity. ··· 59 58 // before the rename. Operators bypass, exactly as they may use any nick. A case-only 60 59 // self-rename of an already-held reserved nick is still blocked here — but an operator who 61 60 // already holds the nick is exempt, and an ordinary user could never have acquired it. 62 - let is_oper = client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 61 + let is_oper = crate::mode::is_oper(client.modes); 63 62 if !is_oper && ctx.resvs.nick_reserved(&new).is_some() { 64 63 return vec![Message::builder(Numeric::ErrErroneousnickname) 65 64 .prefix(&ctx.name)
+2 -1
leveva/src/command/ojoin.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `OJOIN <channel>` — leveva's port of InspIRCd's `m_ojoin` "official join" (P11 slice 165). ··· 22 23 /// members only (the `+Y`/`+o` MODE is what propagates network-wide). The rank is `128`, not 23 24 /// InspIRCd's `9000000` (leveva ranks are `u8`). 24 25 pub(crate) fn ojoin(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 25 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 26 + if !crate::mode::is_oper(client.modes) { 26 27 return vec![no_privileges(ctx, &client.nick)]; 27 28 } 28 29 let Some(chan) = msg
+2 -1
leveva/src/command/okick.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `OKICK <channel> <user> [:comment]` — leveva's port of charybdis `extensions/m_okick.c` (P11 ··· 29 30 /// member; the audit notice rides the `+s` snomask, not `+w` wallops (SA*/OJOIN/OPME family, 30 31 /// slices 184/186/292); local-only. The comment defaults to the oper's nick (KICK precedent). 31 32 pub(crate) fn okick(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 32 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 33 + if !crate::mode::is_oper(client.modes) { 33 34 return vec![no_privileges(ctx, &client.nick)]; 34 35 } 35 36 let Some(chan) = msg.params().first().filter(|s| !s.is_empty()) else {
+2 -1
leveva/src/command/olist.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `321 RPL_LISTSTART` header (matches [`super::list`]'s conventional header). ··· 47 48 /// notice. Documented, not replicated. 48 49 /// - Local-only — a read of *this* server's channel table (charybdis OLIST is per-server too). 49 50 pub(crate) fn olist(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 50 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 51 + if !crate::mode::is_oper(client.modes) { 51 52 return vec![no_privileges(ctx, &client.nick)]; 52 53 } 53 54
+15 -22
leveva/src/command/oper.rs
··· 53 53 } 54 54 55 55 // Re-`381` an existing operator without re-checking credentials. 56 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0 { 56 + if crate::mode::is_oper(client.modes) { 57 57 return vec![youre_oper(ctx, &client.nick)]; 58 58 } 59 59 ··· 184 184 dispatch(client, &Message::parse(line).unwrap(), ctx) 185 185 } 186 186 187 - /// `client()` is `alice@127.0.0.1` (matching the testutil fixture host). 188 - fn oper_bits() -> u32 { 189 - UserMode::Oper.bit() | UserMode::LocalOp.bit() 190 - } 191 - 192 187 #[test] 193 188 fn missing_params_gives_461() { 194 189 let ctx = ctx_with_oper("*@*", "pw", false); ··· 205 200 let r = drive(&mut alice, &ctx, "OPER nobody pw"); 206 201 assert_eq!(codes(&r), &["491"]); 207 202 // Inverse: no oper bit gained. 208 - assert_eq!(alice.modes & oper_bits(), 0); 203 + assert!(!crate::mode::is_oper(alice.modes)); 209 204 } 210 205 211 206 #[test] ··· 215 210 let mut alice = client(); 216 211 let _ = claim_observed(&ctx, "alice"); 217 212 assert_eq!(codes(&drive(&mut alice, &ctx, "OPER root pw")), &["491"]); 218 - assert_eq!(alice.modes & oper_bits(), 0); 213 + assert!(!crate::mode::is_oper(alice.modes)); 219 214 } 220 215 221 216 #[test] ··· 227 222 assert_eq!(codes(&r), &["464"]); 228 223 assert_eq!(r[0].trailing(), Some("Password Incorrect")); 229 224 // Inverse: a failed login grants nothing. 230 - assert_eq!(alice.modes & oper_bits(), 0); 231 - assert_eq!( 232 - ctx.registry.record_of(&uid_for("alice")).unwrap().modes & oper_bits(), 233 - 0 234 - ); 225 + assert!(!crate::mode::is_oper(alice.modes)); 226 + assert!(!crate::mode::is_oper( 227 + ctx.registry.record_of(&uid_for("alice")).unwrap().modes 228 + )); 235 229 } 236 230 237 231 #[test] ··· 314 308 assert_eq!(codes(&r), &["484"]); 315 309 assert_eq!(r[0].trailing(), Some("Your connection is restricted!")); 316 310 // Inverse: no oper bit on the connection or mirrored into the registry. 317 - assert_eq!(alice.modes & oper_bits(), 0); 318 - assert_eq!( 319 - ctx.registry.record_of(&uid_for("alice")).unwrap().modes & oper_bits(), 320 - 0 321 - ); 311 + assert!(!crate::mode::is_oper(alice.modes)); 312 + assert!(!crate::mode::is_oper( 313 + ctx.registry.record_of(&uid_for("alice")).unwrap().modes 314 + )); 322 315 } 323 316 324 317 #[test] ··· 368 361 .set_certfp(&alice.uid, Some("abcdef0123456789")); 369 362 let r = drive(&mut alice, &ctx, "OPER root pw"); 370 363 assert_eq!(codes(&r), &["MODE", "381"]); 371 - assert_ne!(alice.modes & oper_bits(), 0); 364 + assert!(crate::mode::is_oper(alice.modes)); 372 365 } 373 366 374 367 #[test] ··· 381 374 // The password was right but the fingerprint requirement fails → 491, not 464. 382 375 assert_eq!(codes(&r), &["491"]); 383 376 // Inverse: no oper bit granted. 384 - assert_eq!(alice.modes & oper_bits(), 0); 377 + assert!(!crate::mode::is_oper(alice.modes)); 385 378 } 386 379 387 380 #[test] ··· 393 386 .set_certfp(&alice.uid, Some("00000000deadbeef")); 394 387 let r = drive(&mut alice, &ctx, "OPER root pw"); 395 388 assert_eq!(codes(&r), &["491"]); 396 - assert_eq!(alice.modes & oper_bits(), 0); 389 + assert!(!crate::mode::is_oper(alice.modes)); 397 390 } 398 391 399 392 #[test] ··· 421 414 codes(&drive(&mut alice, &ctx, "OPER root pw")), 422 415 &["MODE", "381"] 423 416 ); 424 - assert_ne!(alice.modes & oper_bits(), 0); 417 + assert!(crate::mode::is_oper(alice.modes)); 425 418 } 426 419 }
+1 -1
leveva/src/command/operwall.rs
··· 19 19 /// mailboxes, like a channel `PRIVMSG`. 20 20 pub(crate) fn operwall(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 21 21 // Privilege gate first: only operators may operwall. 22 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 22 + if !crate::mode::is_oper(client.modes) { 23 23 return vec![Message::builder(Numeric::ErrNoprivileges) 24 24 .prefix(&ctx.name) 25 25 .param(&client.nick)
+2 -1
leveva/src/command/opme.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `OPME <channel>` — leveva's port of charybdis `extensions/m_opme.c` (P11 slice 292). An IRC ··· 28 29 /// the "is not opless"/audit wording is leveva's; local-only (a read+grant of this server's 29 30 /// channel table, like charybdis's per-server OPME). 30 31 pub(crate) fn opme(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 31 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 32 + if !crate::mode::is_oper(client.modes) { 32 33 return vec![no_privileges(ctx, &client.nick)]; 33 34 } 34 35 let Some(chan) = msg.params().first().filter(|s| !s.is_empty()) else {
+1 -3
leveva/src/command/redact.rs
··· 58 58 let attrs = crate::extban::SubjectAttrs { 59 59 realname: &client.realname, 60 60 account: account.as_deref(), 61 - is_oper: client.modes 62 - & (crate::mode::UserMode::Oper.bit() | crate::mode::UserMode::LocalOp.bit()) 63 - != 0, 61 + is_oper: crate::mode::is_oper(client.modes), 64 62 is_ssl, 65 63 server: &ctx.name, 66 64 umodes: client.modes,
+2 -1
leveva/src/command/roleplay.rs
··· 32 32 //! the tail), where charybdis's `parv[3]` is a single token unless the client used a trailing. 33 33 34 34 use crate::command::*; 35 + #[cfg(test)] 35 36 use crate::UserMode; 36 37 37 38 /// The fixed pseudo-host every roleplay message is sourced from (charybdis-faithful). ··· 174 175 175 176 /// Whether the issuer holds an IRC-operator bit (`+o`/`+O`). 176 177 fn is_oper(client: &Registered) -> bool { 177 - client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0 178 + crate::mode::is_oper(client.modes) 178 179 } 179 180 180 181 /// The unified argument list — middle params followed by the trailing, if any — so multi-word text
+2 -1
leveva/src/command/sajoin.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `SAJOIN <nick> <channel>{,<channel>}` — leveva-native operator command: forcibly join a ··· 21 22 /// error replies come back to it. Joining a channel the user is already on is a silent 22 23 /// no-op. 23 24 pub(crate) fn sajoin(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 24 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 25 + if !crate::mode::is_oper(client.modes) { 25 26 return vec![no_privileges(ctx, &client.nick)]; 26 27 } 27 28 let target = msg
+2 -1
leveva/src/command/sanick.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `SANICK <nick> <newnick>` — leveva-native operator command: forcibly rename a **local** ··· 22 23 /// new nick and writes the `NICK` line. The oper receives no numeric (like `KILL`) — it 23 24 /// observes the change through any shared channel. 24 25 pub(crate) fn sanick(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 25 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 26 + if !crate::mode::is_oper(client.modes) { 26 27 return vec![no_privileges(ctx, &client.nick)]; 27 28 } 28 29 let target = msg
+2 -1
leveva/src/command/sapart.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// `SAPART <nick> <channel>{,<channel>} [:reason]` — leveva-native operator command: forcibly ··· 19 20 /// oper receives no numeric on a successful part (like `KILL`). The leave is a transparent 20 21 /// `PART` line, indistinguishable from the user's own part. 21 22 pub(crate) fn sapart(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 22 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 23 + if !crate::mode::is_oper(client.modes) { 23 24 return vec![no_privileges(ctx, &client.nick)]; 24 25 } 25 26 let target = msg
+1 -3
leveva/src/command/tagmsg.rs
··· 34 34 // recipients with `draft/oper-tag` (read once). A TAGMSG fan-out target always has 35 35 // `message-tags`, but `draft/oper` rides its own cap, so an oper-tag-only consumer would not 36 36 // receive a TAGMSG at all — `draft/oper` here reaches only clients with *both* caps. 37 - let sender_is_oper = client.modes 38 - & (crate::mode::UserMode::Oper.bit() | crate::mode::UserMode::LocalOp.bit()) 39 - != 0; 37 + let sender_is_oper = crate::mode::is_oper(client.modes); 40 38 // IRCv3 account-tag: a signed-in sender's account name is stamped as `@account` for 41 39 // recipients with `account-tag` (read once). Like `draft/oper`, it rides its own cap, but a 42 40 // TAGMSG fan-out target always has `message-tags`, so it reaches only dual-cap consumers.
+2 -1
leveva/src/command/testline.rs
··· 1 1 use crate::command::*; 2 2 use crate::kline::now_secs; 3 + #[cfg(test)] 3 4 use crate::UserMode; 4 5 5 6 /// What a `TESTLINE` mask resolves to once the optional `nick!` prefix is stripped. Pure (the fuzz ··· 68 69 return vec![need_more_params(ctx, &client.nick, "TESTLINE")]; 69 70 }; 70 71 71 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 72 + if !crate::mode::is_oper(client.modes) { 72 73 return vec![no_privileges(ctx, &client.nick)]; 73 74 } 74 75
+2 -1
leveva/src/command/testmask.rs
··· 1 1 use crate::command::*; 2 2 use crate::matching; 3 + #[cfg(test)] 3 4 use crate::UserMode; 4 5 5 6 /// A parsed `TESTMASK` argument: a `[nick!]user@host` glob split into its three components, with an ··· 72 73 return vec![need_more_params(ctx, &client.nick, "TESTMASK")]; 73 74 }; 74 75 75 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 76 + if !crate::mode::is_oper(client.modes) { 76 77 return vec![no_privileges(ctx, &client.nick)]; 77 78 } 78 79
+3 -6
leveva/src/command/trace.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 - 4 - /// The oper-status bits (`+o`/`+O`): a record carrying either is an operator and is 5 - /// always visible in a `TRACE` sweep, regardless of who is asking. 6 - const OPER_BITS: u32 = UserMode::Oper.bit() | UserMode::LocalOp.bit(); 7 4 8 5 /// `TRACE [<target>]` — report the connections this server can see. 9 6 /// ··· 60 57 let see_all = client.has_privilege(OperPrivilege::Trace); 61 58 let mut out = Vec::new(); 62 59 for rec in ctx.registry.records() { 63 - let is_oper = rec.modes & OPER_BITS != 0; 60 + let is_oper = crate::mode::is_oper(rec.modes); 64 61 let is_self = rec.uid == client.uid; 65 62 // An ordinary other client is hidden from a requester without ACL_TRACE. 66 63 if !is_self && !is_oper && !see_all { ··· 74 71 75 72 /// One `204`/`205` line for `rec` (operator → `204 Oper`, else `205 User`). 76 73 fn trace_line(ctx: &ServerContext, to: &str, rec: &crate::registry::ClientRecord) -> Message { 77 - let (num, label) = if rec.modes & OPER_BITS != 0 { 74 + let (num, label) = if crate::mode::is_oper(rec.modes) { 78 75 (Numeric::RplTraceoperator, "Oper") 79 76 } else { 80 77 (Numeric::RplTraceuser, "User")
+2 -1
leveva/src/command/userhost.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// The maximum number of nick tokens `USERHOST` examines, matching the oracle's ··· 54 55 55 56 /// `<nick>[*]=<sign><user>@<host>` for one registered person. 56 57 fn format_entry(rec: &crate::registry::ClientRecord) -> String { 57 - let oper = rec.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 58 + let oper = crate::mode::is_oper(rec.modes); 58 59 let sign = if rec.away.is_some() { '-' } else { '+' }; 59 60 format!( 60 61 "{}{}={}{}@{}",
+3 -2
leveva/src/command/userip.rs
··· 1 1 use crate::command::*; 2 + #[cfg(test)] 2 3 use crate::UserMode; 3 4 4 5 /// The maximum number of nick tokens `USERIP` examines, matching `USERHOST`'s `i = 5` cap ··· 39 40 } 40 41 41 42 // An operator may see every user's real IP; a non-oper only their own. 42 - let requester_is_oper = client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 43 + let requester_is_oper = crate::mode::is_oper(client.modes); 43 44 44 45 let entries: Vec<String> = tokens 45 46 .into_iter() ··· 61 62 /// `<nick>[*]=<sign><user>@<addr>` for one registered person. `addr` is the real connect IP 62 63 /// (`orighost`) when `show_ip`, else the visible (possibly cloaked) `host`. 63 64 fn format_entry(rec: &crate::registry::ClientRecord, show_ip: bool) -> String { 64 - let oper = rec.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0; 65 + let oper = crate::mode::is_oper(rec.modes); 65 66 let sign = if rec.away.is_some() { '-' } else { '+' }; 66 67 let addr = if show_ip { &rec.orighost } else { &rec.host }; 67 68 format!(
+1 -1
leveva/src/command/wallops.rs
··· 21 21 /// the broadcast is a side effect on recipients' mailboxes, like a channel `PRIVMSG`. 22 22 pub(crate) fn wallops(client: &Registered, msg: &Message, ctx: &ServerContext) -> Vec<Message> { 23 23 // Privilege gate first: only operators may wallops. 24 - if client.modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) == 0 { 24 + if !crate::mode::is_oper(client.modes) { 25 25 return vec![Message::builder(Numeric::ErrNoprivileges) 26 26 .prefix(&ctx.name) 27 27 .param(&client.nick)
+3 -7
leveva/src/command/who.rs
··· 1 1 use crate::command::*; 2 2 use crate::{matching, UserMode}; 3 3 4 - /// The user-mode bits that mark an operator (`+o` global or `+O` local) — used for the 5 - /// `*` flag in a WHO status and for the WHOX/`o` opers-only filter. 6 - fn oper_bits() -> u32 { 7 - UserMode::Oper.bit() | UserMode::LocalOp.bit() 8 - } 9 - 4 + /// Whether `rec` is an operator (`+o` global or `+O` local) — used for the `*` flag in a 5 + /// WHO status and for the WHOX/`o` opers-only filter. 10 6 fn is_oper(rec: &crate::registry::ClientRecord) -> bool { 11 - rec.modes & oper_bits() != 0 7 + crate::mode::is_oper(rec.modes) 12 8 } 13 9 14 10 /// Whether `rec` survives the optional `o` opers-only filter: always unless the filter is
+3 -7
leveva/src/command/whois.rs
··· 199 199 // +<modes>`. leveva-native (the IRCnet 2.11 oracle has no 379). User modes 200 200 // leak `+i`/oper/cloak state, so this is gated: only the target themselves 201 201 // or an operator may see it. Last extra-info line before the 317/318 tail. 202 - let requester_is_oper = client.modes 203 - & (crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit()) 204 - != 0; 202 + let requester_is_oper = crate::mode::is_oper(client.modes); 205 203 if client.uid == rec.uid || requester_is_oper { 206 204 replies.push( 207 205 Message::builder(Numeric::RplWhoismodes) ··· 229 227 .metadata() 230 228 .list(&crate::metadata::MetaTarget::User(rec.uid.clone())); 231 229 let ok = crate::control::live_oper_keys().unwrap_or_default(); 232 - let requester_oper = client.modes 233 - & (crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit()) 234 - != 0; 230 + let requester_oper = crate::mode::is_oper(client.modes); 235 231 replies.extend(whois_keyvalue_lines( 236 232 ctx, 237 233 &client.nick, ··· 303 299 pub fn whois_oper_line(modes: u32) -> Option<WhoisLine> { 304 300 if crate::mode::is_service(modes) { 305 301 Some(WhoisLine::Service) 306 - } else if modes & (crate::UserMode::Oper.bit() | crate::UserMode::LocalOp.bit()) != 0 { 302 + } else if crate::mode::is_oper(modes) { 307 303 Some(WhoisLine::Operator) 308 304 } else { 309 305 None
+9
leveva/src/mode.rs
··· 497 497 modes & UserMode::LocOps.bit() != 0 498 498 } 499 499 500 + /// Whether `modes` marks an IRC operator — the `+o` ([`UserMode::Oper`], global) **or** `+O` 501 + /// ([`UserMode::LocalOp`], local) bit. The single operator predicate behind every oper-gated 502 + /// command and oper-visibility check; a change to what counts as an operator happens here, 503 + /// nowhere else. 504 + #[inline] 505 + pub fn is_oper(modes: u32) -> bool { 506 + modes & (UserMode::Oper.bit() | UserMode::LocalOp.bit()) != 0 507 + } 508 + 500 509 impl core::fmt::Display for UserMode { 501 510 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 502 511 f.write_str(match self {