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.

ircd.rs / docs / superpowers / plans / 2026-06-16-p11-slice221-whois-keyvalue-760.md
2.8 kB

P11 slice 221 — 760 RPL_WHOISKEYVALUE (metadata in WHOIS)#

Goal#

Close a documented IRCv3 draft/metadata-2 deferral: a WHOIS on a user with metadata set now exposes that metadata as 760 RPL_WHOISKEYVALUE lines, to a requester that negotiated the draft/metadata-2 capability. Format (the metadata spec, §RPL_WHOISKEYVALUE):

:<server> 760 <requester> <target> <key> <visibility> :<value>

This was listed verbatim as out-of-scope in command/metadata.rs ("760 RPL_WHOISKEYVALUE … out of scope here"). leveva-native (no C oracle — IRCnet 2.11 has no metadata); modelled on the draft/metadata-2 spec and the existing 761 RPL_KEYVALUE (METADATA … GET) which shares the identical param shape.

Scope / behavior#

  • Gated on the requester's cap (client.caps.metadata), per the spec ("when a user with the capability enabled runs WHOIS"). A requester without the cap sees no 760 (the inverse).
  • One 760 per set key, in the deterministic MetadataStore::list (sorted) key order.
  • Visibility is always * — leveva has no privileged-key / restricted-visibility system (that whole subsystem stays out of scope; the only remaining metadata-2 deferral).
  • Fires for remote targets too: metadata is keyed by stable Uid and is network-wide (burst slice 189 + live propagate slice 177), so a remote user's keys are in our store.
  • Placed among the WHOIS extra-info lines, before the 317/318 tail (after 276/379).

Mechanism#

  1. numeric.rs: add RplWhoiskeyvalue = 760 (name map + try_from).
  2. command/whois.rs: pure builder whois_keyvalue_lines(ctx, requester, target, &[(k,v)]) -> Vec<Message> — one 760 line per pair, visibility *, value as trailing. The fuzz seam.
  3. command/whois.rs handler: in the per-target block, if client.caps.metadata fetch ctx.registry.metadata().list(&MetaTarget::User(rec.uid)) and replies.extend(...) the builder output, just before the 317 idle line.

Tests (TDD)#

  • whois.rs unit: cap-enabled WHOIS shows 760 for each key (sorted, * visibility, before 317); inverses — no cap → no 760; cap but no keys → no 760; set→remove round-trip drops the 760; a remote target still gets 760. Pure-builder shape + empty.
  • whois.rs inline proptest: the builder is total over arbitrary keys/values, one 760 per pair, params <req> <tgt> <key> * + value trailing.
  • tests/golden_whois_metadata.rs (boot-golden): alice sets two keys; a cap-enabled bob WHOIS sees both 760 lines sorted before 318; a non-cap carol sees none (the inverse), end-to-end through the real binary.

Gate#

cargo test -p leveva green; cargo clippy -p leveva --tests clean; cargo build --workspace 0 warnings.