diff --git a/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs b/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs index 9037c393ca..25fc87ba4b 100644 --- a/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs +++ b/aries/agents/rust/aries-vcx-agent/src/services/did_exchange.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use aries_vcx::{ + did_doc::schema::{service::typed::ServiceType, types::uri::Uri}, messages::{ msg_fields::protocols::{ did_exchange::{ @@ -25,7 +26,6 @@ use aries_vcx_core::wallet::{base_wallet::BaseWallet, indy::IndySdkWallet}; use did_peer::peer_did::{numalgos::numalgo2::Numalgo2, PeerDid}; use did_resolver_registry::ResolverRegistry; use did_resolver_sov::did_resolver::did_doc::schema::did_doc::DidDocument; -use url::Url; use super::connection::ServiceEndpoint; use crate::{ @@ -83,10 +83,17 @@ impl ServiceDidExchange { .thid; let ddo_their = requester.their_did_doc(); let ddo_our = requester.our_did_document(); - let encryption_envelope = - pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &request.into()).await?; + let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?; + let encryption_envelope = pairwise_encrypt( + ddo_our, + ddo_their, + self.wallet.as_ref(), + &request.into(), + service.id(), + ) + .await?; VcxHttpClient - .send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?) + .send_message(encryption_envelope.0, service.service_endpoint().clone()) .await?; self.did_exchange.insert(&request_id, requester.clone()) } @@ -127,10 +134,17 @@ impl ServiceDidExchange { .await?; let ddo_their = responder.their_did_doc(); let ddo_our = responder.our_did_document(); - let encryption_envelope = - pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &response.into()).await?; + let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?; + let encryption_envelope = pairwise_encrypt( + ddo_our, + ddo_their, + self.wallet.as_ref(), + &response.into(), + service.id(), + ) + .await?; VcxHttpClient - .send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?) + .send_message(encryption_envelope.0, service.service_endpoint().clone()) .await?; self.did_exchange.insert(&request_id, responder.clone()) } @@ -144,10 +158,17 @@ impl ServiceDidExchange { .await?; let ddo_their = requester.their_did_doc(); let ddo_our = requester.our_did_document(); - let encryption_envelope = - pairwise_encrypt(ddo_our, ddo_their, self.wallet.as_ref(), &complete.into()).await?; + let service = ddo_their.get_service_of_type(&ServiceType::DIDCommV1)?; + let encryption_envelope = pairwise_encrypt( + ddo_our, + ddo_their, + self.wallet.as_ref(), + &complete.into(), + service.id(), + ) + .await?; VcxHttpClient - .send_message(encryption_envelope.0, get_first_endpoint(ddo_their)?) + .send_message(encryption_envelope.0, service.service_endpoint().clone()) .await?; self.did_exchange.insert(&thread_id, requester.clone()) } @@ -187,25 +208,19 @@ impl ServiceDidExchange { } } -pub fn get_first_endpoint(did_document: &DidDocument) -> AgentResult { - let service = did_document.service().first().ok_or(AgentError::from_msg( - AgentErrorKind::InvalidState, - "No service found", - ))?; - Ok(service.service_endpoint().clone()) -} - pub async fn pairwise_encrypt( our_did_doc: &DidDocument, their_did_doc: &DidDocument, wallet: &impl BaseWallet, message: &AriesMessage, + their_service_id: &Uri, ) -> AgentResult { EncryptionEnvelope::create( wallet, serde_json::json!(message).to_string().as_bytes(), our_did_doc, their_did_doc, + their_service_id, ) .await .map_err(|err| { diff --git a/aries/aries_vcx/src/utils/didcomm_utils.rs b/aries/aries_vcx/src/utils/didcomm_utils.rs index a682ccea5c..b044966659 100644 --- a/aries/aries_vcx/src/utils/didcomm_utils.rs +++ b/aries/aries_vcx/src/utils/didcomm_utils.rs @@ -1,5 +1,5 @@ use did_doc::schema::{ - did_doc::DidDocument, service::service_key_kind::ServiceKeyKind, + did_doc::DidDocument, service::service_key_kind::ServiceKeyKind, types::uri::Uri, verification_method::VerificationMethodType, }; use public_key::Key; @@ -41,27 +41,18 @@ pub fn resolve_base58_key_agreement(did_document: &DidDocument) -> VcxResult VcxResult> { - let service = our_did_doc - .service() - .first() - .ok_or_else(|| { - AriesVcxError::from_msg( - AriesVcxErrorKind::InvalidState, - "No Service object found on our did document", - ) - })? - .clone(); +pub fn get_routing_keys(their_did_doc: &DidDocument, service_id: &Uri) -> VcxResult> { + let service = their_did_doc.get_service_by_id(service_id)?; match service.extra_field_routing_keys() { Ok(routing_keys) => { let mut naked_routing_keys = Vec::new(); for key in routing_keys.iter() { naked_routing_keys - .push(resolve_service_key_to_typed_key(key, our_did_doc)?.base58()); + .push(resolve_service_key_to_typed_key(key, their_did_doc)?.base58()); } Ok(naked_routing_keys) } diff --git a/aries/aries_vcx/src/utils/encryption_envelope.rs b/aries/aries_vcx/src/utils/encryption_envelope.rs index a1a4ef57ef..d2399e9fb5 100644 --- a/aries/aries_vcx/src/utils/encryption_envelope.rs +++ b/aries/aries_vcx/src/utils/encryption_envelope.rs @@ -1,6 +1,6 @@ use agency_client::testing::mocking::AgencyMockDecrypted; use aries_vcx_core::{global::settings::VERKEY, wallet::base_wallet::BaseWallet}; -use did_doc::schema::did_doc::DidDocument; +use did_doc::schema::{did_doc::DidDocument, types::uri::Uri}; use diddoc_legacy::aries::diddoc::AriesDidDoc; use messages::{ msg_fields::protocols::routing::{Forward, ForwardContent}, @@ -43,15 +43,28 @@ impl EncryptionEnvelope { Self::create_from_keys(wallet, data, sender_vk, recipient_key, routing_keys).await } + /// Create encrypted message based on key agreement keys of our did document, counterparties + /// did document and their specific service, identified by id, which must be part of their + /// did document + /// + /// # Arguments + /// + /// * `our_did_doc` - Our did_document, which the counterparty should already be in possession + /// of + /// * `their_did_doc` - The did document of the counterparty, the recipient of the encrypted + /// message + /// * `their_service_id` - Id of service where message will be sent. The counterparty did + /// document must contain Service object identified with such value. pub async fn create( wallet: &impl BaseWallet, data: &[u8], our_did_doc: &DidDocument, their_did_doc: &DidDocument, + their_service_id: &Uri, ) -> VcxResult { let sender_vk = resolve_base58_key_agreement(our_did_doc)?; let recipient_key = resolve_base58_key_agreement(their_did_doc)?; - let routing_keys = get_routing_keys(their_did_doc)?; + let routing_keys = get_routing_keys(their_did_doc, their_service_id)?; EncryptionEnvelope::create_from_keys( wallet, diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 29805dd306..121931c65b 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -18,7 +18,9 @@ use aries_vcx::{ }; use aries_vcx_core::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; use did_doc::schema::{ - did_doc::DidDocument, service::typed::didcommv1::ServiceDidCommV1, types::uri::Uri, + did_doc::DidDocument, + service::typed::{didcommv1::ServiceDidCommV1, ServiceType}, + types::uri::Uri, }; use did_parser::Did; use did_peer::{ @@ -179,11 +181,15 @@ async fn did_exchange_test() -> Result<(), Box> { ); let data = "Hello world"; + let service = requester + .their_did_doc() + .get_service_of_type(&ServiceType::DIDCommV1)?; let m = EncryptionEnvelope::create( &agent_invitee.wallet, data.as_bytes(), requester.our_did_doc(), requester.their_did_doc(), + service.id(), ) .await?; diff --git a/aries/misc/shared/src/http_client.rs b/aries/misc/shared/src/http_client.rs index 855ea1fb62..8f7355e6b0 100644 --- a/aries/misc/shared/src/http_client.rs +++ b/aries/misc/shared/src/http_client.rs @@ -21,6 +21,7 @@ lazy_static! { }; } +// todo: take Url by reference pub async fn post_message(body_content: Vec, url: Url) -> HttpResult> { debug!("post_message >> http client sending request POST {}", &url); diff --git a/did_core/did_doc/src/schema/service/mod.rs b/did_core/did_doc/src/schema/service/mod.rs index 5a5e4c51ca..3af547a661 100644 --- a/did_core/did_doc/src/schema/service/mod.rs +++ b/did_core/did_doc/src/schema/service/mod.rs @@ -47,6 +47,13 @@ impl Service { &self.id } + pub fn contains_service_type(&self, tested_service_type: &ServiceType) -> bool { + match &self.service_type { + OneOrList::One(service_type) => tested_service_type == service_type, + OneOrList::List(service_types) => service_types.contains(tested_service_type), + } + } + pub fn service_type(&self) -> &OneOrList { &self.service_type } diff --git a/did_core/did_doc/src/schema/utils/mod.rs b/did_core/did_doc/src/schema/utils/mod.rs index 930dcc1d1f..c6c5acfccf 100644 --- a/did_core/did_doc/src/schema/utils/mod.rs +++ b/did_core/did_doc/src/schema/utils/mod.rs @@ -6,6 +6,8 @@ use crate::{ error::DidDocumentBuilderError, schema::{ did_doc::DidDocument, + service::{typed::ServiceType, Service}, + types::uri::Uri, verification_method::{VerificationMethod, VerificationMethodKind, VerificationMethodType}, }, }; @@ -36,7 +38,7 @@ impl Display for OneOrList { } impl DidDocument { - pub fn find_key_agreement_of_type( + pub fn get_key_agreement_of_type( &self, key_types: &[VerificationMethodType], ) -> Result { @@ -65,6 +67,33 @@ impl DidDocument { "No supported key_agreement keys have been found".to_string(), )) } + + pub fn get_service_of_type( + &self, + service_type: &ServiceType, + ) -> Result { + for service in self.service() { + if service.contains_service_type(service_type) { + return Ok(service.clone()); + } + } + Err(DidDocumentBuilderError::CustomError(format!( + "No service of type {}", + service_type + ))) + } + + pub fn get_service_by_id(&self, id: &Uri) -> Result { + for service in self.service() { + if service.id() == id { + return Ok(service.clone()); + } + } + Err(DidDocumentBuilderError::CustomError(format!( + "No service found by id {}", + id + ))) + } } #[cfg(test)] @@ -106,7 +135,7 @@ mod tests { VerificationMethodType::Ed25519VerificationKey2020, VerificationMethodType::X25519KeyAgreementKey2020, ]; - let key = did_document.find_key_agreement_of_type(methods).unwrap(); + let key = did_document.get_key_agreement_of_type(methods).unwrap(); assert_eq!(key.id().to_string(), "#bar") } @@ -115,7 +144,7 @@ mod tests { let did_document: DidDocument = serde_json::from_str(DID_DOC).unwrap(); let methods = &vec![VerificationMethodType::Bls12381G1Key2020]; let err = did_document - .find_key_agreement_of_type(methods) + .get_key_agreement_of_type(methods) .expect_err("expected error"); assert!(err .to_string()