From 08bea95672ef03600fab60747d696cb2b083b921 Mon Sep 17 00:00:00 2001 From: George Mulhearn <57472912+gmulhearn@users.noreply.github.com> Date: Tue, 16 Jul 2024 01:48:56 +1000 Subject: [PATCH] Handle trust pings in the AATH backchannel (#1254) * handle trust ping Signed-off-by: George Mulhearn * clipppy Signed-off-by: George Mulhearn --------- Signed-off-by: George Mulhearn Co-authored-by: George Mulhearn --- .../src/controllers/didcomm.rs | 82 +++++++------------ .../src/handlers/connection.rs | 66 +++++++++++++-- .../src/protocols/connection/inviter/mod.rs | 9 +- 3 files changed, 89 insertions(+), 68 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index ef8637f928..8354bb7a77 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -12,6 +12,7 @@ use aries_vcx_agent::aries_vcx::{ }, notification::Notification, present_proof::{v1::PresentProofV1, PresentProof}, + trust_ping::TrustPing, }, AriesMessage, }, @@ -75,14 +76,10 @@ impl HarnessAgent { async fn handle_issuance_msg( &self, msg: CredentialIssuance, - connection_ids: Vec, - sender_vk: &str, + connection_id: &str, ) -> HarnessResult<()> { match msg { - CredentialIssuance::V1(msg) => { - self.handle_issuance_msg_v1(msg, connection_ids, sender_vk) - .await - } + CredentialIssuance::V1(msg) => self.handle_issuance_msg_v1(msg, connection_id).await, CredentialIssuance::V2(_) => { unimplemented!("V2 issuance is not implemented for aries-vcx aath") } @@ -92,35 +89,19 @@ impl HarnessAgent { async fn handle_issuance_msg_v1( &self, msg: CredentialIssuanceV1, - connection_ids: Vec, - sender_vk: &str, + connection_id: &str, ) -> HarnessResult<()> { - let connection_id = connection_ids.last(); match msg { CredentialIssuanceV1::OfferCredential(offer) => { - if connection_ids.len() == 1 { - self.aries_agent - .holder() - .create_from_offer(connection_id.unwrap(), offer.clone())?; - } else { - return Err(HarnessError::from_msg( - HarnessErrorType::InvalidState, - &format!("Found multiple or no connections by verkey {}", sender_vk), - )); - } + self.aries_agent + .holder() + .create_from_offer(connection_id, offer.clone())?; } CredentialIssuanceV1::ProposeCredential(proposal) => { - if connection_ids.len() == 1 { - self.aries_agent - .issuer() - .accept_proposal(connection_id.unwrap(), &proposal) - .await?; - } else { - return Err(HarnessError::from_msg( - HarnessErrorType::InvalidState, - &format!("Found multiple or no connections by verkey {}", sender_vk), - )); - } + self.aries_agent + .issuer() + .accept_proposal(connection_id, &proposal) + .await?; } CredentialIssuanceV1::RequestCredential(request) => { let thread_id = request @@ -149,14 +130,10 @@ impl HarnessAgent { async fn handle_presentation_msg( &self, msg: PresentProof, - connection_ids: Vec, - sender_vk: &str, + connection_id: &str, ) -> HarnessResult<()> { match msg { - PresentProof::V1(msg) => { - self.handle_presentation_msg_v1(msg, connection_ids, sender_vk) - .await - } + PresentProof::V1(msg) => self.handle_presentation_msg_v1(msg, connection_id).await, PresentProof::V2(_) => { unimplemented!("V2 issuance is not implemented for aries-vcx aath") } @@ -166,22 +143,13 @@ impl HarnessAgent { async fn handle_presentation_msg_v1( &self, msg: PresentProofV1, - connection_ids: Vec, - sender_vk: &str, + connection_id: &str, ) -> HarnessResult<()> { - let connection_id = connection_ids.last(); match msg { PresentProofV1::RequestPresentation(request) => { - if connection_ids.len() == 1 { - self.aries_agent - .prover() - .create_from_request(connection_id.unwrap(), request)?; - } else { - return Err(HarnessError::from_msg( - HarnessErrorType::InvalidState, - &format!("Found multiple or no connections by verkey {}", sender_vk), - )); - } + self.aries_agent + .prover() + .create_from_request(connection_id, request)?; } PresentProofV1::Presentation(presentation) => { let thread_id = presentation.decorators.thread.thid.clone(); @@ -255,7 +223,6 @@ impl HarnessAgent { ) })?; info!("Received message: {}", message); - let connection_ids = self.aries_agent.connections().get_by_their_vk(&sender_vk)?; match message { AriesMessage::Notification(msg) => { match msg { @@ -272,15 +239,22 @@ impl HarnessAgent { } } } + AriesMessage::TrustPing(TrustPing::Ping(msg)) => { + let connection_id = self.aries_agent.connections().get_by_sender_vk(sender_vk)?; + self.aries_agent + .connections() + .process_trust_ping(msg, &connection_id) + .await? + } AriesMessage::Connection(msg) => self.handle_connection_msg(msg).await?, AriesMessage::CredentialIssuance(msg) => { - self.handle_issuance_msg(msg, connection_ids, &sender_vk) - .await? + let connection_id = self.aries_agent.connections().get_by_sender_vk(sender_vk)?; + self.handle_issuance_msg(msg, &connection_id).await? } AriesMessage::DidExchange(msg) => self.handle_did_exchange_msg(msg).await?, AriesMessage::PresentProof(msg) => { - self.handle_presentation_msg(msg, connection_ids, &sender_vk) - .await? + let connection_id = self.aries_agent.connections().get_by_sender_vk(sender_vk)?; + self.handle_presentation_msg(msg, &connection_id).await? } m => { warn!("Received message of unexpected type: {}", m); diff --git a/aries/agents/aries-vcx-agent/src/handlers/connection.rs b/aries/agents/aries-vcx-agent/src/handlers/connection.rs index 60322f160c..ca667bb886 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/connection.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/connection.rs @@ -6,11 +6,16 @@ use aries_vcx::{ msg_fields::protocols::{ connection::{request::Request, response::Response}, notification::ack::Ack, + trust_ping::ping::Ping, }, AriesMessage, }, - protocols::connection::{ - pairwise_info::PairwiseInfo, Connection, GenericConnection, State, ThinState, + protocols::{ + connection::{ + inviter::states::completed::Completed, pairwise_info::PairwiseInfo, Connection, + GenericConnection, State, ThinState, + }, + trustping::build_ping_response, }, }; use aries_vcx_ledger::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; @@ -179,6 +184,42 @@ impl ServiceConnections { Ok(()) } + /// Process a trust ping and send a pong. Also bump the connection state (ack) if needed. + pub async fn process_trust_ping(&self, ping: Ping, connection_id: &str) -> AgentResult<()> { + let generic_inviter = self.connections.get(connection_id)?; + + let inviter: Connection<_, Completed> = match generic_inviter.state() { + ThinState::Inviter(State::Requested) => { + // bump state. requested -> complete + let inviter: Connection<_, _> = generic_inviter.try_into()?; + inviter.acknowledge_connection(&ping.clone().into())? + } + ThinState::Inviter(State::Completed) => generic_inviter.try_into()?, + s => { + return Err(AgentError::from_msg( + AgentErrorKind::GenericAriesVcxError, + &format!( + "Connection with handle {} cannot process a trust ping; State: {:?}", + connection_id, s + ), + )) + } + }; + + // send pong if desired + if ping.content.response_requested { + let response = build_ping_response(&ping); + inviter + .send_message(self.wallet.as_ref(), &response.into(), &VcxHttpClient) + .await?; + } + + // update state + self.connections.insert(connection_id, inviter.into())?; + + Ok(()) + } + pub fn get_state(&self, thread_id: &str) -> AgentResult { Ok(self.connections.get(thread_id)?.state()) } @@ -187,16 +228,29 @@ impl ServiceConnections { self.connections.get(thread_id) } - pub fn get_by_their_vk(&self, their_vk: &str) -> AgentResult> { - let their_vk = their_vk.to_string(); + pub fn get_by_sender_vk(&self, sender_vk: String) -> AgentResult { let f = |(id, m): (&String, &Mutex)| -> Option { let connection = m.lock().unwrap(); match connection.remote_vk() { - Ok(remote_vk) if remote_vk == their_vk => Some(id.to_string()), + Ok(remote_vk) if remote_vk == sender_vk => Some(id.to_string()), _ => None, } }; - self.connections.find_by(f) + let conns = self.connections.find_by(f)?; + + if conns.len() > 1 { + return Err(AgentError::from_msg( + AgentErrorKind::InvalidState, + &format!( + "Found multiple connections by sender's verkey {}", + sender_vk + ), + )); + } + conns.into_iter().next().ok_or(AgentError::from_msg( + AgentErrorKind::InvalidState, + &format!("Found no connections by sender's verkey {}", sender_vk), + )) } pub fn exists_by_id(&self, thread_id: &str) -> bool { diff --git a/aries/aries_vcx/src/protocols/connection/inviter/mod.rs b/aries/aries_vcx/src/protocols/connection/inviter/mod.rs index f8ba562ea4..9ddd1bdf17 100644 --- a/aries/aries_vcx/src/protocols/connection/inviter/mod.rs +++ b/aries/aries_vcx/src/protocols/connection/inviter/mod.rs @@ -24,7 +24,6 @@ use crate::{ common::signing::sign_connection_response, errors::error::VcxResult, handlers::util::{verify_thread_id, AnyInvitation}, - protocols::connection::trait_bounds::ThreadId, }; pub type InviterConnection = Connection; @@ -235,16 +234,10 @@ impl InviterConnection { /// Acknowledges an invitee's connection by processing their first message /// and transitions to [`InviterConnection`]. - /// - /// # Errors - /// - /// Will error out if the message's thread ID does not match - /// the ID of the thread context used in this connection. pub fn acknowledge_connection( self, - msg: &AriesMessage, + _msg: &AriesMessage, ) -> VcxResult> { - verify_thread_id(self.state.thread_id(), msg)?; let state = Completed::new( self.state.did_doc, self.state.signed_response.decorators.thread.thid,