feat: wire traffic resistance, implement v2 CLI commands, add auth expiry detection
Server: - Wire traffic resistance decoy generator into main.rs startup behind --traffic-resistance flag + --decoy-interval-ms config (feature-gated) Client: - Implement v2 CLI one-shot commands: send, recv, dm, group create, group invite All previously printed "coming soon" — now fully functional with MLS state restoration, peer resolution, KeyPackage fetch, and MLS encryption pipeline SDK: - Add SdkError::SessionExpired variant + is_auth_expired() helper for detecting expired session tokens (RpcStatus::Unauthorized) - Add ClientEvent::AuthExpired for UI-layer session expiry notification
This commit is contained in:
@@ -179,6 +179,15 @@ struct Args {
|
||||
/// Storage/database operation timeout in seconds (default: 10).
|
||||
#[arg(long, env = "QPQ_STORAGE_TIMEOUT", default_value_t = config::DEFAULT_STORAGE_TIMEOUT_SECS)]
|
||||
storage_timeout: u64,
|
||||
|
||||
/// Enable traffic analysis resistance (decoy traffic + timing jitter).
|
||||
/// Requires --features traffic-resistance.
|
||||
#[arg(long, env = "QPQ_TRAFFIC_RESISTANCE", default_value_t = false)]
|
||||
traffic_resistance: bool,
|
||||
|
||||
/// Mean interval in milliseconds between decoy messages (default: 5000).
|
||||
#[arg(long, env = "QPQ_DECOY_INTERVAL_MS", default_value_t = 5000)]
|
||||
decoy_interval_ms: u64,
|
||||
}
|
||||
|
||||
// ── In-flight RPC guard ──────────────────────────────────────────────────────
|
||||
@@ -646,6 +655,40 @@ async fn main() -> anyhow::Result<()> {
|
||||
"effective timeouts and listeners"
|
||||
);
|
||||
|
||||
// ── Traffic resistance (decoy traffic generator) ──────────────────────────
|
||||
#[cfg(feature = "traffic-resistance")]
|
||||
let _decoy_handle = {
|
||||
if args.traffic_resistance {
|
||||
let shutdown_notify = Arc::new(tokio::sync::Notify::new());
|
||||
let delivery_svc = Arc::new(domain::delivery::DeliveryService {
|
||||
store: Arc::clone(&store),
|
||||
waiters: Arc::clone(&waiters),
|
||||
});
|
||||
let config = domain::traffic_resistance::TrafficResistanceConfig {
|
||||
decoy_interval_ms: args.decoy_interval_ms,
|
||||
..Default::default()
|
||||
};
|
||||
tracing::info!(
|
||||
decoy_interval_ms = config.decoy_interval_ms,
|
||||
jitter_max_ms = config.jitter_max_ms,
|
||||
padding_boundary = config.padding_boundary,
|
||||
"traffic resistance enabled — decoy generator started"
|
||||
);
|
||||
// Start with an empty recipient list; decoys will be a no-op until
|
||||
// recipients are populated. A future enhancement can dynamically
|
||||
// update the list from connected sessions.
|
||||
Some(domain::traffic_resistance::spawn_decoy_generator(
|
||||
delivery_svc,
|
||||
Vec::new(),
|
||||
b"decoy-channel".to_vec(),
|
||||
config,
|
||||
shutdown_notify,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
// In-flight RPC counter for graceful drain on shutdown.
|
||||
let in_flight: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user