feat(presence): pure friends presence protocol + auth gate (W7 P4 core)
The logic half of the friends-only idle listener, built as pure unit-tested
seams so the security-critical decisions are provable without live networking.
src/presence.rs:
- ControlMsg { Ping, Pong { room: Option<RoomPresence> } } — self-describing
tagged JSON; unknown tags rejected (forward-compat).
- should_answer(from, friends, mode): the authorization gate — answer pings
from FRIENDS ONLY and never while invisible. This whitelist is what keeps
the always-on-while-open endpoint from being a stranger-facing spam/DoS
surface; must be the authenticated remote_id, never payload data.
- PresenceMode { Invisible, Normal(default), Discoverable } + helpers; persisted
in AppConfig (backward-compat default = Normal = friends-only, no beacon).
- interpret_pong: defensive reply handling — sanitizes the peer-supplied room
name and only surfaces a joinable room if its ticket actually parses, else
downgrades to plain Online (no dead/hostile Join button). Never auto-joins.
Deferred to a 2-machine session (the I/O edges): binding the live control
endpoint, its accept loop, and the ping scheduler. +8 presence tests, 256 lib
tests green, clippy clean, release builds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -153,6 +153,10 @@ pub struct AppConfig {
|
||||
pub output_volume: f32,
|
||||
#[serde(default)]
|
||||
pub network_mode: NetworkMode,
|
||||
/// Presence posture for the friends idle listener (W7): invisible / normal /
|
||||
/// discoverable. Default `Normal` = answer friends only, no DNS beacon.
|
||||
#[serde(default)]
|
||||
pub presence_mode: crate::presence::PresenceMode,
|
||||
/// Route audio through PipeWire's echo-cancel module (AEC + noise suppression).
|
||||
/// Takes effect on the next room join. Off by default.
|
||||
#[serde(default)]
|
||||
@@ -249,6 +253,7 @@ impl Default for AppConfig {
|
||||
input_volume: 1.0,
|
||||
output_volume: 1.0,
|
||||
network_mode: NetworkMode::default(),
|
||||
presence_mode: crate::presence::PresenceMode::default(),
|
||||
echo_cancellation_enabled: false,
|
||||
notifications_enabled: true,
|
||||
participants_width: default_participants_width(),
|
||||
@@ -361,6 +366,8 @@ mod tests {
|
||||
let deserialized: AppConfig = serde_json::from_str(minimal_json).unwrap();
|
||||
|
||||
assert_eq!(deserialized.network_mode, NetworkMode::RelayNoDiscovery);
|
||||
// Configs predating the presence posture load as friends-only (no beacon).
|
||||
assert_eq!(deserialized.presence_mode, crate::presence::PresenceMode::Normal);
|
||||
assert!(!deserialized.echo_cancellation_enabled);
|
||||
assert!(deserialized.notifications_enabled);
|
||||
// Configs predating the volume sliders must load at unity gain.
|
||||
|
||||
Reference in New Issue
Block a user