From 064a730b42060964f9d6420fc480ff6b817b3ebc Mon Sep 17 00:00:00 2001 From: Siavash Sameni Date: Sat, 28 Mar 2026 09:13:23 +0400 Subject: [PATCH] =?UTF-8?q?v0.0.21:=20WZP=20integration=20groundwork=20?= =?UTF-8?q?=E2=80=94=20CallSignal=20+=20token=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WZP-FC-1: CallSignal WireMessage variant - CallSignalType enum: Offer, Answer, IceCandidate, Hangup, Reject, Ringing, Busy - Routed through existing E2E encrypted channels - Server dedup handles new variant - TUI shows "📞 Call signal: Offer" etc - CLI recv prints call signals WZP-FC-4: Token validation endpoint - POST /v1/auth/validate { "token": "..." } - Returns: { "valid": true, "fingerprint": "...", "alias": "..." } - WZP relay calls this to verify featherChat bearer tokens - Resolves alias alongside fingerprint These two unblock WZP integration tasks WZP-S-2 (accept FC tokens) and WZP-S-3 (signaling bridge mode). Co-Authored-By: Claude Opus 4.6 (1M context) --- warzone/Cargo.lock | 10 ++--- warzone/Cargo.toml | 2 +- warzone/crates/warzone-client/src/cli/recv.rs | 3 ++ warzone/crates/warzone-client/src/tui/app.rs | 16 +++++++ .../crates/warzone-protocol/src/message.rs | 30 +++++++++++++ .../crates/warzone-server/src/routes/auth.rs | 42 ++++++++++++++++++- .../warzone-server/src/routes/messages.rs | 1 + .../crates/warzone-server/src/routes/ws.rs | 1 + 8 files changed, 97 insertions(+), 8 deletions(-) diff --git a/warzone/Cargo.lock b/warzone/Cargo.lock index 70d1213..6dcac2e 100644 --- a/warzone/Cargo.lock +++ b/warzone/Cargo.lock @@ -2789,7 +2789,7 @@ dependencies = [ [[package]] name = "warzone-client" -version = "0.0.19" +version = "0.0.20" dependencies = [ "anyhow", "argon2", @@ -2822,7 +2822,7 @@ dependencies = [ [[package]] name = "warzone-mule" -version = "0.0.19" +version = "0.0.20" dependencies = [ "anyhow", "clap", @@ -2831,7 +2831,7 @@ dependencies = [ [[package]] name = "warzone-protocol" -version = "0.0.19" +version = "0.0.20" dependencies = [ "base64", "bincode", @@ -2856,7 +2856,7 @@ dependencies = [ [[package]] name = "warzone-server" -version = "0.0.19" +version = "0.0.20" dependencies = [ "anyhow", "axum", @@ -2883,7 +2883,7 @@ dependencies = [ [[package]] name = "warzone-wasm" -version = "0.0.19" +version = "0.0.20" dependencies = [ "base64", "bincode", diff --git a/warzone/Cargo.toml b/warzone/Cargo.toml index 143bef8..06442ad 100644 --- a/warzone/Cargo.toml +++ b/warzone/Cargo.toml @@ -9,7 +9,7 @@ members = [ ] [workspace.package] -version = "0.0.20" +version = "0.0.21" edition = "2021" license = "MIT" rust-version = "1.75" diff --git a/warzone/crates/warzone-client/src/cli/recv.rs b/warzone/crates/warzone-client/src/cli/recv.rs index 528cd6e..344f8a2 100644 --- a/warzone/crates/warzone-client/src/cli/recv.rs +++ b/warzone/crates/warzone-client/src/cli/recv.rs @@ -129,6 +129,9 @@ pub async fn run(server_url: &str, identity: &IdentityKeyPair) -> Result<()> { Ok(WireMessage::SenderKeyDistribution { sender_fingerprint, group_name, .. }) => { println!(" [sender key] received key from {} for #{}", sender_fingerprint, group_name); } + Ok(WireMessage::CallSignal { sender_fingerprint, signal_type, target, .. }) => { + println!(" [call] {:?} from {} → {}", signal_type, sender_fingerprint, target); + } Err(e) => { eprintln!(" failed to deserialize message: {}", e); } diff --git a/warzone/crates/warzone-client/src/tui/app.rs b/warzone/crates/warzone-client/src/tui/app.rs index 990e774..357875e 100644 --- a/warzone/crates/warzone-client/src/tui/app.rs +++ b/warzone/crates/warzone-client/src/tui/app.rs @@ -1542,6 +1542,22 @@ fn process_wire_message( message_id: None, }); } + WireMessage::CallSignal { + id: _, + sender_fingerprint, + signal_type, + payload: _, + target: _, + } => { + let type_str = format!("{:?}", signal_type); + messages.lock().unwrap().push(ChatLine { + sender: sender_fingerprint[..sender_fingerprint.len().min(12)].to_string(), + text: format!("📞 Call signal: {}", type_str), + is_system: false, + is_self: false, + message_id: None, + }); + } } } diff --git a/warzone/crates/warzone-protocol/src/message.rs b/warzone/crates/warzone-protocol/src/message.rs index 68b230f..7dddc6c 100644 --- a/warzone/crates/warzone-protocol/src/message.rs +++ b/warzone/crates/warzone-protocol/src/message.rs @@ -101,4 +101,34 @@ pub enum WireMessage { chain_key: [u8; 32], generation: u32, }, + /// Call signaling: SDP offers/answers, ICE candidates, call control. + /// Routed through featherChat's E2E encrypted channel for WarzonePhone integration. + CallSignal { + id: String, + sender_fingerprint: String, + signal_type: CallSignalType, + /// SDP offer/answer body, ICE candidate, or empty for hangup/reject. + payload: String, + /// Target peer (for 1:1) or group/room name (for group calls). + target: String, + }, +} + +/// Call signaling types for WarzonePhone integration. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum CallSignalType { + /// Initiate a call (contains SDP offer or WZP connection params). + Offer, + /// Accept a call (contains SDP answer or WZP connection params). + Answer, + /// ICE candidate for NAT traversal. + IceCandidate, + /// Hang up / end call. + Hangup, + /// Reject incoming call. + Reject, + /// Call is ringing on the other side. + Ringing, + /// Peer is busy. + Busy, } diff --git a/warzone/crates/warzone-server/src/routes/auth.rs b/warzone/crates/warzone-server/src/routes/auth.rs index ad44b2a..7fd20c5 100644 --- a/warzone/crates/warzone-server/src/routes/auth.rs +++ b/warzone/crates/warzone-server/src/routes/auth.rs @@ -32,6 +32,7 @@ pub fn routes() -> Router { Router::new() .route("/auth/challenge", post(create_challenge)) .route("/auth/verify", post(verify_challenge)) + .route("/auth/validate", post(validate_token_endpoint)) } fn now_ts() -> i64 { @@ -172,8 +173,6 @@ async fn verify_challenge( } /// Validate a bearer token. Returns the fingerprint if valid. -/// Used by protected endpoints (will be wired in when auth middleware is added). -#[allow(dead_code)] pub fn validate_token(db: &sled::Tree, token: &str) -> Option { let data = db.get(token.as_bytes()).ok()??; let val: serde_json::Value = serde_json::from_slice(&data).ok()?; @@ -184,3 +183,42 @@ pub fn validate_token(db: &sled::Tree, token: &str) -> Option { } val.get("fingerprint")?.as_str().map(String::from) } + +#[derive(Deserialize)] +struct ValidateRequest { + token: String, +} + +/// External token validation endpoint — used by WarzonePhone and other services +/// to verify that a bearer token is valid and get the associated fingerprint. +/// +/// POST /v1/auth/validate { "token": "..." } +/// Returns: { "valid": true, "fingerprint": "...", "expires_at": ... } +/// or: { "valid": false } +async fn validate_token_endpoint( + State(state): State, + Json(req): Json, +) -> Json { + match validate_token(&state.db.tokens, &req.token) { + Some(fingerprint) => { + // Also resolve alias if available + let alias = state.db.aliases.get(format!("fp:{}", fingerprint).as_bytes()) + .ok().flatten() + .map(|v| String::from_utf8_lossy(&v).to_string()); + + // Get Ethereum address if we have the bundle + let eth_address: Option = None; // Would need seed, which server doesn't have + + tracing::info!("Token validated for {}", fingerprint); + Json(serde_json::json!({ + "valid": true, + "fingerprint": fingerprint, + "alias": alias, + "eth_address": eth_address, + })) + } + None => { + Json(serde_json::json!({ "valid": false })) + } + } +} diff --git a/warzone/crates/warzone-server/src/routes/messages.rs b/warzone/crates/warzone-server/src/routes/messages.rs index 109fae1..f9b6d57 100644 --- a/warzone/crates/warzone-server/src/routes/messages.rs +++ b/warzone/crates/warzone-server/src/routes/messages.rs @@ -22,6 +22,7 @@ fn extract_message_id(data: &[u8]) -> Option { WireMessage::SenderKeyDistribution { sender_fingerprint, group_name, .. } => { Some(format!("skd:{}:{}", sender_fingerprint, group_name)) } + WireMessage::CallSignal { id, .. } => Some(id), } } else { None diff --git a/warzone/crates/warzone-server/src/routes/ws.rs b/warzone/crates/warzone-server/src/routes/ws.rs index fa2c0f0..f8d19f3 100644 --- a/warzone/crates/warzone-server/src/routes/ws.rs +++ b/warzone/crates/warzone-server/src/routes/ws.rs @@ -34,6 +34,7 @@ fn extract_message_id(data: &[u8]) -> Option { WireMessage::SenderKeyDistribution { sender_fingerprint, group_name, .. } => { Some(format!("skd:{}:{}", sender_fingerprint, group_name)) } + WireMessage::CallSignal { id, .. } => Some(id), } } else { None