From edf4718d5d3b6e154347a709fb9a7bbbf631440c Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 18 Jun 2024 12:22:23 +1000 Subject: [PATCH 01/32] move existing into v1_0 section Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 13 ++- .../src/controllers/didcomm.rs | 10 +-- .../src/handlers/did_exchange.rs | 2 +- aries/aries_vcx/src/handlers/util.rs | 14 ++-- .../did_exchange/state_machine/generic/mod.rs | 2 +- .../did_exchange/state_machine/helpers.rs | 2 +- .../did_exchange/state_machine/mod.rs | 2 +- .../state_machine/requester/helpers.rs | 2 +- .../requester/request_sent/mod.rs | 2 +- .../responder/response_sent/mod.rs | 2 +- aries/messages/src/lib.rs | 22 +++-- .../msg_fields/protocols/did_exchange/mod.rs | 83 +------------------ .../did_exchange/{ => v1_0}/complete.rs | 0 .../protocols/did_exchange/v1_0/mod.rs | 78 +++++++++++++++++ .../did_exchange/{ => v1_0}/problem_report.rs | 0 .../did_exchange/{ => v1_0}/request.rs | 2 +- .../did_exchange/{ => v1_0}/response.rs | 0 .../protocols/did_exchange/v1_1/mod.rs | 77 +++++++++++++++++ .../src/msg_types/protocols/did_exchange.rs | 11 +++ 19 files changed, 218 insertions(+), 106 deletions(-) rename aries/messages/src/msg_fields/protocols/did_exchange/{ => v1_0}/complete.rs (100%) create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs rename aries/messages/src/msg_fields/protocols/did_exchange/{ => v1_0}/problem_report.rs (100%) rename aries/messages/src/msg_fields/protocols/did_exchange/{ => v1_0}/request.rs (97%) rename aries/messages/src/msg_fields/protocols/did_exchange/{ => v1_0}/response.rs (100%) create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index 2eef94b880..fb06b7630f 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -4,7 +4,10 @@ use actix_web::{get, post, web, Responder}; use aries_vcx_agent::aries_vcx::{ did_parser_nom::Did, messages::{ - msg_fields::protocols::did_exchange::{request::Request, DidExchange}, + msg_fields::protocols::did_exchange::{ + v1_0::{request::Request, DidExchangeV1_0}, + DidExchange, + }, AriesMessage, }, protocols::did_exchange::state_machine::requester::helpers::invitation_get_first_did_service, @@ -98,7 +101,9 @@ impl HarnessAgent { })? .clone() }; - if let AriesMessage::DidExchange(DidExchange::Request(ref request)) = request { + if let AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(ref request))) = + request + { let thid = request.decorators.thread.clone().unwrap().thid; Ok(json!({ "connection_id": thid }).to_string()) } else { @@ -139,7 +144,9 @@ impl HarnessAgent { ) })? }; - if let AriesMessage::DidExchange(DidExchange::Request(request)) = request { + if let AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) = + request + { let opt_invitation = match request.decorators.thread.clone().unwrap().pthid { None => None, Some(pthid) => { diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index 8fc0b2f6e3..7878afc8d1 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -6,7 +6,7 @@ use aries_vcx_agent::aries_vcx::{ msg_fields::protocols::{ connection::Connection, cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, - did_exchange::DidExchange, + did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, notification::Notification, present_proof::{v1::PresentProofV1, PresentProof}, }, @@ -197,10 +197,10 @@ impl HarnessAgent { async fn handle_did_exchange_msg(&self, msg: DidExchange) -> HarnessResult<()> { match msg { - DidExchange::Request(request) => { + DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { self.queue_didexchange_request(request)?; } - DidExchange::Response(response) => { + DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { let res = self .aries_agent .did_exchange() @@ -210,12 +210,12 @@ impl HarnessAgent { error!("Error sending complete: {:?}", err); }; } - DidExchange::Complete(complete) => { + DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { self.aries_agent .did_exchange() .handle_msg_complete(complete)?; } - DidExchange::ProblemReport(problem_report) => { + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { self.aries_agent .did_exchange() .receive_problem_report(problem_report)?; diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index ea0edc7455..fd388f141a 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -5,7 +5,7 @@ use aries_vcx::{ did_parser_nom::Did, messages::{ msg_fields::protocols::{ - did_exchange::{ + did_exchange::v1_0::{ complete::Complete, problem_report::ProblemReport, request::Request, response::Response, }, diff --git a/aries/aries_vcx/src/handlers/util.rs b/aries/aries_vcx/src/handlers/util.rs index b2e0c7ce33..0036797e70 100644 --- a/aries/aries_vcx/src/handlers/util.rs +++ b/aries/aries_vcx/src/handlers/util.rs @@ -4,7 +4,7 @@ use messages::{ connection::{invitation::Invitation, Connection}, coordinate_mediation::CoordinateMediation, cred_issuance::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance}, - did_exchange::DidExchange, + did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, discover_features::DiscoverFeatures, notification::Notification, out_of_band::{invitation::Invitation as OobInvitation, OutOfBand}, @@ -241,12 +241,16 @@ pub fn verify_thread_id(thread_id: &str, message: &AriesMessage) -> VcxResult<() AriesMessage::CoordinateMediation(CoordinateMediation::Keylist(msg)) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::Request(msg)) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(msg))) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::Response(msg)) => matches_thread_id!(msg, thread_id), - AriesMessage::DidExchange(DidExchange::Complete(msg)) => matches_thread_id!(msg, thread_id), - AriesMessage::DidExchange(DidExchange::ProblemReport(msg)) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Response(msg))) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Complete(msg))) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::ProblemReport(msg))) => { matches_thread_id!(msg, thread_id) } }; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index ccc6178a09..00608601ad 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -5,7 +5,7 @@ use did_doc::schema::did_doc::DidDocument; use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::{ +use messages::msg_fields::protocols::did_exchange::v1_0::{ complete::Complete, problem_report::ProblemReport, request::Request, response::Response, }; use public_key::Key; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 27fc40dce5..a7e0ff7474 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -24,7 +24,7 @@ use messages::{ thread::Thread, timing::Timing, }, - msg_fields::protocols::did_exchange::response::{ + msg_fields::protocols::did_exchange::v1_0::response::{ Response, ResponseContent, ResponseDecorators, }, }; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs index 896e0843be..f443eef4ff 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs @@ -10,7 +10,7 @@ use chrono::Utc; use did_doc::schema::did_doc::DidDocument; use messages::{ decorators::{thread::Thread, timing::Timing}, - msg_fields::protocols::did_exchange::problem_report::{ + msg_fields::protocols::did_exchange::v1_0::problem_report::{ ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, }, }; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index e658130832..067efac0a1 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -6,7 +6,7 @@ use messages::{ timing::Timing, }, msg_fields::protocols::{ - did_exchange::{ + did_exchange::v1_0::{ complete::{Complete, CompleteDecorators}, request::{Request, RequestContent, RequestDecorators}, }, diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index fd04b83830..3cc24c6406 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -4,7 +4,7 @@ use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver::traits::resolvable::resolution_output::DidResolutionOutput; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::{ +use messages::msg_fields::protocols::did_exchange::v1_0::{ complete::Complete as CompleteMessage, request::Request, response::Response, }; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 5b1c8afa31..eed2f56a49 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -4,7 +4,7 @@ use aries_vcx_wallet::wallet::base_wallet::BaseWallet; use did_doc::schema::did_doc::DidDocument; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::{ +use messages::msg_fields::protocols::did_exchange::v1_0::{ complete::Complete, request::Request, response::Response, }; use public_key::Key; diff --git a/aries/messages/src/lib.rs b/aries/messages/src/lib.rs index 89c1eb8e74..5e9367dbdb 100644 --- a/aries/messages/src/lib.rs +++ b/aries/messages/src/lib.rs @@ -17,13 +17,17 @@ use display_as_json::Display; use misc::utils; use msg_fields::protocols::{ cred_issuance::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance}, - did_exchange::DidExchange, + did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, pickup::Pickup, present_proof::{v2::PresentProofV2, PresentProof}, }; use msg_types::{ - cred_issuance::CredentialIssuanceType, present_proof::PresentProofType, - report_problem::ReportProblemTypeV1_0, routing::RoutingTypeV1_0, MsgWithType, + cred_issuance::CredentialIssuanceType, + present_proof::PresentProofType, + protocols::did_exchange::{DidExchangeType, DidExchangeTypeV1}, + report_problem::ReportProblemTypeV1_0, + routing::RoutingTypeV1_0, + MsgWithType, }; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; @@ -188,8 +192,14 @@ impl DelayedSerde for AriesMessage { CoordinateMediation::delayed_deserialize((msg_type, kind_str), deserializer) .map(From::from) } - Protocol::DidExchangeType(msg_type) => { - DidExchange::delayed_deserialize((msg_type, kind_str), deserializer).map(From::from) + Protocol::DidExchangeType(DidExchangeType::V1(DidExchangeTypeV1::V1_0(msg_type))) => { + DidExchangeV1_0::delayed_deserialize((msg_type, kind_str), deserializer) + .map(|x| AriesMessage::from(DidExchange::V1_0(x))) + } + Protocol::DidExchangeType(DidExchangeType::V1(DidExchangeTypeV1::V1_1(_msg_type))) => { + unimplemented!() + // DidExchange::delayed_deserialize((msg_type, kind_str), + // deserializer).map(From::from) } } } @@ -214,7 +224,7 @@ impl DelayedSerde for AriesMessage { Self::Notification(v) => v.delayed_serialize(serializer), Self::Pickup(v) => v.delayed_serialize(serializer), Self::CoordinateMediation(v) => v.delayed_serialize(serializer), - Self::DidExchange(v) => v.delayed_serialize(serializer), + Self::DidExchange(DidExchange::V1_0(v)) => v.delayed_serialize(serializer), } } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs index c7e676f06d..2092e9f03d 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs @@ -1,85 +1,10 @@ -// TODO: Why are not msg fields and types grouped by protocol??? -pub mod complete; -// TODO: Duplicates connection problem report, deduplicate -pub mod problem_report; -pub mod request; -pub mod response; - use derive_more::From; -use serde::{de::Error, Deserialize, Serialize}; -use shared::misc::serde_ignored::SerdeIgnored as NoContent; +use v1_0::DidExchangeV1_0; -use self::{ - complete::{Complete, CompleteDecorators}, - problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, - request::{Request, RequestContent, RequestDecorators}, - response::{Response, ResponseContent, ResponseDecorators}, -}; -use crate::{ - misc::utils::{into_msg_with_type, transit_to_aries_msg}, - msg_fields::traits::DelayedSerde, - msg_types::{ - protocols::did_exchange::{ - DidExchangeType as DidExchangeKind, DidExchangeTypeV1, DidExchangeTypeV1_0, - }, - MsgWithType, - }, -}; +pub mod v1_0; +pub mod v1_1; #[derive(Clone, Debug, From, PartialEq)] pub enum DidExchange { - Request(Request), - Response(Response), - ProblemReport(ProblemReport), - Complete(Complete), + V1_0(DidExchangeV1_0), } - -impl DelayedSerde for DidExchange { - type MsgType<'a> = (DidExchangeKind, &'a str); - - fn delayed_deserialize<'de, D>( - msg_type: Self::MsgType<'de>, - deserializer: D, - ) -> Result - where - D: serde::Deserializer<'de>, - { - let (protocol, kind_str) = msg_type; - - let kind = match protocol { - DidExchangeKind::V1(DidExchangeTypeV1::V1_0(kind)) => kind.kind_from_str(kind_str), - }; - - match kind.map_err(D::Error::custom)? { - DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), - DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), - DidExchangeTypeV1_0::ProblemReport => { - ProblemReport::deserialize(deserializer).map(From::from) - } - DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), - } - } - - fn delayed_serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - match self { - Self::Request(v) => MsgWithType::from(v).serialize(serializer), - Self::Response(v) => MsgWithType::from(v).serialize(serializer), - Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), - Self::Complete(v) => MsgWithType::from(v).serialize(serializer), - } - } -} - -// TODO: Seems to be required only for tests? -transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchange); -transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchange); -transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchange); -transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchange); - -into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); -into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); -into_msg_with_type!(ProblemReport, DidExchangeTypeV1_0, ProblemReport); -into_msg_with_type!(Complete, DidExchangeTypeV1_0, Complete); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs similarity index 100% rename from aries/messages/src/msg_fields/protocols/did_exchange/complete.rs rename to aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs new file mode 100644 index 0000000000..140208b88b --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -0,0 +1,78 @@ +// TODO: Why are not msg fields and types grouped by protocol??? +pub mod complete; +// TODO: Duplicates connection problem report, deduplicate +pub mod problem_report; +pub mod request; +pub mod response; + +use derive_more::From; +use serde::{de::Error, Deserialize, Serialize}; +use shared::misc::serde_ignored::SerdeIgnored as NoContent; + +use self::{ + complete::{Complete, CompleteDecorators}, + problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, + request::{Request, RequestContent, RequestDecorators}, + response::{Response, ResponseContent, ResponseDecorators}, +}; +use super::DidExchange; +use crate::{ + misc::utils::{into_msg_with_type, transit_to_aries_msg}, + msg_fields::traits::DelayedSerde, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType, MsgWithType}, +}; + +#[derive(Clone, Debug, From, PartialEq)] +pub enum DidExchangeV1_0 { + Request(Request), + Response(Response), + ProblemReport(ProblemReport), + Complete(Complete), +} + +impl DelayedSerde for DidExchangeV1_0 { + type MsgType<'a> = (MsgKindType, &'a str); + + fn delayed_deserialize<'de, D>( + msg_type: Self::MsgType<'de>, + deserializer: D, + ) -> Result + where + D: serde::Deserializer<'de>, + { + let (protocol, kind_str) = msg_type; + let kind = protocol.kind_from_str(kind_str); + + match kind.map_err(D::Error::custom)? { + DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_0::ProblemReport => { + ProblemReport::deserialize(deserializer).map(From::from) + } + DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), + } + } + + fn delayed_serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Request(v) => MsgWithType::from(v).serialize(serializer), + Self::Response(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), + Self::Complete(v) => MsgWithType::from(v).serialize(serializer), + } + } +} + +// TODO: Seems to be required only for tests? +transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_0, DidExchange); + +into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); +into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); +into_msg_with_type!(ProblemReport, DidExchangeTypeV1_0, ProblemReport); +into_msg_with_type!(Complete, DidExchangeTypeV1_0, Complete); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs similarity index 100% rename from aries/messages/src/msg_fields/protocols/did_exchange/problem_report.rs rename to aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs similarity index 97% rename from aries/messages/src/msg_fields/protocols/did_exchange/request.rs rename to aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs index 0cc68ffc63..4341770c02 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs @@ -49,7 +49,7 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_fields::protocols::did_exchange::request::{Request, RequestDecorators}, + msg_fields::protocols::did_exchange::v1_0::request::{Request, RequestDecorators}, msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs similarity index 100% rename from aries/messages/src/msg_fields/protocols/did_exchange/response.rs rename to aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs new file mode 100644 index 0000000000..91cc50cb21 --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs @@ -0,0 +1,77 @@ +// use derive_more::From; +// use serde::{de::Error, Deserialize, Serialize}; +// use shared::misc::serde_ignored::SerdeIgnored as NoContent; + +// use super::v1_0::{ +// complete::{Complete, CompleteDecorators}, +// problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, +// request::{Request, RequestContent, RequestDecorators}, +// response::{Response, ResponseContent, ResponseDecorators}, +// }; +// use crate::{ +// misc::utils::{into_msg_with_type, transit_to_aries_msg}, +// msg_fields::traits::DelayedSerde, +// msg_types::{ +// protocols::did_exchange::{ +// DidExchangeType as DidExchangeKind, DidExchangeTypeV1, DidExchangeTypeV1_0, +// DidExchangeTypeV1_1, }, MsgKindType, MsgWithType +// }, +// }; + +// #[derive(Clone, Debug, From, PartialEq)] +// pub enum DidExchangeV1_1 { +// Request(Request), +// Response(Response), +// ProblemReport(ProblemReport), +// Complete(Complete), +// } + +// impl DelayedSerde for DidExchangeV1_1 { +// type MsgType<'a> = (MsgKindType, &'a str); + +// fn delayed_deserialize<'de, D>( +// msg_type: Self::MsgType<'de>, +// deserializer: D, +// ) -> Result +// where +// D: serde::Deserializer<'de>, +// { +// let (kind, kind_str) = msg_type; + +// let kind = match protocol { +// DidExchangeKind::V1(DidExchangeTypeV1::V1_1(kind)) => kind.kind_from_str(kind_str), +// }; + +// match kind.map_err(D::Error::custom)? { +// DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), +// DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), +// DidExchangeTypeV1_0::ProblemReport => { +// ProblemReport::deserialize(deserializer).map(From::from) +// } +// DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), +// } +// } + +// fn delayed_serialize(&self, serializer: S) -> Result +// where +// S: serde::Serializer, +// { +// match self { +// Self::Request(v) => MsgWithType::from(v).serialize(serializer), +// Self::Response(v) => MsgWithType::from(v).serialize(serializer), +// Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), +// Self::Complete(v) => MsgWithType::from(v).serialize(serializer), +// } +// } +// } + +// // TODO: Seems to be required only for tests? +// // transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_0); +// // transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0); +// // transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_0); +// // transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_0); + +// into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); +// into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); +// into_msg_with_type!(ProblemReport, DidExchangeTypeV1_0, ProblemReport); +// into_msg_with_type!(Complete, DidExchangeTypeV1_0, Complete); diff --git a/aries/messages/src/msg_types/protocols/did_exchange.rs b/aries/messages/src/msg_types/protocols/did_exchange.rs index 0c5fb7b3cb..5da0852329 100644 --- a/aries/messages/src/msg_types/protocols/did_exchange.rs +++ b/aries/messages/src/msg_types/protocols/did_exchange.rs @@ -18,6 +18,8 @@ pub enum DidExchangeType { pub enum DidExchangeTypeV1 { #[msg_type(minor = 0, roles = "Role::Requester, Role::Responder")] V1_0(MsgKindType), + #[msg_type(minor = 1, roles = "Role::Requester, Role::Responder")] + V1_1(MsgKindType), } #[derive(Copy, Clone, Debug, AsRefStr, EnumString, PartialEq)] @@ -29,6 +31,15 @@ pub enum DidExchangeTypeV1_0 { Complete, } +#[derive(Copy, Clone, Debug, AsRefStr, EnumString, PartialEq)] +#[strum(serialize_all = "snake_case")] +pub enum DidExchangeTypeV1_1 { + Request, + Response, + ProblemReport, + Complete, +} + #[cfg(test)] mod tests { use serde_json::json; From ab675587f71016831270fa401b46a36d58950e08 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 18 Jun 2024 15:16:38 +1000 Subject: [PATCH 02/32] duplicate types Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 3 +- .../src/controllers/didcomm.rs | 57 ++++---- aries/aries_vcx/src/handlers/util.rs | 14 +- aries/messages/src/lib.rs | 10 +- .../msg_fields/protocols/did_exchange/mod.rs | 2 + .../protocols/did_exchange/v1_0/mod.rs | 1 - .../protocols/did_exchange/v1_1/complete.rs | 81 +++++++++++ .../protocols/did_exchange/v1_1/mod.rs | 137 +++++++++--------- .../did_exchange/v1_1/problem_report.rs | 112 ++++++++++++++ .../protocols/did_exchange/v1_1/request.rs | 127 ++++++++++++++++ .../protocols/did_exchange/v1_1/response.rs | 113 +++++++++++++++ .../src/msg_types/protocols/did_exchange.rs | 62 +++++++- aries/messages/src/msg_types/registry.rs | 1 + 13 files changed, 608 insertions(+), 112 deletions(-) create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index fb06b7630f..88652fffd4 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -60,7 +60,8 @@ impl HarnessAgent { "Failed to lock message buffer", ) })?; - msg_buffer.push(request.into()); + let m = AriesMessage::from(request); + msg_buffer.push(m); Ok(()) } diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index 7878afc8d1..051b5ad1b7 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -6,7 +6,7 @@ use aries_vcx_agent::aries_vcx::{ msg_fields::protocols::{ connection::Connection, cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, - did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, + did_exchange::DidExchange, notification::Notification, present_proof::{v1::PresentProofV1, PresentProof}, }, @@ -195,33 +195,34 @@ impl HarnessAgent { Ok(()) } - async fn handle_did_exchange_msg(&self, msg: DidExchange) -> HarnessResult<()> { - match msg { - DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { - self.queue_didexchange_request(request)?; - } - DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { - let res = self - .aries_agent - .did_exchange() - .handle_msg_response(response) - .await; - if let Err(err) = res { - error!("Error sending complete: {:?}", err); - }; - } - DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { - self.aries_agent - .did_exchange() - .handle_msg_complete(complete)?; - } - DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { - self.aries_agent - .did_exchange() - .receive_problem_report(problem_report)?; - } - }; - Ok(()) + async fn handle_did_exchange_msg(&self, _msg: DidExchange) -> HarnessResult<()> { + todo!() + // match msg { + // DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { + // self.queue_didexchange_request(request)?; + // } + // DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { + // let res = self + // .aries_agent + // .did_exchange() + // .handle_msg_response(response) + // .await; + // if let Err(err) = res { + // error!("Error sending complete: {:?}", err); + // }; + // } + // DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { + // self.aries_agent + // .did_exchange() + // .handle_msg_complete(complete)?; + // } + // DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { + // self.aries_agent + // .did_exchange() + // .receive_problem_report(problem_report)?; + // } + // }; + // Ok(()) } pub async fn receive_message(&self, payload: Vec) -> HarnessResult { diff --git a/aries/aries_vcx/src/handlers/util.rs b/aries/aries_vcx/src/handlers/util.rs index 0036797e70..c733da8def 100644 --- a/aries/aries_vcx/src/handlers/util.rs +++ b/aries/aries_vcx/src/handlers/util.rs @@ -4,7 +4,7 @@ use messages::{ connection::{invitation::Invitation, Connection}, coordinate_mediation::CoordinateMediation, cred_issuance::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance}, - did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, + did_exchange::{v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange}, discover_features::DiscoverFeatures, notification::Notification, out_of_band::{invitation::Invitation as OobInvitation, OutOfBand}, @@ -253,6 +253,18 @@ pub fn verify_thread_id(thread_id: &str, message: &AriesMessage) -> VcxResult<() AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::ProblemReport(msg))) => { matches_thread_id!(msg, thread_id) } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(msg))) => { + matches_opt_thread_id!(msg, thread_id) + } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Response(msg))) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Complete(msg))) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::ProblemReport(msg))) => { + matches_thread_id!(msg, thread_id) + } }; if !is_match { diff --git a/aries/messages/src/lib.rs b/aries/messages/src/lib.rs index 5e9367dbdb..65f20cc785 100644 --- a/aries/messages/src/lib.rs +++ b/aries/messages/src/lib.rs @@ -17,7 +17,7 @@ use display_as_json::Display; use misc::utils; use msg_fields::protocols::{ cred_issuance::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance}, - did_exchange::{v1_0::DidExchangeV1_0, DidExchange}, + did_exchange::{v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange}, pickup::Pickup, present_proof::{v2::PresentProofV2, PresentProof}, }; @@ -196,10 +196,9 @@ impl DelayedSerde for AriesMessage { DidExchangeV1_0::delayed_deserialize((msg_type, kind_str), deserializer) .map(|x| AriesMessage::from(DidExchange::V1_0(x))) } - Protocol::DidExchangeType(DidExchangeType::V1(DidExchangeTypeV1::V1_1(_msg_type))) => { - unimplemented!() - // DidExchange::delayed_deserialize((msg_type, kind_str), - // deserializer).map(From::from) + Protocol::DidExchangeType(DidExchangeType::V1(DidExchangeTypeV1::V1_1(msg_type))) => { + DidExchangeV1_1::delayed_deserialize((msg_type, kind_str), deserializer) + .map(|x| AriesMessage::from(DidExchange::V1_1(x))) } } } @@ -225,6 +224,7 @@ impl DelayedSerde for AriesMessage { Self::Pickup(v) => v.delayed_serialize(serializer), Self::CoordinateMediation(v) => v.delayed_serialize(serializer), Self::DidExchange(DidExchange::V1_0(v)) => v.delayed_serialize(serializer), + Self::DidExchange(DidExchange::V1_1(v)) => v.delayed_serialize(serializer), } } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs index 2092e9f03d..b757eb798f 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs @@ -1,5 +1,6 @@ use derive_more::From; use v1_0::DidExchangeV1_0; +use v1_1::DidExchangeV1_1; pub mod v1_0; pub mod v1_1; @@ -7,4 +8,5 @@ pub mod v1_1; #[derive(Clone, Debug, From, PartialEq)] pub enum DidExchange { V1_0(DidExchangeV1_0), + V1_1(DidExchangeV1_1), } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs index 140208b88b..c342eb0b67 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -66,7 +66,6 @@ impl DelayedSerde for DidExchangeV1_0 { } } -// TODO: Seems to be required only for tests? transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_0, DidExchange); transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0, DidExchange); transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_0, DidExchange); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs new file mode 100644 index 0000000000..de235d37bc --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs @@ -0,0 +1,81 @@ +use serde::{Deserialize, Serialize}; +use shared::misc::serde_ignored::SerdeIgnored as NoContent; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type Complete = MsgParts; + +// TODO: Pthid is mandatory in this case! +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct CompleteDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + + use super::*; + use crate::{ + decorators::{ + thread::tests::{make_extended_thread, make_minimal_thread}, + timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + }; + + #[test] + fn test_minimal_complete_message() { + let thread = make_minimal_thread(); + + let expected = json!({ + "~thread": { + "thid": thread.thid + } + }); + + let decorators = CompleteDecorators { + thread, + timing: None, + }; + + test_utils::test_msg( + NoContent, + decorators, + DidExchangeTypeV1_1::Complete, + expected, + ); + } + + #[test] + fn test_extended_complete_message() { + let decorators = CompleteDecorators { + thread: make_extended_thread(), + timing: Some(make_extended_timing()), + }; + + let expected = json!({ + "~thread": serde_json::to_value(make_extended_thread()).unwrap(), + "~timing": serde_json::to_value(make_extended_timing()).unwrap() + }); + + test_utils::test_msg( + NoContent, + decorators, + DidExchangeTypeV1_1::Complete, + expected, + ); + } +} diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs index 91cc50cb21..5985d69eef 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs @@ -1,77 +1,78 @@ -// use derive_more::From; -// use serde::{de::Error, Deserialize, Serialize}; -// use shared::misc::serde_ignored::SerdeIgnored as NoContent; +// TODO: Why are not msg fields and types grouped by protocol??? +pub mod complete; +// TODO: Duplicates connection problem report, deduplicate +pub mod problem_report; +pub mod request; +pub mod response; -// use super::v1_0::{ -// complete::{Complete, CompleteDecorators}, -// problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, -// request::{Request, RequestContent, RequestDecorators}, -// response::{Response, ResponseContent, ResponseDecorators}, -// }; -// use crate::{ -// misc::utils::{into_msg_with_type, transit_to_aries_msg}, -// msg_fields::traits::DelayedSerde, -// msg_types::{ -// protocols::did_exchange::{ -// DidExchangeType as DidExchangeKind, DidExchangeTypeV1, DidExchangeTypeV1_0, -// DidExchangeTypeV1_1, }, MsgKindType, MsgWithType -// }, -// }; +use derive_more::From; +use serde::{de::Error, Deserialize, Serialize}; +use shared::misc::serde_ignored::SerdeIgnored as NoContent; -// #[derive(Clone, Debug, From, PartialEq)] -// pub enum DidExchangeV1_1 { -// Request(Request), -// Response(Response), -// ProblemReport(ProblemReport), -// Complete(Complete), -// } +use self::{ + complete::{Complete, CompleteDecorators}, + problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, + request::{Request, RequestContent, RequestDecorators}, + response::{Response, ResponseContent, ResponseDecorators}, +}; +use super::DidExchange; +use crate::{ + misc::utils::{into_msg_with_type, transit_to_aries_msg}, + msg_fields::traits::DelayedSerde, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType, MsgWithType}, +}; -// impl DelayedSerde for DidExchangeV1_1 { -// type MsgType<'a> = (MsgKindType, &'a str); +#[derive(Clone, Debug, From, PartialEq)] +pub enum DidExchangeV1_1 { + Request(Request), + Response(Response), + ProblemReport(ProblemReport), + Complete(Complete), +} -// fn delayed_deserialize<'de, D>( -// msg_type: Self::MsgType<'de>, -// deserializer: D, -// ) -> Result -// where -// D: serde::Deserializer<'de>, -// { -// let (kind, kind_str) = msg_type; +impl DelayedSerde for DidExchangeV1_1 { + type MsgType<'a> = (MsgKindType, &'a str); -// let kind = match protocol { -// DidExchangeKind::V1(DidExchangeTypeV1::V1_1(kind)) => kind.kind_from_str(kind_str), -// }; + fn delayed_deserialize<'de, D>( + msg_type: Self::MsgType<'de>, + deserializer: D, + ) -> Result + where + D: serde::Deserializer<'de>, + { + let (protocol, kind_str) = msg_type; + let kind = protocol.kind_from_str(kind_str); -// match kind.map_err(D::Error::custom)? { -// DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), -// DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), -// DidExchangeTypeV1_0::ProblemReport => { -// ProblemReport::deserialize(deserializer).map(From::from) -// } -// DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), -// } -// } + match kind.map_err(D::Error::custom)? { + DidExchangeTypeV1_1::Request => Request::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_1::Response => Response::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_1::ProblemReport => { + ProblemReport::deserialize(deserializer).map(From::from) + } + DidExchangeTypeV1_1::Complete => Complete::deserialize(deserializer).map(From::from), + } + } -// fn delayed_serialize(&self, serializer: S) -> Result -// where -// S: serde::Serializer, -// { -// match self { -// Self::Request(v) => MsgWithType::from(v).serialize(serializer), -// Self::Response(v) => MsgWithType::from(v).serialize(serializer), -// Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), -// Self::Complete(v) => MsgWithType::from(v).serialize(serializer), -// } -// } -// } + fn delayed_serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Request(v) => MsgWithType::from(v).serialize(serializer), + Self::Response(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), + Self::Complete(v) => MsgWithType::from(v).serialize(serializer), + } + } +} -// // TODO: Seems to be required only for tests? -// // transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_0); -// // transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0); -// // transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_0); -// // transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_0); +// TODO: Seems to be required only for tests? +transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_1, DidExchange); -// into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); -// into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); -// into_msg_with_type!(ProblemReport, DidExchangeTypeV1_0, ProblemReport); -// into_msg_with_type!(Complete, DidExchangeTypeV1_0, Complete); +into_msg_with_type!(Request, DidExchangeTypeV1_1, Request); +into_msg_with_type!(Response, DidExchangeTypeV1_1, Response); +into_msg_with_type!(ProblemReport, DidExchangeTypeV1_1, ProblemReport); +into_msg_with_type!(Complete, DidExchangeTypeV1_1, Complete); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs new file mode 100644 index 0000000000..a132ea653f --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs @@ -0,0 +1,112 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{localization::MsgLocalization, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type ProblemReport = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct ProblemReportContent { + #[serde(rename = "problem-code")] + #[serde(skip_serializing_if = "Option::is_none")] + pub problem_code: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub explain: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ProblemCode { + RequestNotAccepted, + RequestProcessingError, + ResponseNotAccepted, + ResponseProcessingError, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct ProblemReportDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~l10n")] + #[serde(skip_serializing_if = "Option::is_none")] + pub localization: Option, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +impl ProblemReportDecorators { + pub fn new(thread: Thread) -> Self { + Self { + thread, + localization: None, + timing: None, + } + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + + use super::*; + use crate::{ + decorators::{ + localization::tests::make_extended_msg_localization, + thread::tests::make_extended_thread, timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + }; + + #[test] + fn test_minimal_conn_problem_report() { + let content = ProblemReportContent::default(); + + let decorators = ProblemReportDecorators::new(make_extended_thread()); + + let expected = json!({ + "~thread": decorators.thread + }); + + test_utils::test_msg( + content, + decorators, + DidExchangeTypeV1_1::ProblemReport, + expected, + ); + } + + #[test] + fn test_extended_conn_problem_report() { + let mut content = ProblemReportContent::default(); + content.problem_code = Some(ProblemCode::RequestNotAccepted); + content.explain = Some("test_conn_problem_report_explain".to_owned()); + + let mut decorators = ProblemReportDecorators::new(make_extended_thread()); + decorators.timing = Some(make_extended_timing()); + decorators.localization = Some(make_extended_msg_localization()); + + let expected = json!({ + "problem-code": content.problem_code, + "explain": content.explain, + "~thread": decorators.thread, + "~timing": decorators.timing, + "~l10n": decorators.localization + }); + + test_utils::test_msg( + content, + decorators, + DidExchangeTypeV1_1::ProblemReport, + expected, + ); + } +} diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs new file mode 100644 index 0000000000..afd42afe83 --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs @@ -0,0 +1,127 @@ +use serde::{Deserialize, Serialize}; +use shared::maybe_known::MaybeKnown; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{ + attachment::Attachment, + thread::{Thread, ThreadGoalCode}, + timing::Timing, + }, + msg_parts::MsgParts, +}; + +pub type Request = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct RequestContent { + pub label: String, + pub goal_code: Option>, + pub goal: Option, + pub did: String, // TODO: Use Did + #[serde(rename = "did_doc~attach")] + pub did_doc: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct RequestDecorators { + #[serde(rename = "~thread")] + #[serde(skip_serializing_if = "Option::is_none")] + pub thread: Option, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use diddoc_legacy::aries::diddoc::AriesDidDoc; + use serde_json::json; + + use super::*; + use crate::{ + decorators::{ + attachment::{AttachmentData, AttachmentType}, + thread::tests::make_extended_thread, + timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_fields::protocols::did_exchange::v1_1::request::{Request, RequestDecorators}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + }; + + pub fn request_content() -> RequestContent { + let did_doc = AriesDidDoc::default(); + RequestContent { + label: "test_request_label".to_owned(), + goal_code: Some(MaybeKnown::Known(ThreadGoalCode::AriesRelBuild)), + goal: Some("test_goal".to_owned()), + did: did_doc.id.clone(), + did_doc: Some( + Attachment::builder() + .data( + AttachmentData::builder() + .content(AttachmentType::Json( + serde_json::to_value(&did_doc).unwrap(), + )) + .build(), + ) + .build(), + ), + } + } + + #[test] + fn test_print_message() { + let msg: Request = Request::builder() + .id("test_id".to_owned()) + .content(request_content()) + .decorators(RequestDecorators::default()) + .build(); + let printed_json = format!("{}", msg); + let parsed_request: Request = serde_json::from_str(&printed_json).unwrap(); + assert_eq!(msg, parsed_request); + } + + #[test] + fn test_minimal_didexchange_request() { + let content = request_content(); + let expected = json!({ + "label": content.label, + "goal_code": content.goal_code, + "goal": content.goal, + "did": content.did, + "did_doc~attach": content.did_doc, + }); + test_utils::test_msg( + content, + RequestDecorators::default(), + DidExchangeTypeV1_1::Request, + expected, + ); + } + + #[test] + fn test_extended_didexchange_request() { + let content = request_content(); + + let mut decorators = RequestDecorators::default(); + decorators.thread = Some(make_extended_thread()); + decorators.timing = Some(make_extended_timing()); + + let expected = json!({ + "label": content.label, + "goal_code": content.goal_code, + "goal": content.goal, + "did": content.did, + "did_doc~attach": content.did_doc, + "~thread": decorators.thread, + "~timing": decorators.timing + }); + + test_utils::test_msg(content, decorators, DidExchangeTypeV1_1::Request, expected); + } +} diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs new file mode 100644 index 0000000000..f62a9309c5 --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs @@ -0,0 +1,113 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{attachment::Attachment, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type Response = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct ResponseContent { + pub did: String, // TODO: Use Did + #[serde(rename = "did_doc~attach")] + pub did_doc: Option, + #[serde(rename = "did_rotate~attach")] + pub did_rotate: Option, +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, TypedBuilder)] +pub struct ResponseDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use diddoc_legacy::aries::diddoc::AriesDidDoc; + use serde_json::json; + + use super::*; + use crate::{ + decorators::{ + attachment::{AttachmentData, AttachmentType}, + thread::tests::make_extended_thread, + timing::tests::make_extended_timing, + }, + misc::{test_utils, MimeType}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + }; + + fn response_content() -> ResponseContent { + let did_doc = AriesDidDoc::default(); + ResponseContent { + did: did_doc.id.clone(), + did_doc: Some( + Attachment::builder() + .data( + AttachmentData::builder() + .content(AttachmentType::Json( + serde_json::to_value(&did_doc).unwrap(), + )) + .build(), + ) + .build(), + ), + did_rotate: Some( + Attachment::builder() + .data( + AttachmentData::builder() + .content(AttachmentType::Base64(String::from("Qi5kaWRAQjpB"))) + .build(), + ) + .mime_type(MimeType::Plain) + .build(), + ), + } + } + + #[test] + fn test_minimal_conn_response() { + let content = response_content(); + + let decorators = ResponseDecorators { + thread: make_extended_thread(), + timing: None, + }; + + let expected = json!({ + "did": content.did, + "did_doc~attach": content.did_doc, + "~thread": decorators.thread + }); + + test_utils::test_msg(content, decorators, DidExchangeTypeV1_1::Response, expected); + } + + #[test] + fn test_extended_conn_response() { + let content = response_content(); + + let decorators = ResponseDecorators { + thread: make_extended_thread(), + timing: Some(make_extended_timing()), + }; + + let expected = json!({ + "did": content.did, + "did_doc~attach": content.did_doc, + "did_rotate~attach": content.did_rotate, + "~thread": decorators.thread, + "~timing": decorators.timing + }); + + test_utils::test_msg(content, decorators, DidExchangeTypeV1_1::Response, expected); + } +} diff --git a/aries/messages/src/msg_types/protocols/did_exchange.rs b/aries/messages/src/msg_types/protocols/did_exchange.rs index 5da0852329..dd375270db 100644 --- a/aries/messages/src/msg_types/protocols/did_exchange.rs +++ b/aries/messages/src/msg_types/protocols/did_exchange.rs @@ -16,10 +16,10 @@ pub enum DidExchangeType { #[transitive(into(DidExchangeType, Protocol))] #[msg_type(major = 1)] pub enum DidExchangeTypeV1 { - #[msg_type(minor = 0, roles = "Role::Requester, Role::Responder")] - V1_0(MsgKindType), #[msg_type(minor = 1, roles = "Role::Requester, Role::Responder")] V1_1(MsgKindType), + #[msg_type(minor = 0, roles = "Role::Requester, Role::Responder")] + V1_0(MsgKindType), } #[derive(Copy, Clone, Debug, AsRefStr, EnumString, PartialEq)] @@ -48,18 +48,28 @@ mod tests { use crate::misc::test_utils; #[test] - fn test_protocol_didexchange() { + fn test_protocol_didexchange_v1_0() { test_utils::test_serde( Protocol::from(DidExchangeTypeV1::new_v1_0()), json!("https://didcomm.org/didexchange/1.0"), ) } + #[test] + fn test_protocol_didexchange_v1_1() { + let x = Protocol::from(DidExchangeTypeV1::new_v1_1()); + dbg!(x); + test_utils::test_serde( + Protocol::from(DidExchangeTypeV1::new_v1_1()), + json!("https://didcomm.org/didexchange/1.1"), + ) + } + #[test] fn test_version_resolution_didexchange() { test_utils::test_msg_type_resolution( "https://didcomm.org/didexchange/1.255", - DidExchangeTypeV1::new_v1_0(), + DidExchangeTypeV1::new_v1_1(), ) } @@ -73,7 +83,7 @@ mod tests { } #[test] - fn test_msg_type_request() { + fn test_msg_type_request_v1_0() { test_utils::test_msg_type( "https://didcomm.org/didexchange/1.0", "request", @@ -82,7 +92,7 @@ mod tests { } #[test] - fn test_msg_type_response() { + fn test_msg_type_response_v1_0() { test_utils::test_msg_type( "https://didcomm.org/didexchange/1.0", "response", @@ -91,7 +101,7 @@ mod tests { } #[test] - fn test_msg_type_complete() { + fn test_msg_type_complete_v1_0() { test_utils::test_msg_type( "https://didcomm.org/didexchange/1.0", "complete", @@ -100,11 +110,47 @@ mod tests { } #[test] - fn test_msg_type_problem() { + fn test_msg_type_problem_v1_0() { test_utils::test_msg_type( "https://didcomm.org/didexchange/1.0", "problem_report", DidExchangeTypeV1::new_v1_0(), ) } + + #[test] + fn test_msg_type_request_v1_1() { + test_utils::test_msg_type( + "https://didcomm.org/didexchange/1.1", + "request", + DidExchangeTypeV1::new_v1_1(), + ) + } + + #[test] + fn test_msg_type_response_v1_1() { + test_utils::test_msg_type( + "https://didcomm.org/didexchange/1.1", + "response", + DidExchangeTypeV1::new_v1_1(), + ) + } + + #[test] + fn test_msg_type_complete_v1_1() { + test_utils::test_msg_type( + "https://didcomm.org/didexchange/1.1", + "complete", + DidExchangeTypeV1::new_v1_1(), + ) + } + + #[test] + fn test_msg_type_problem_v1_1() { + test_utils::test_msg_type( + "https://didcomm.org/didexchange/1.1", + "problem_report", + DidExchangeTypeV1::new_v1_1(), + ) + } } diff --git a/aries/messages/src/msg_types/registry.rs b/aries/messages/src/msg_types/registry.rs index ddf5461bec..a6850dd8b2 100644 --- a/aries/messages/src/msg_types/registry.rs +++ b/aries/messages/src/msg_types/registry.rs @@ -97,6 +97,7 @@ lazy_static! { map_insert(&mut m, extract_parts!(PickupTypeV2::new_v2_0())); map_insert(&mut m, extract_parts!(CoordinateMediationTypeV1::new_v1_0())); map_insert(&mut m, extract_parts!(DidExchangeTypeV1::new_v1_0())); + map_insert(&mut m, extract_parts!(DidExchangeTypeV1::new_v1_1())); m }; } From 0354cb87036152d741293e8f14a33dc71bac43aa Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 09:57:10 +1000 Subject: [PATCH 03/32] static generic types for messages created and piped thru all layers Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 74 ++++--- .../src/controllers/didcomm.rs | 80 +++++--- .../src/handlers/did_exchange.rs | 40 ++-- .../did_exchange/state_machine/generic/mod.rs | 27 ++- .../did_exchange/state_machine/helpers.rs | 38 +++- .../did_exchange/state_machine/mod.rs | 13 +- .../state_machine/requester/helpers.rs | 9 +- .../requester/request_sent/mod.rs | 43 ++-- .../responder/response_sent/mod.rs | 54 +++-- aries/aries_vcx/tests/test_did_exchange.rs | 4 +- .../msg_fields/protocols/did_exchange/mod.rs | 1 + .../protocols/did_exchange/v1_0/complete.rs | 29 +-- .../protocols/did_exchange/v1_0/mod.rs | 23 ++- .../did_exchange/v1_0/problem_report.rs | 58 +----- .../protocols/did_exchange/v1_0/request.rs | 43 +--- .../protocols/did_exchange/v1_0/response.rs | 14 +- .../protocols/did_exchange/v1_1/complete.rs | 29 +-- .../protocols/did_exchange/v1_1/mod.rs | 23 ++- .../did_exchange/v1_1/problem_report.rs | 60 +----- .../protocols/did_exchange/v1_1/request.rs | 43 +--- .../protocols/did_exchange/v1_1/response.rs | 16 +- .../protocols/did_exchange/v1_x/complete.rs | 144 +++++++++++++ .../protocols/did_exchange/v1_x/mod.rs | 7 + .../did_exchange/v1_x/problem_report.rs | 178 ++++++++++++++++ .../protocols/did_exchange/v1_x/request.rs | 191 ++++++++++++++++++ .../protocols/did_exchange/v1_x/response.rs | 72 +++++++ aries/messages/src/msg_types/mod.rs | 6 + 27 files changed, 938 insertions(+), 381 deletions(-) create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_x/mod.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs create mode 100644 aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index 88652fffd4..f0c37ceb7f 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -5,8 +5,7 @@ use aries_vcx_agent::aries_vcx::{ did_parser_nom::Did, messages::{ msg_fields::protocols::did_exchange::{ - v1_0::{request::Request, DidExchangeV1_0}, - DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::AnyRequest, DidExchange, }, AriesMessage, }, @@ -52,8 +51,8 @@ impl HarnessAgent { Ok(json!({ "connection_id" : connection_id }).to_string()) } - pub fn queue_didexchange_request(&self, request: Request) -> HarnessResult<()> { - info!("queue_didexchange_request >> request: {}", request); + pub fn queue_didexchange_request(&self, request: AnyRequest) -> HarnessResult<()> { + info!("queue_didexchange_request >> request: {:?}", request); let mut msg_buffer = self.didx_msg_buffer.write().map_err(|_| { HarnessError::from_msg( HarnessErrorType::InvalidState, @@ -145,39 +144,50 @@ impl HarnessAgent { ) })? }; - if let AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) = - request - { - let opt_invitation = match request.decorators.thread.clone().unwrap().pthid { - None => None, - Some(pthid) => { - let invitation = self.aries_agent.out_of_band().get_invitation(&pthid)?; - Some(invitation) - } - }; - let (thid, pthid) = self - .aries_agent - .did_exchange() - .handle_msg_request(request.clone(), opt_invitation) - .await?; + let request: AnyRequest = match request { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) => { + request.into() + } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { + request.into() + } + _ => { + return Err(HarnessError::from_msg( + HarnessErrorType::InvalidState, + "Message is not a request", + )) + } + }; + + let request_thread = match request { + AnyRequest::V1_0(ref inner) => &inner.decorators.thread, + AnyRequest::V1_1(ref inner) => &inner.decorators.thread, + }; - if let Some(pthid) = pthid { - self.store_mapping_pthid_thid(pthid, thid.clone()); - } else { - warn!("No storing pthid->this mapping; no pthid available"); + let opt_invitation = match request_thread.clone().and_then(|th| th.pthid) { + Some(pthid) => { + let invitation = self.aries_agent.out_of_band().get_invitation(&pthid)?; + Some(invitation) } + None => None, + }; + let (thid, pthid) = self + .aries_agent + .did_exchange() + .handle_msg_request(request.clone(), opt_invitation) + .await?; - self.aries_agent - .did_exchange() - .send_response(thid.clone()) - .await?; - Ok(json!({ "connection_id": thid }).to_string()) + if let Some(pthid) = pthid { + self.store_mapping_pthid_thid(pthid, thid.clone()); } else { - Err(HarnessError::from_msg( - HarnessErrorType::InvalidState, - "Message is not a request", - )) + warn!("No storing pthid->this mapping; no pthid available"); } + + self.aries_agent + .did_exchange() + .send_response(thid.clone()) + .await?; + Ok(json!({ "connection_id": thid }).to_string()) } pub async fn didx_get_state(&self, connection_id: &str) -> HarnessResult { diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index 051b5ad1b7..6ec4536a97 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -6,7 +6,7 @@ use aries_vcx_agent::aries_vcx::{ msg_fields::protocols::{ connection::Connection, cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, - did_exchange::DidExchange, + did_exchange::{v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange}, notification::Notification, present_proof::{v1::PresentProofV1, PresentProof}, }, @@ -195,34 +195,56 @@ impl HarnessAgent { Ok(()) } - async fn handle_did_exchange_msg(&self, _msg: DidExchange) -> HarnessResult<()> { - todo!() - // match msg { - // DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { - // self.queue_didexchange_request(request)?; - // } - // DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { - // let res = self - // .aries_agent - // .did_exchange() - // .handle_msg_response(response) - // .await; - // if let Err(err) = res { - // error!("Error sending complete: {:?}", err); - // }; - // } - // DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { - // self.aries_agent - // .did_exchange() - // .handle_msg_complete(complete)?; - // } - // DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { - // self.aries_agent - // .did_exchange() - // .receive_problem_report(problem_report)?; - // } - // }; - // Ok(()) + async fn handle_did_exchange_msg(&self, msg: DidExchange) -> HarnessResult<()> { + match msg { + DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { + self.queue_didexchange_request(request.into())?; + } + DidExchange::V1_1(DidExchangeV1_1::Request(request)) => { + self.queue_didexchange_request(request.into())?; + } + DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { + let res = self + .aries_agent + .did_exchange() + .handle_msg_response(response.into()) + .await; + if let Err(err) = res { + error!("Error sending complete: {:?}", err); + }; + } + DidExchange::V1_1(DidExchangeV1_1::Response(response)) => { + let res = self + .aries_agent + .did_exchange() + .handle_msg_response(response.into()) + .await; + if let Err(err) = res { + error!("Error sending complete: {:?}", err); + }; + } + DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { + self.aries_agent + .did_exchange() + .handle_msg_complete(complete)?; + } + DidExchange::V1_1(DidExchangeV1_1::Complete(complete)) => { + self.aries_agent + .did_exchange() + .handle_msg_complete(complete)?; + } + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { + self.aries_agent + .did_exchange() + .receive_problem_report(problem_report)?; + } + DidExchange::V1_1(DidExchangeV1_1::ProblemReport(problem_report)) => { + self.aries_agent + .did_exchange() + .receive_problem_report(problem_report)?; + } + }; + Ok(()) } pub async fn receive_message(&self, payload: Vec) -> HarnessResult { diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index fd388f141a..9f08247fce 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -5,9 +5,9 @@ use aries_vcx::{ did_parser_nom::Did, messages::{ msg_fields::protocols::{ - did_exchange::v1_0::{ - complete::Complete, problem_report::ProblemReport, request::Request, - response::Response, + did_exchange::v1_x::{ + complete::Complete, problem_report::ProblemReport, request::AnyRequest, + response::AnyResponse, }, out_of_band::invitation::Invitation as OobInvitation, }, @@ -134,16 +134,19 @@ impl DidcommHandlerDidExchange { // rather than being supplied by upper layers pub async fn handle_msg_request( &self, - request: Request, + request: AnyRequest, invitation: Option, ) -> AgentResult<(String, Option)> { // todo: type the return type // Todo: messages should expose fallible API to get thid (for any aries msg). It's common // pattern - let thid = request + let thread = match request { + AnyRequest::V1_0(ref inner) => &inner.decorators.thread, + AnyRequest::V1_1(ref inner) => &inner.decorators.thread, + }; + + let thid = thread .clone() - .decorators - .thread .ok_or_else(|| { AgentError::from_msg( AgentErrorKind::InvalidState, @@ -168,10 +171,7 @@ impl DidcommHandlerDidExchange { let (peer_did_4_invitee, _our_verkey) = create_peer_did_4(self.wallet.as_ref(), self.service_endpoint.clone(), vec![]).await?; - let pthid = request - .clone() - .decorators - .thread + let pthid = thread .clone() .ok_or_else(|| { AgentError::from_msg( @@ -225,8 +225,12 @@ impl DidcommHandlerDidExchange { } // todo: break down into "process_response" and "send_complete" - pub async fn handle_msg_response(&self, response: Response) -> AgentResult { - let thid = response.decorators.thread.thid.clone(); + pub async fn handle_msg_response(&self, response: AnyResponse) -> AgentResult { + let thread = match response { + AnyResponse::V1_0(ref inner) => &inner.decorators.thread, + AnyResponse::V1_1(ref inner) => &inner.decorators.thread, + }; + let thid = thread.thid.clone(); let (requester, _) = self.did_exchange.get(&thid)?; @@ -251,14 +255,20 @@ impl DidcommHandlerDidExchange { Ok(thid) } - pub fn handle_msg_complete(&self, complete: Complete) -> AgentResult { + pub fn handle_msg_complete( + &self, + complete: Complete, + ) -> AgentResult { let thread_id = complete.decorators.thread.thid.clone(); let (requester, _) = self.did_exchange.get(&thread_id)?; let requester = requester.handle_complete(complete)?; self.did_exchange.insert(&thread_id, (requester, None)) } - pub fn receive_problem_report(&self, problem_report: ProblemReport) -> AgentResult { + pub fn receive_problem_report( + &self, + problem_report: ProblemReport, + ) -> AgentResult { let thread_id = problem_report.decorators.thread.thid.clone(); let (requester, _) = self.did_exchange.get(&thread_id)?; let requester = requester.handle_problem_report(problem_report)?; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index 00608601ad..2cb6c8f259 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -5,8 +5,14 @@ use did_doc::schema::did_doc::DidDocument; use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::v1_0::{ - complete::Complete, problem_report::ProblemReport, request::Request, response::Response, +use messages::msg_fields::protocols::did_exchange::{ + v1_1::request::Request, + v1_x::{ + complete::{AnyComplete, Complete}, + problem_report::ProblemReport, + request::AnyRequest, + response::AnyResponse, + }, }; use public_key::Key; pub use thin_state::ThinState; @@ -106,10 +112,10 @@ impl GenericDidExchange { pub async fn handle_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: Request, + request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, - ) -> Result<(Self, Response), AriesVcxError> { + ) -> Result<(Self, AnyResponse), AriesVcxError> { let TransitionResult { state, output } = DidExchangeResponder::::receive_request( wallet, @@ -127,9 +133,9 @@ impl GenericDidExchange { pub async fn handle_response( self, - response: Response, + response: AnyResponse, resolver_registry: Arc, - ) -> Result<(Self, Complete), (Self, AriesVcxError)> { + ) -> Result<(Self, AnyComplete), (Self, AriesVcxError)> { match self { GenericDidExchange::Requester(requester_state) => match requester_state { RequesterState::RequestSent(request_sent_state) => { @@ -172,7 +178,10 @@ impl GenericDidExchange { } } - pub fn handle_complete(self, complete: Complete) -> Result { + pub fn handle_complete( + self, + complete: Complete, + ) -> Result { match self { GenericDidExchange::Responder(responder_state) => match responder_state { ResponderState::ResponseSent(response_sent_state) => { @@ -211,9 +220,9 @@ impl GenericDidExchange { } } - pub fn handle_problem_report( + pub fn handle_problem_report( self, - problem_report: ProblemReport, + problem_report: ProblemReport, ) -> Result { match self { GenericDidExchange::Requester(requester_state) => match requester_state { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index a7e0ff7474..6839ca3c1b 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -24,8 +24,10 @@ use messages::{ thread::Thread, timing::Timing, }, - msg_fields::protocols::did_exchange::v1_0::response::{ - Response, ResponseContent, ResponseDecorators, + msg_fields::protocols::did_exchange::{ + v1_0::response::{Response as ResponseV1_0, ResponseContent as ResponseV1_0Content}, + v1_1::response::{Response as ResponseV1_1, ResponseContent as ResponseV1_1Content}, + v1_x::response::ResponseDecorators, }, }; use public_key::{Key, KeyType}; @@ -41,20 +43,40 @@ use crate::{ }, }; -pub(crate) fn construct_response( +pub(crate) fn construct_response_v1_0( request_id: String, our_did_document: &DidDocument, - signed_attach: Attachment, -) -> Response { - let content = ResponseContent::builder() + signed_diddoc_attach: Attachment, +) -> ResponseV1_0 { + let content = ResponseV1_0Content::builder() .did(our_did_document.id().to_string()) - .did_doc(Some(signed_attach)) + .did_doc(Some(signed_diddoc_attach)) .build(); let decorators = ResponseDecorators::builder() .thread(Thread::builder().thid(request_id).build()) .timing(Timing::builder().out_time(Utc::now()).build()) .build(); - Response::builder() + ResponseV1_0::builder() + .id(Uuid::new_v4().to_string()) + .content(content) + .decorators(decorators) + .build() +} + +pub(crate) fn construct_response_v1_1( + request_id: String, + our_did_document: &DidDocument, + signed_didrotate_attach: Attachment, +) -> ResponseV1_1 { + let content = ResponseV1_1Content::builder() + .did(our_did_document.id().to_string()) + .did_rotate(signed_didrotate_attach) + .build(); + let decorators = ResponseDecorators::builder() + .thread(Thread::builder().thid(request_id).build()) + .timing(Timing::builder().out_time(Utc::now()).build()) + .build(); + ResponseV1_1::builder() .id(Uuid::new_v4().to_string()) .content(content) .decorators(decorators) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs index f443eef4ff..d3882efdd9 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs @@ -10,8 +10,11 @@ use chrono::Utc; use did_doc::schema::did_doc::DidDocument; use messages::{ decorators::{thread::Thread, timing::Timing}, - msg_fields::protocols::did_exchange::v1_0::problem_report::{ - ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, + msg_fields::protocols::did_exchange::{ + v1_1::problem_report::ProblemReport as ProblemReportV1_1, + v1_x::problem_report::{ + ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, + }, }, }; use uuid::Uuid; @@ -38,7 +41,7 @@ impl DidExchange { self, reason: String, problem_code: Option, - ) -> TransitionResult, ProblemReport> { + ) -> TransitionResult, ProblemReportV1_1> { let content = ProblemReportContent::builder() .problem_code(problem_code) .explain(Some(reason.clone())) @@ -71,9 +74,9 @@ impl DidExchange { } } - pub fn receive_problem_report( + pub fn receive_problem_report( self, - problem_report: ProblemReport, + problem_report: ProblemReport, ) -> DidExchange { DidExchange { state: Abandoned { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index 067efac0a1..95922db98b 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -6,7 +6,7 @@ use messages::{ timing::Timing, }, msg_fields::protocols::{ - did_exchange::v1_0::{ + did_exchange::v1_x::{ complete::{Complete, CompleteDecorators}, request::{Request, RequestContent, RequestDecorators}, }, @@ -18,7 +18,10 @@ use uuid::Uuid; use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; -pub fn construct_request(invitation_id: Option, our_did: String) -> Request { +pub fn construct_request( + invitation_id: Option, + our_did: String, +) -> Request { let msg_id = Uuid::new_v4().to_string(); let thid = msg_id.clone(); let thread = match invitation_id { @@ -43,7 +46,7 @@ pub fn construct_request(invitation_id: Option, our_did: String) -> Requ .build() } -pub fn construct_didexchange_complete(request_id: String) -> Complete { +pub fn construct_didexchange_complete(request_id: String) -> Complete { // assuming we'd want to support RFC 100% and include pthread in complete message, we can add // new function argument: `invitation_id: Option` // We choose not to do this, as it's rather historic artifact and doesn't have justification in diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 3cc24c6406..64a413e96a 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -4,8 +4,12 @@ use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver::traits::resolvable::resolution_output::DidResolutionOutput; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::v1_0::{ - complete::Complete as CompleteMessage, request::Request, response::Response, +use messages::{ + msg_fields::protocols::did_exchange::{ + v1_1::request::Request, + v1_x::{complete::AnyComplete, response::AnyResponse}, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use super::DidExchangeRequester; @@ -28,7 +32,7 @@ impl DidExchangeRequester { their_did: &Did, our_peer_did: &PeerDid, ) -> Result, AriesVcxError> { - info!( + debug!( "DidExchangeRequester::construct_request >> their_did: {}, our_peer_did: \ {}", their_did, our_peer_did @@ -40,7 +44,7 @@ impl DidExchangeRequester { let our_did_document = our_peer_did.resolve_did_doc()?; let request = construct_request(invitation_id.clone(), our_peer_did.to_string()); - info!( + debug!( "DidExchangeRequester::construct_request << prepared request: {}", request ); @@ -58,16 +62,17 @@ impl DidExchangeRequester { pub async fn receive_response( self, - response: Response, + response: AnyResponse, resolver_registry: Arc, - ) -> Result< - TransitionResult, CompleteMessage>, - TransitionError, - > { - info!( + ) -> Result, AnyComplete>, TransitionError> + { + debug!( "DidExchangeRequester::receive_response >> response: {:?}", response ); + let version = response.get_version_marker(); + let response = response.into_v1_1(); + if response.decorators.thread.thid != self.state.request_id { return Err(TransitionError { error: AriesVcxError::from_msg( @@ -77,14 +82,15 @@ impl DidExchangeRequester { state: self, }); } + // TODO - process differently depending on version let did_document = if let Some(ddo) = response.content.did_doc { - info!( + debug!( "DidExchangeRequester::receive_response >> the Response message \ contained attached ddo" ); attachment_to_diddoc(ddo).map_err(to_transition_error(self.clone()))? } else { - info!( + debug!( "DidExchangeRequester::receive_response >> the Response message \ contains pairwise DID, resolving to DID Document" ); @@ -97,9 +103,16 @@ impl DidExchangeRequester { did_document }; - let complete_message = construct_didexchange_complete(self.state.request_id.clone()); - info!( - "DidExchangeRequester::receive_response << complete_message: {}", + let complete_message = match version { + DidExchangeTypeV1::V1_1(_) => AnyComplete::V1_1(construct_didexchange_complete( + self.state.request_id.clone(), + )), + DidExchangeTypeV1::V1_0(_) => AnyComplete::V1_0(construct_didexchange_complete( + self.state.request_id.clone(), + )), + }; + debug!( + "DidExchangeRequester::receive_response << complete_message: {:?}", complete_message ); diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index eed2f56a49..455e033223 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -4,8 +4,13 @@ use aries_vcx_wallet::wallet::base_wallet::BaseWallet; use did_doc::schema::did_doc::DidDocument; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::v1_0::{ - complete::Complete, request::Request, response::Response, +use messages::{ + msg_fields::protocols::did_exchange::v1_x::{ + complete::Complete, + request::{AnyRequest, Request}, + response::AnyResponse, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use public_key::Key; @@ -14,7 +19,8 @@ use crate::{ errors::error::{AriesVcxError, AriesVcxErrorKind}, protocols::did_exchange::{ state_machine::helpers::{ - attachment_to_diddoc, construct_response, ddo_to_attach, jws_sign_attach, + attachment_to_diddoc, construct_response_v1_0, construct_response_v1_1, ddo_to_attach, + jws_sign_attach, }, states::{completed::Completed, responder::response_sent::ResponseSent}, transition::{transition_error::TransitionError, transition_result::TransitionResult}, @@ -25,19 +31,23 @@ impl DidExchangeResponder { pub async fn receive_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: Request, + request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, - ) -> Result, Response>, AriesVcxError> { - info!( - "DidExchangeResponder::receive_request >> request: {}, our_peer_did: \ + ) -> Result, AnyResponse>, AriesVcxError> + { + debug!( + "DidExchangeResponder::receive_request >> request: {:?}, our_peer_did: \ {}, invitation_key: {:?}", request, our_peer_did, invitation_key ); + let version = request.get_version_marker(); + let request = request.into_v1_1(); + let their_ddo = resolve_ddo_from_request(&resolver_registry, &request).await?; let our_did_document = our_peer_did.resolve_did_doc()?; - // TODO: Check amendment made to did-exchange protocol in terms of rotating keys. - // When keys are rotated, there's a new decorator which conveys that + + // TODO - use v1.1 rotate attach if possible let ddo_attachment_unsigned = ddo_to_attach(our_did_document.clone())?; let ddo_attachment = match invitation_key { None => { @@ -54,9 +64,21 @@ impl DidExchangeResponder { jws_sign_attach(ddo_attachment_unsigned, invitation_key, wallet).await? } }; - let response = construct_response(request.id.clone(), &our_did_document, ddo_attachment); - info!( - "DidExchangeResponder::receive_request << prepared response: {}", + + let response = match version { + DidExchangeTypeV1::V1_1(_) => AnyResponse::V1_1(construct_response_v1_1( + request.id.clone(), + &our_did_document, + ddo_attachment, + )), + DidExchangeTypeV1::V1_0(_) => AnyResponse::V1_0(construct_response_v1_0( + request.id.clone(), + &our_did_document, + ddo_attachment, + )), + }; + debug!( + "DidExchangeResponder::receive_request << prepared response: {:?}", response ); @@ -72,9 +94,9 @@ impl DidExchangeResponder { }) } - pub fn receive_complete( + pub fn receive_complete( self, - complete: Complete, + complete: Complete, ) -> Result, TransitionError> { if complete.decorators.thread.thid != self.state.request_id { return Err(TransitionError { @@ -95,9 +117,9 @@ impl DidExchangeResponder { } } -async fn resolve_ddo_from_request( +async fn resolve_ddo_from_request( resolver_registry: &Arc, - request: &Request, + request: &Request, ) -> Result { Ok(request .content diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 6930b47148..2daaa41d45 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -147,7 +147,7 @@ async fn did_exchange_test() -> Result<(), Box> { } = DidExchangeResponder::::receive_request( &agent_inviter.wallet, resolver_registry.clone(), - request, + request.into(), &responders_peer_did, Some(invitation_key), ) @@ -162,7 +162,7 @@ async fn did_exchange_test() -> Result<(), Box> { .await .unwrap(); - let responder = responder.receive_complete(complete).unwrap(); + let responder = responder.receive_complete(complete.into_v1_1()).unwrap(); info!("Asserting did document of requester"); assert_key_agreement( diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs index b757eb798f..2424b2c3a4 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/mod.rs @@ -4,6 +4,7 @@ use v1_1::DidExchangeV1_1; pub mod v1_0; pub mod v1_1; +pub mod v1_x; #[derive(Clone, Debug, From, PartialEq)] pub enum DidExchange { diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs index d93e8086f2..cdbd051645 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs @@ -1,29 +1,20 @@ -use serde::{Deserialize, Serialize}; use shared::misc::serde_ignored::SerdeIgnored as NoContent; -use typed_builder::TypedBuilder; use crate::{ - decorators::{thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, }; -pub type Complete = MsgParts; - -// TODO: Pthid is mandatory in this case! -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct CompleteDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} +pub type CompleteDecoratorsV1_0 = CompleteDecorators>; +pub type Complete = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::field_reassign_with_default)] mod tests { + use std::marker::PhantomData; + use serde_json::json; use super::*; @@ -46,10 +37,7 @@ mod tests { } }); - let decorators = CompleteDecorators { - thread, - timing: None, - }; + let decorators = CompleteDecoratorsV1_0::builder().thread(thread).build(); test_utils::test_msg( NoContent, @@ -61,9 +49,10 @@ mod tests { #[test] fn test_extended_complete_message() { - let decorators = CompleteDecorators { + let decorators = CompleteDecoratorsV1_0 { thread: make_extended_thread(), timing: Some(make_extended_timing()), + _marker: PhantomData, }; let expected = json!({ diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs index c342eb0b67..8c003b9ed3 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -6,16 +6,23 @@ pub mod request; pub mod response; use derive_more::From; +use problem_report::ProblemReportContentV1_0; use serde::{de::Error, Deserialize, Serialize}; use shared::misc::serde_ignored::SerdeIgnored as NoContent; use self::{ - complete::{Complete, CompleteDecorators}, - problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, - request::{Request, RequestContent, RequestDecorators}, - response::{Response, ResponseContent, ResponseDecorators}, + complete::{Complete, CompleteDecoratorsV1_0}, + problem_report::ProblemReport, + request::{Request, RequestContentV1_0}, + response::{Response, ResponseContent}, +}; +use super::{ + v1_x::{ + problem_report::ProblemReportDecorators, request::RequestDecorators, + response::ResponseDecorators, + }, + DidExchange, }; -use super::DidExchange; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, @@ -66,10 +73,10 @@ impl DelayedSerde for DidExchangeV1_0 { } } -transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(RequestContentV1_0: RequestDecorators, DidExchangeV1_0, DidExchange); transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0, DidExchange); -transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_0, DidExchange); -transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(ProblemReportContentV1_0: ProblemReportDecorators, DidExchangeV1_0, DidExchange); +transit_to_aries_msg!(NoContent: CompleteDecoratorsV1_0, DidExchangeV1_0, DidExchange); into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs index 598cfba41a..5f4229f4f7 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs @@ -1,54 +1,13 @@ -use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder; - use crate::{ - decorators::{localization::MsgLocalization, thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::v1_x::problem_report::{ + ProblemReportContent, ProblemReportDecorators, + }, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, }; -pub type ProblemReport = MsgParts; - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct ProblemReportContent { - #[serde(rename = "problem-code")] - #[serde(skip_serializing_if = "Option::is_none")] - pub problem_code: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub explain: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum ProblemCode { - RequestNotAccepted, - RequestProcessingError, - ResponseNotAccepted, - ResponseProcessingError, -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct ProblemReportDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, - #[builder(default, setter(strip_option))] - #[serde(rename = "~l10n")] - #[serde(skip_serializing_if = "Option::is_none")] - pub localization: Option, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} - -impl ProblemReportDecorators { - pub fn new(thread: Thread) -> Self { - Self { - thread, - localization: None, - timing: None, - } - } -} +pub type ProblemReportContentV1_0 = ProblemReportContent>; +pub type ProblemReport = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -63,12 +22,13 @@ mod tests { thread::tests::make_extended_thread, timing::tests::make_extended_timing, }, misc::test_utils, + msg_fields::protocols::did_exchange::v1_x::problem_report::ProblemCode, msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContent::default(); + let content = ProblemReportContentV1_0::default(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -86,7 +46,7 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let mut content = ProblemReportContent::default(); + let mut content = ProblemReportContentV1_0::default(); content.problem_code = Some(ProblemCode::RequestNotAccepted); content.explain = Some("test_conn_problem_report_explain".to_owned()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs index 4341770c02..bfd097cd92 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs @@ -1,38 +1,11 @@ -use serde::{Deserialize, Serialize}; -use shared::maybe_known::MaybeKnown; -use typed_builder::TypedBuilder; - use crate::{ - decorators::{ - attachment::Attachment, - thread::{Thread, ThreadGoalCode}, - timing::Timing, - }, + msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, }; -pub type Request = MsgParts; - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct RequestContent { - pub label: String, - pub goal_code: Option>, - pub goal: Option, - pub did: String, // TODO: Use Did - #[serde(rename = "did_doc~attach")] - pub did_doc: Option, -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct RequestDecorators { - #[serde(rename = "~thread")] - #[serde(skip_serializing_if = "Option::is_none")] - pub thread: Option, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} +pub type RequestContentV1_0 = RequestContent>; +pub type Request = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -40,12 +13,13 @@ pub struct RequestDecorators { mod tests { use diddoc_legacy::aries::diddoc::AriesDidDoc; use serde_json::json; + use shared::maybe_known::MaybeKnown; use super::*; use crate::{ decorators::{ - attachment::{AttachmentData, AttachmentType}, - thread::tests::make_extended_thread, + attachment::{Attachment, AttachmentData, AttachmentType}, + thread::{tests::make_extended_thread, ThreadGoalCode}, timing::tests::make_extended_timing, }, misc::test_utils, @@ -53,7 +27,7 @@ mod tests { msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; - pub fn request_content() -> RequestContent { + pub fn request_content() -> RequestContentV1_0 { let did_doc = AriesDidDoc::default(); RequestContent { label: "test_request_label".to_owned(), @@ -71,6 +45,7 @@ mod tests { ) .build(), ), + _marker: std::marker::PhantomData, } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs index 0779b114ac..c4d766b764 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use typed_builder::TypedBuilder; use crate::{ - decorators::{attachment::Attachment, thread::Thread, timing::Timing}, - msg_parts::MsgParts, + decorators::attachment::Attachment, + msg_fields::protocols::did_exchange::v1_x::response::ResponseDecorators, msg_parts::MsgParts, }; pub type Response = MsgParts; @@ -15,16 +15,6 @@ pub struct ResponseContent { pub did_doc: Option, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, TypedBuilder)] -pub struct ResponseDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} - #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::field_reassign_with_default)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs index de235d37bc..955ad600ad 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs @@ -1,29 +1,20 @@ -use serde::{Deserialize, Serialize}; use shared::misc::serde_ignored::SerdeIgnored as NoContent; -use typed_builder::TypedBuilder; use crate::{ - decorators::{thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, }; -pub type Complete = MsgParts; - -// TODO: Pthid is mandatory in this case! -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct CompleteDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} +pub type CompleteDecoratorsV1_1 = CompleteDecorators>; +pub type Complete = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::field_reassign_with_default)] mod tests { + use std::marker::PhantomData; + use serde_json::json; use super::*; @@ -46,10 +37,7 @@ mod tests { } }); - let decorators = CompleteDecorators { - thread, - timing: None, - }; + let decorators = CompleteDecoratorsV1_1::builder().thread(thread).build(); test_utils::test_msg( NoContent, @@ -61,9 +49,10 @@ mod tests { #[test] fn test_extended_complete_message() { - let decorators = CompleteDecorators { + let decorators = CompleteDecoratorsV1_1 { thread: make_extended_thread(), timing: Some(make_extended_timing()), + _marker: PhantomData, }; let expected = json!({ diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs index 5985d69eef..6438977d43 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs @@ -10,12 +10,18 @@ use serde::{de::Error, Deserialize, Serialize}; use shared::misc::serde_ignored::SerdeIgnored as NoContent; use self::{ - complete::{Complete, CompleteDecorators}, - problem_report::{ProblemReport, ProblemReportContent, ProblemReportDecorators}, - request::{Request, RequestContent, RequestDecorators}, - response::{Response, ResponseContent, ResponseDecorators}, + complete::{Complete, CompleteDecoratorsV1_1}, + problem_report::{ProblemReport, ProblemReportContentV1_1}, + request::{Request, RequestContentV1_1}, + response::{Response, ResponseContent}, +}; +use super::{ + v1_x::{ + problem_report::ProblemReportDecorators, request::RequestDecorators, + response::ResponseDecorators, + }, + DidExchange, }; -use super::DidExchange; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, @@ -66,11 +72,10 @@ impl DelayedSerde for DidExchangeV1_1 { } } -// TODO: Seems to be required only for tests? -transit_to_aries_msg!(RequestContent: RequestDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(RequestContentV1_1: RequestDecorators, DidExchangeV1_1, DidExchange); transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_1, DidExchange); -transit_to_aries_msg!(ProblemReportContent: ProblemReportDecorators, DidExchangeV1_1, DidExchange); -transit_to_aries_msg!(NoContent: CompleteDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(ProblemReportContentV1_1: ProblemReportDecorators, DidExchangeV1_1, DidExchange); +transit_to_aries_msg!(NoContent: CompleteDecoratorsV1_1, DidExchangeV1_1, DidExchange); into_msg_with_type!(Request, DidExchangeTypeV1_1, Request); into_msg_with_type!(Response, DidExchangeTypeV1_1, Response); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs index a132ea653f..794894274c 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs @@ -1,54 +1,13 @@ -use serde::{Deserialize, Serialize}; -use typed_builder::TypedBuilder; - use crate::{ - decorators::{localization::MsgLocalization, thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::v1_x::problem_report::{ + ProblemReportContent, ProblemReportDecorators, + }, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, }; -pub type ProblemReport = MsgParts; - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct ProblemReportContent { - #[serde(rename = "problem-code")] - #[serde(skip_serializing_if = "Option::is_none")] - pub problem_code: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub explain: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum ProblemCode { - RequestNotAccepted, - RequestProcessingError, - ResponseNotAccepted, - ResponseProcessingError, -} - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct ProblemReportDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, - #[builder(default, setter(strip_option))] - #[serde(rename = "~l10n")] - #[serde(skip_serializing_if = "Option::is_none")] - pub localization: Option, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} - -impl ProblemReportDecorators { - pub fn new(thread: Thread) -> Self { - Self { - thread, - localization: None, - timing: None, - } - } -} +pub type ProblemReportContentV1_1 = ProblemReportContent>; +pub type ProblemReport = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -63,12 +22,15 @@ mod tests { thread::tests::make_extended_thread, timing::tests::make_extended_timing, }, misc::test_utils, + msg_fields::protocols::did_exchange::v1_x::problem_report::{ + ProblemCode, ProblemReportDecorators, + }, msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContent::default(); + let content = ProblemReportContentV1_1::default(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -86,7 +48,7 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let mut content = ProblemReportContent::default(); + let mut content = ProblemReportContentV1_1::default(); content.problem_code = Some(ProblemCode::RequestNotAccepted); content.explain = Some("test_conn_problem_report_explain".to_owned()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs index afd42afe83..6e95ab4fb3 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs @@ -1,38 +1,11 @@ -use serde::{Deserialize, Serialize}; -use shared::maybe_known::MaybeKnown; -use typed_builder::TypedBuilder; - use crate::{ - decorators::{ - attachment::Attachment, - thread::{Thread, ThreadGoalCode}, - timing::Timing, - }, + msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, }; -pub type Request = MsgParts; - -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct RequestContent { - pub label: String, - pub goal_code: Option>, - pub goal: Option, - pub did: String, // TODO: Use Did - #[serde(rename = "did_doc~attach")] - pub did_doc: Option, -} - -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct RequestDecorators { - #[serde(rename = "~thread")] - #[serde(skip_serializing_if = "Option::is_none")] - pub thread: Option, - #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, -} +pub type RequestContentV1_1 = RequestContent>; +pub type Request = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -40,12 +13,13 @@ pub struct RequestDecorators { mod tests { use diddoc_legacy::aries::diddoc::AriesDidDoc; use serde_json::json; + use shared::maybe_known::MaybeKnown; use super::*; use crate::{ decorators::{ - attachment::{AttachmentData, AttachmentType}, - thread::tests::make_extended_thread, + attachment::{Attachment, AttachmentData, AttachmentType}, + thread::{tests::make_extended_thread, ThreadGoalCode}, timing::tests::make_extended_timing, }, misc::test_utils, @@ -53,7 +27,7 @@ mod tests { msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; - pub fn request_content() -> RequestContent { + pub fn request_content() -> RequestContentV1_1 { let did_doc = AriesDidDoc::default(); RequestContent { label: "test_request_label".to_owned(), @@ -71,6 +45,7 @@ mod tests { ) .build(), ), + _marker: std::marker::PhantomData, } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs index f62a9309c5..a6413265a1 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs @@ -2,8 +2,8 @@ use serde::{Deserialize, Serialize}; use typed_builder::TypedBuilder; use crate::{ - decorators::{attachment::Attachment, thread::Thread, timing::Timing}, - msg_parts::MsgParts, + decorators::attachment::Attachment, + msg_fields::protocols::did_exchange::v1_x::response::ResponseDecorators, msg_parts::MsgParts, }; pub type Response = MsgParts; @@ -12,19 +12,11 @@ pub type Response = MsgParts; pub struct ResponseContent { pub did: String, // TODO: Use Did #[serde(rename = "did_doc~attach")] + #[builder(default, setter(strip_option))] pub did_doc: Option, #[serde(rename = "did_rotate~attach")] - pub did_rotate: Option, -} - -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, TypedBuilder)] -pub struct ResponseDecorators { - #[serde(rename = "~thread")] - pub thread: Thread, #[builder(default, setter(strip_option))] - #[serde(rename = "~timing")] - #[serde(skip_serializing_if = "Option::is_none")] - pub timing: Option, + pub did_rotate: Option, } #[cfg(test)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs new file mode 100644 index 0000000000..314a9f86aa --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs @@ -0,0 +1,144 @@ +use std::marker::PhantomData; + +use serde::{Deserialize, Serialize}; +use shared::misc::serde_ignored::SerdeIgnored as NoContent; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::{ + v1_0::{complete::Complete as CompleteV1_0, DidExchangeV1_0}, + v1_1::{ + complete::{Complete as CompleteV1_1, CompleteDecoratorsV1_1}, + DidExchangeV1_1, + }, + DidExchange, + }, + msg_parts::MsgParts, + msg_types::protocols::did_exchange::DidExchangeTypeV1, + AriesMessage, +}; + +pub type Complete = MsgParts>; + +// TODO: Pthid is mandatory in this case! +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct CompleteDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, + #[builder(default, setter(skip))] + #[serde(skip)] + pub(crate) _marker: PhantomData, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] +#[serde(untagged)] +pub enum AnyComplete { + V1_0(CompleteV1_0), + V1_1(CompleteV1_1), +} + +impl AnyComplete { + pub fn get_version_marker(&self) -> DidExchangeTypeV1 { + match self { + AnyComplete::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyComplete::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } + + pub fn into_v1_1(self) -> CompleteV1_1 { + match self { + AnyComplete::V1_0(r) => r.into_v1_1(), + AnyComplete::V1_1(r) => r, + } + } +} + +impl CompleteV1_0 { + pub fn into_v1_1(self) -> CompleteV1_1 { + CompleteV1_1 { + id: self.id, + content: self.content, + decorators: CompleteDecoratorsV1_1 { + thread: self.decorators.thread, + timing: self.decorators.timing, + _marker: PhantomData, + }, + } + } +} + +impl From for AriesMessage { + fn from(value: AnyComplete) -> Self { + match value { + AnyComplete::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Complete(inner)).into(), + AnyComplete::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Complete(inner)).into(), + } + } +} + +// #[cfg(test)] +// #[allow(clippy::unwrap_used)] +// #[allow(clippy::field_reassign_with_default)] +// mod tests { +// use serde_json::json; + +// use super::*; +// use crate::{ +// decorators::{ +// thread::tests::{make_extended_thread, make_minimal_thread}, +// timing::tests::make_extended_timing, +// }, +// misc::test_utils, +// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, +// }; + +// #[test] +// fn test_minimal_complete_message() { +// let thread = make_minimal_thread(); + +// let expected = json!({ +// "~thread": { +// "thid": thread.thid +// } +// }); + +// let decorators = CompleteDecorators { +// thread, +// timing: None, +// _marker: PhantomData::<()>, +// }; + +// test_utils::test_msg( +// NoContent, +// decorators, +// DidExchangeTypeV1_0::Complete, +// expected, +// ); +// } + +// #[test] +// fn test_extended_complete_message() { +// let decorators = CompleteDecorators { +// thread: make_extended_thread(), +// timing: Some(make_extended_timing()), +// _marker: PhantomData::<()>, +// }; + +// let expected = json!({ +// "~thread": serde_json::to_value(make_extended_thread()).unwrap(), +// "~timing": serde_json::to_value(make_extended_timing()).unwrap() +// }); + +// test_utils::test_msg( +// NoContent, +// decorators, +// DidExchangeTypeV1_0::Complete, +// expected, +// ); +// } +// } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/mod.rs new file mode 100644 index 0000000000..66f957c85a --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/mod.rs @@ -0,0 +1,7 @@ +//! Common components for V1.X DIDExchange messages (v1.0 & v1.1). +//! Necessary to prevent duplicated code, since most types between v1.0 & v1.1 are identical + +pub mod complete; +pub mod problem_report; +pub mod request; +pub mod response; diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs new file mode 100644 index 0000000000..da807565bb --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs @@ -0,0 +1,178 @@ +use std::marker::PhantomData; + +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{localization::MsgLocalization, thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::{ + v1_0::{problem_report::ProblemReport as ProblemReportV1_0, DidExchangeV1_0}, + v1_1::{ + problem_report::{ProblemReport as ProblemReportV1_1, ProblemReportContentV1_1}, + DidExchangeV1_1, + }, + DidExchange, + }, + msg_parts::MsgParts, + msg_types::protocols::did_exchange::DidExchangeTypeV1, + AriesMessage, +}; + +pub type ProblemReport = + MsgParts, ProblemReportDecorators>; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] +#[serde(untagged)] +pub enum AnyProblemReport { + V1_0(ProblemReportV1_0), + V1_1(ProblemReportV1_1), +} + +impl AnyProblemReport { + pub fn get_version_marker(&self) -> DidExchangeTypeV1 { + match self { + AnyProblemReport::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyProblemReport::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } + + pub fn into_v1_1(self) -> ProblemReportV1_1 { + match self { + AnyProblemReport::V1_0(r) => r.into_v1_1(), + AnyProblemReport::V1_1(r) => r, + } + } +} + +impl ProblemReportV1_0 { + pub fn into_v1_1(self) -> ProblemReportV1_1 { + ProblemReportV1_1 { + id: self.id, + content: ProblemReportContentV1_1 { + problem_code: self.content.problem_code, + explain: self.content.explain, + _marker: PhantomData, + }, + decorators: self.decorators, + } + } +} + +impl From for AriesMessage { + fn from(value: AnyProblemReport) -> Self { + match value { + AnyProblemReport::V1_0(inner) => { + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(inner)).into() + } + AnyProblemReport::V1_1(inner) => { + DidExchange::V1_1(DidExchangeV1_1::ProblemReport(inner)).into() + } + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct ProblemReportContent { + #[serde(rename = "problem-code")] + #[serde(skip_serializing_if = "Option::is_none")] + pub problem_code: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub explain: Option, + #[builder(default)] + #[serde(skip)] + pub(crate) _marker: PhantomData, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "snake_case")] +pub enum ProblemCode { + RequestNotAccepted, + RequestProcessingError, + ResponseNotAccepted, + ResponseProcessingError, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct ProblemReportDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~l10n")] + #[serde(skip_serializing_if = "Option::is_none")] + pub localization: Option, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +impl ProblemReportDecorators { + pub fn new(thread: Thread) -> Self { + Self { + thread, + localization: None, + timing: None, + } + } +} + +// #[cfg(test)] +// #[allow(clippy::unwrap_used)] +// #[allow(clippy::field_reassign_with_default)] +// mod tests { +// use serde_json::json; + +// use super::*; +// use crate::{ +// decorators::{ +// localization::tests::make_extended_msg_localization, +// thread::tests::make_extended_thread, timing::tests::make_extended_timing, +// }, +// misc::test_utils, +// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, +// }; + +// #[test] +// fn test_minimal_conn_problem_report() { +// let content = ProblemReportContent::<()>::default(); + +// let decorators = ProblemReportDecorators::new(make_extended_thread()); + +// let expected = json!({ +// "~thread": decorators.thread +// }); + +// test_utils::test_msg( +// content, +// decorators, +// DidExchangeTypeV1_0::ProblemReport, +// expected, +// ); +// } + +// #[test] +// fn test_extended_conn_problem_report() { +// let mut content = ProblemReportContent::<()>::default(); +// content.problem_code = Some(ProblemCode::RequestNotAccepted); +// content.explain = Some("test_conn_problem_report_explain".to_owned()); + +// let mut decorators = ProblemReportDecorators::new(make_extended_thread()); +// decorators.timing = Some(make_extended_timing()); +// decorators.localization = Some(make_extended_msg_localization()); + +// let expected = json!({ +// "problem-code": content.problem_code, +// "explain": content.explain, +// "~thread": decorators.thread, +// "~timing": decorators.timing, +// "~l10n": decorators.localization +// }); + +// test_utils::test_msg( +// content, +// decorators, +// DidExchangeTypeV1_0::ProblemReport, +// expected, +// ); +// } +// } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs new file mode 100644 index 0000000000..781128b4ff --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs @@ -0,0 +1,191 @@ +use std::marker::PhantomData; + +use serde::{Deserialize, Serialize}; +use shared::maybe_known::MaybeKnown; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{ + attachment::Attachment, + thread::{Thread, ThreadGoalCode}, + timing::Timing, + }, + msg_fields::protocols::did_exchange::{ + v1_0::{request::Request as RequestV1_0, DidExchangeV1_0}, + v1_1::{ + request::{Request as RequestV1_1, RequestContentV1_1}, + DidExchangeV1_1, + }, + DidExchange, + }, + msg_parts::MsgParts, + msg_types::protocols::did_exchange::DidExchangeTypeV1, + AriesMessage, +}; + +pub type Request = MsgParts, RequestDecorators>; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct RequestContent { + pub label: String, + pub goal_code: Option>, + pub goal: Option, + pub did: String, // TODO: Use Did + #[serde(rename = "did_doc~attach")] + pub did_doc: Option, + #[builder(default)] + #[serde(skip)] + pub(crate) _marker: PhantomData, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct RequestDecorators { + #[serde(rename = "~thread")] + #[serde(skip_serializing_if = "Option::is_none")] + pub thread: Option, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] +#[serde(untagged)] +pub enum AnyRequest { + V1_0(RequestV1_0), + V1_1(RequestV1_1), +} + +impl AnyRequest { + pub fn get_version_marker(&self) -> DidExchangeTypeV1 { + match self { + AnyRequest::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyRequest::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } + + pub fn into_v1_1(self) -> RequestV1_1 { + match self { + AnyRequest::V1_0(r) => r.into_v1_1(), + AnyRequest::V1_1(r) => r, + } + } +} + +impl RequestV1_0 { + pub fn into_v1_1(self) -> RequestV1_1 { + RequestV1_1 { + id: self.id, + content: RequestContentV1_1 { + label: self.content.label, + goal_code: self.content.goal_code, + goal: self.content.goal, + did: self.content.did, + did_doc: self.content.did_doc, + _marker: PhantomData, + }, + decorators: self.decorators, + } + } +} + +impl From for AriesMessage { + fn from(value: AnyRequest) -> Self { + match value { + AnyRequest::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Request(inner)).into(), + AnyRequest::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Request(inner)).into(), + } + } +} + +// #[cfg(test)] +// #[allow(clippy::unwrap_used)] +// #[allow(clippy::field_reassign_with_default)] +// mod tests { +// use diddoc_legacy::aries::diddoc::AriesDidDoc; +// use serde_json::json; + +// use super::*; +// use crate::{ +// decorators::{ +// attachment::{AttachmentData, AttachmentType}, +// thread::tests::make_extended_thread, +// timing::tests::make_extended_timing, +// }, +// misc::test_utils, +// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, +// }; + +// pub fn request_content() -> RequestContent<()> { +// let did_doc = AriesDidDoc::default(); +// RequestContent { +// label: "test_request_label".to_owned(), +// goal_code: Some(MaybeKnown::Known(ThreadGoalCode::AriesRelBuild)), +// goal: Some("test_goal".to_owned()), +// did: did_doc.id.clone(), +// did_doc: Some( +// Attachment::builder() +// .data( +// AttachmentData::builder() +// .content(AttachmentType::Json( +// serde_json::to_value(&did_doc).unwrap(), +// )) +// .build(), +// ) +// .build(), +// ), +// _marker: PhantomData, +// } +// } + +// #[test] +// fn test_print_message() { +// let msg: Request<_> = Request::<()>::builder() +// .id("test_id".to_owned()) +// .content(request_content()) +// .decorators(RequestDecorators::default()) +// .build(); +// let printed_json = format!("{}", msg); +// let parsed_request: Request<_> = serde_json::from_str(&printed_json).unwrap(); +// assert_eq!(msg, parsed_request); +// } + +// #[test] +// fn test_minimal_didexchange_request() { +// let content = request_content(); +// let expected = json!({ +// "label": content.label, +// "goal_code": content.goal_code, +// "goal": content.goal, +// "did": content.did, +// "did_doc~attach": content.did_doc, +// }); +// test_utils::test_msg( +// content, +// RequestDecorators::default(), +// DidExchangeTypeV1_0::Request, +// expected, +// ); +// } + +// #[test] +// fn test_extended_didexchange_request() { +// let content = request_content(); + +// let mut decorators = RequestDecorators::default(); +// decorators.thread = Some(make_extended_thread()); +// decorators.timing = Some(make_extended_timing()); + +// let expected = json!({ +// "label": content.label, +// "goal_code": content.goal_code, +// "goal": content.goal, +// "did": content.did, +// "did_doc~attach": content.did_doc, +// "~thread": decorators.thread, +// "~timing": decorators.timing +// }); + +// test_utils::test_msg(content, decorators, DidExchangeTypeV1_0::Request, expected); +// } +// } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs new file mode 100644 index 0000000000..cf6bcc3588 --- /dev/null +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs @@ -0,0 +1,72 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + decorators::{thread::Thread, timing::Timing}, + msg_fields::protocols::did_exchange::{ + v1_0::{response::Response as ResponseV1_0, DidExchangeV1_0}, + v1_1::{ + response::{Response as ResponseV1_1, ResponseContent as ResponseV1_1Content}, + DidExchangeV1_1, + }, + DidExchange, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, + AriesMessage, +}; + +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] +#[serde(untagged)] +pub enum AnyResponse { + V1_0(ResponseV1_0), + V1_1(ResponseV1_1), +} + +impl AnyResponse { + pub fn get_version_marker(&self) -> DidExchangeTypeV1 { + match self { + AnyResponse::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyResponse::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } + + pub fn into_v1_1(self) -> ResponseV1_1 { + match self { + AnyResponse::V1_0(r) => r.into_v1_1(), + AnyResponse::V1_1(r) => r, + } + } +} + +impl ResponseV1_0 { + pub fn into_v1_1(self) -> ResponseV1_1 { + ResponseV1_1 { + id: self.id, + decorators: self.decorators, + content: ResponseV1_1Content { + did: self.content.did, + did_doc: self.content.did_doc, + did_rotate: None, + }, + } + } +} + +impl From for AriesMessage { + fn from(value: AnyResponse) -> Self { + match value { + AnyResponse::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Response(inner)).into(), + AnyResponse::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Response(inner)).into(), + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, TypedBuilder)] +pub struct ResponseDecorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default, setter(strip_option))] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} diff --git a/aries/messages/src/msg_types/mod.rs b/aries/messages/src/msg_types/mod.rs index ad77a324e8..56bf0283c8 100644 --- a/aries/messages/src/msg_types/mod.rs +++ b/aries/messages/src/msg_types/mod.rs @@ -142,3 +142,9 @@ where kind_str.parse() } } + +impl Default for MsgKindType { + fn default() -> Self { + Self(Default::default()) + } +} From 807e4251d4beb196fb530ce36852622871075ca3 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 10:35:19 +1000 Subject: [PATCH 04/32] simplify generics Signed-off-by: George Mulhearn --- .../protocols/did_exchange/v1_0/complete.rs | 7 +++---- .../did_exchange/v1_0/problem_report.rs | 16 ++++++++++------ .../protocols/did_exchange/v1_0/request.rs | 4 ++-- .../protocols/did_exchange/v1_1/complete.rs | 7 +++---- .../did_exchange/v1_1/problem_report.rs | 16 ++++++++++------ .../protocols/did_exchange/v1_1/request.rs | 4 ++-- .../did_exchange/v1_x/problem_report.rs | 2 +- .../protocols/did_exchange/v1_x/request.rs | 2 +- 8 files changed, 32 insertions(+), 26 deletions(-) diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs index cdbd051645..58c9f109ce 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs @@ -1,12 +1,11 @@ use shared::misc::serde_ignored::SerdeIgnored as NoContent; use crate::{ - msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, - msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, + msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type CompleteDecoratorsV1_0 = CompleteDecorators>; +pub type CompleteDecoratorsV1_0 = CompleteDecorators; pub type Complete = MsgParts; #[cfg(test)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs index 5f4229f4f7..e0f642953b 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs @@ -3,10 +3,10 @@ use crate::{ ProblemReportContent, ProblemReportDecorators, }, msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type ProblemReportContentV1_0 = ProblemReportContent>; +pub type ProblemReportContentV1_0 = ProblemReportContent; pub type ProblemReport = MsgParts; #[cfg(test)] @@ -28,7 +28,10 @@ mod tests { #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContentV1_0::default(); + let content = ProblemReportContentV1_0::builder() + .problem_code(None) + .explain(None) + .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -46,9 +49,10 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let mut content = ProblemReportContentV1_0::default(); - content.problem_code = Some(ProblemCode::RequestNotAccepted); - content.explain = Some("test_conn_problem_report_explain".to_owned()); + let content = ProblemReportContentV1_0::builder() + .problem_code(Some(ProblemCode::RequestNotAccepted)) + .explain(Some("test_conn_problem_report_explain".to_owned())) + .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); decorators.timing = Some(make_extended_timing()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs index bfd097cd92..44ece35a67 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs @@ -1,10 +1,10 @@ use crate::{ msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type RequestContentV1_0 = RequestContent>; +pub type RequestContentV1_0 = RequestContent; pub type Request = MsgParts; #[cfg(test)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs index 955ad600ad..677af8d99e 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs @@ -1,12 +1,11 @@ use shared::misc::serde_ignored::SerdeIgnored as NoContent; use crate::{ - msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, - msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, + msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type CompleteDecoratorsV1_1 = CompleteDecorators>; +pub type CompleteDecoratorsV1_1 = CompleteDecorators; pub type Complete = MsgParts; #[cfg(test)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs index 794894274c..cfad5f9929 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs @@ -3,10 +3,10 @@ use crate::{ ProblemReportContent, ProblemReportDecorators, }, msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type ProblemReportContentV1_1 = ProblemReportContent>; +pub type ProblemReportContentV1_1 = ProblemReportContent; pub type ProblemReport = MsgParts; #[cfg(test)] @@ -30,7 +30,10 @@ mod tests { #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContentV1_1::default(); + let content = ProblemReportContentV1_1::builder() + .problem_code(None) + .explain(None) + .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -48,9 +51,10 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let mut content = ProblemReportContentV1_1::default(); - content.problem_code = Some(ProblemCode::RequestNotAccepted); - content.explain = Some("test_conn_problem_report_explain".to_owned()); + let content = ProblemReportContentV1_1::builder() + .problem_code(Some(ProblemCode::RequestNotAccepted)) + .explain(Some("test_conn_problem_report_explain".to_owned())) + .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); decorators.timing = Some(make_extended_timing()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs index 6e95ab4fb3..eff14876e4 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs @@ -1,10 +1,10 @@ use crate::{ msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type RequestContentV1_1 = RequestContent>; +pub type RequestContentV1_1 = RequestContent; pub type Request = MsgParts; #[cfg(test)] diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs index da807565bb..b24fcce7a0 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs @@ -78,7 +78,7 @@ pub struct ProblemReportContent { pub problem_code: Option, #[serde(skip_serializing_if = "Option::is_none")] pub explain: Option, - #[builder(default)] + #[builder(default, setter(skip))] #[serde(skip)] pub(crate) _marker: PhantomData, } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs index 781128b4ff..3afaf1be55 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs @@ -33,7 +33,7 @@ pub struct RequestContent { pub did: String, // TODO: Use Did #[serde(rename = "did_doc~attach")] pub did_doc: Option, - #[builder(default)] + #[builder(default, setter(skip))] #[serde(skip)] pub(crate) _marker: PhantomData, } From e8b4e057c39bfd728f2badb83468d0adda5af6f9 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 12:02:10 +1000 Subject: [PATCH 05/32] change approach to use runtime versioning rather than generics Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 21 +-- .../src/handlers/did_exchange.rs | 27 +-- .../did_exchange/state_machine/generic/mod.rs | 20 +-- .../did_exchange/state_machine/mod.rs | 6 +- .../state_machine/requester/helpers.rs | 10 +- .../requester/request_sent/mod.rs | 22 ++- .../responder/response_sent/mod.rs | 17 +- aries/aries_vcx/tests/test_did_exchange.rs | 2 +- .../protocols/did_exchange/v1_0/complete.rs | 21 ++- .../protocols/did_exchange/v1_0/mod.rs | 49 +++--- .../did_exchange/v1_0/problem_report.rs | 16 +- .../protocols/did_exchange/v1_0/request.rs | 19 +- .../protocols/did_exchange/v1_0/response.rs | 2 +- .../protocols/did_exchange/v1_1/complete.rs | 21 ++- .../protocols/did_exchange/v1_1/mod.rs | 52 +++--- .../did_exchange/v1_1/problem_report.rs | 16 +- .../protocols/did_exchange/v1_1/request.rs | 14 +- .../protocols/did_exchange/v1_1/response.rs | 9 +- .../protocols/did_exchange/v1_x/complete.rs | 135 +++----------- .../did_exchange/v1_x/problem_report.rs | 151 +++------------- .../protocols/did_exchange/v1_x/request.rs | 164 ++---------------- .../protocols/did_exchange/v1_x/response.rs | 2 +- 22 files changed, 246 insertions(+), 550 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index f0c37ceb7f..e2fa3560b6 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -5,7 +5,7 @@ use aries_vcx_agent::aries_vcx::{ did_parser_nom::Did, messages::{ msg_fields::protocols::did_exchange::{ - v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::AnyRequest, DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::Request, DidExchange, }, AriesMessage, }, @@ -51,7 +51,7 @@ impl HarnessAgent { Ok(json!({ "connection_id" : connection_id }).to_string()) } - pub fn queue_didexchange_request(&self, request: AnyRequest) -> HarnessResult<()> { + pub fn queue_didexchange_request(&self, request: Request) -> HarnessResult<()> { info!("queue_didexchange_request >> request: {:?}", request); let mut msg_buffer = self.didx_msg_buffer.write().map_err(|_| { HarnessError::from_msg( @@ -144,12 +144,12 @@ impl HarnessAgent { ) })? }; - let request: AnyRequest = match request { + let request = match request { AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) => { - request.into() + request } AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { - request.into() + request } _ => { return Err(HarnessError::from_msg( @@ -159,14 +159,11 @@ impl HarnessAgent { } }; - let request_thread = match request { - AnyRequest::V1_0(ref inner) => &inner.decorators.thread, - AnyRequest::V1_1(ref inner) => &inner.decorators.thread, - }; + let request_thread = &request.decorators.thread; - let opt_invitation = match request_thread.clone().and_then(|th| th.pthid) { + let opt_invitation = match request_thread.as_ref().and_then(|th| th.pthid.as_ref()) { Some(pthid) => { - let invitation = self.aries_agent.out_of_band().get_invitation(&pthid)?; + let invitation = self.aries_agent.out_of_band().get_invitation(pthid)?; Some(invitation) } None => None, @@ -174,7 +171,7 @@ impl HarnessAgent { let (thid, pthid) = self .aries_agent .did_exchange() - .handle_msg_request(request.clone(), opt_invitation) + .handle_msg_request(request, opt_invitation) .await?; if let Some(pthid) = pthid { diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index 9f08247fce..e984c6b0c4 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -6,7 +6,7 @@ use aries_vcx::{ messages::{ msg_fields::protocols::{ did_exchange::v1_x::{ - complete::Complete, problem_report::ProblemReport, request::AnyRequest, + complete::Complete, problem_report::ProblemReport, request::Request, response::AnyResponse, }, out_of_band::invitation::Invitation as OobInvitation, @@ -134,26 +134,23 @@ impl DidcommHandlerDidExchange { // rather than being supplied by upper layers pub async fn handle_msg_request( &self, - request: AnyRequest, + request: Request, invitation: Option, ) -> AgentResult<(String, Option)> { // todo: type the return type // Todo: messages should expose fallible API to get thid (for any aries msg). It's common // pattern - let thread = match request { - AnyRequest::V1_0(ref inner) => &inner.decorators.thread, - AnyRequest::V1_1(ref inner) => &inner.decorators.thread, - }; + let thread = request.decorators.thread.as_ref(); let thid = thread - .clone() .ok_or_else(|| { AgentError::from_msg( AgentErrorKind::InvalidState, "Request did not contain a thread id", ) })? - .thid; + .thid + .clone(); // Todo: "invitation_key" should not be None; see the todo inside this scope let invitation_key = match invitation { @@ -172,14 +169,14 @@ impl DidcommHandlerDidExchange { create_peer_did_4(self.wallet.as_ref(), self.service_endpoint.clone(), vec![]).await?; let pthid = thread - .clone() .ok_or_else(|| { AgentError::from_msg( AgentErrorKind::InvalidState, "Request did not contain a thread", ) })? - .pthid; + .pthid + .clone(); let (responder, response) = GenericDidExchange::handle_request( self.wallet.as_ref(), @@ -255,20 +252,14 @@ impl DidcommHandlerDidExchange { Ok(thid) } - pub fn handle_msg_complete( - &self, - complete: Complete, - ) -> AgentResult { + pub fn handle_msg_complete(&self, complete: Complete) -> AgentResult { let thread_id = complete.decorators.thread.thid.clone(); let (requester, _) = self.did_exchange.get(&thread_id)?; let requester = requester.handle_complete(complete)?; self.did_exchange.insert(&thread_id, (requester, None)) } - pub fn receive_problem_report( - &self, - problem_report: ProblemReport, - ) -> AgentResult { + pub fn receive_problem_report(&self, problem_report: ProblemReport) -> AgentResult { let thread_id = problem_report.decorators.thread.thid.clone(); let (requester, _) = self.did_exchange.get(&thread_id)?; let requester = requester.handle_problem_report(problem_report)?; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index 2cb6c8f259..3c0978d660 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -7,12 +7,7 @@ use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; use messages::msg_fields::protocols::did_exchange::{ v1_1::request::Request, - v1_x::{ - complete::{AnyComplete, Complete}, - problem_report::ProblemReport, - request::AnyRequest, - response::AnyResponse, - }, + v1_x::{complete::Complete, problem_report::ProblemReport, response::AnyResponse}, }; use public_key::Key; pub use thin_state::ThinState; @@ -112,7 +107,7 @@ impl GenericDidExchange { pub async fn handle_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: AnyRequest, + request: Request, our_peer_did: &PeerDid, invitation_key: Option, ) -> Result<(Self, AnyResponse), AriesVcxError> { @@ -135,7 +130,7 @@ impl GenericDidExchange { self, response: AnyResponse, resolver_registry: Arc, - ) -> Result<(Self, AnyComplete), (Self, AriesVcxError)> { + ) -> Result<(Self, Complete), (Self, AriesVcxError)> { match self { GenericDidExchange::Requester(requester_state) => match requester_state { RequesterState::RequestSent(request_sent_state) => { @@ -178,10 +173,7 @@ impl GenericDidExchange { } } - pub fn handle_complete( - self, - complete: Complete, - ) -> Result { + pub fn handle_complete(self, complete: Complete) -> Result { match self { GenericDidExchange::Responder(responder_state) => match responder_state { ResponderState::ResponseSent(response_sent_state) => { @@ -220,9 +212,9 @@ impl GenericDidExchange { } } - pub fn handle_problem_report( + pub fn handle_problem_report( self, - problem_report: ProblemReport, + problem_report: ProblemReport, ) -> Result { match self { GenericDidExchange::Requester(requester_state) => match requester_state { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs index d3882efdd9..6d585b2a82 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs @@ -16,6 +16,7 @@ use messages::{ ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, }, }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use uuid::Uuid; @@ -45,6 +46,7 @@ impl DidExchange { let content = ProblemReportContent::builder() .problem_code(problem_code) .explain(Some(reason.clone())) + .version(DidExchangeTypeV1::new_v1_1()) .build(); let decorators = ProblemReportDecorators::builder() .thread( @@ -74,9 +76,9 @@ impl DidExchange { } } - pub fn receive_problem_report( + pub fn receive_problem_report( self, - problem_report: ProblemReport, + problem_report: ProblemReport, ) -> DidExchange { DidExchange { state: Abandoned { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index 95922db98b..6d7fc3f366 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -12,16 +12,18 @@ use messages::{ }, out_of_band::invitation::{Invitation, OobService}, }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use shared::maybe_known::MaybeKnown; use uuid::Uuid; use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; -pub fn construct_request( +pub fn construct_request( invitation_id: Option, our_did: String, -) -> Request { + version: DidExchangeTypeV1, +) -> Request { let msg_id = Uuid::new_v4().to_string(); let thid = msg_id.clone(); let thread = match invitation_id { @@ -38,6 +40,7 @@ pub fn construct_request( .did_doc(None) .goal(Some("To establish a connection".into())) // Rejected if non-empty by acapy .goal_code(Some(MaybeKnown::Known(ThreadGoalCode::AriesRelBuild))) // Rejected if non-empty by acapy + .version(version) .build(); Request::builder() .id(msg_id) @@ -46,7 +49,7 @@ pub fn construct_request( .build() } -pub fn construct_didexchange_complete(request_id: String) -> Complete { +pub fn construct_didexchange_complete(request_id: String, version: DidExchangeTypeV1) -> Complete { // assuming we'd want to support RFC 100% and include pthread in complete message, we can add // new function argument: `invitation_id: Option` // We choose not to do this, as it's rather historic artifact and doesn't have justification in @@ -65,6 +68,7 @@ pub fn construct_didexchange_complete(request_id: String) -> Complete< let decorators = CompleteDecorators::builder() .thread(thread) .timing(Timing::builder().out_time(Utc::now()).build()) + .version(version) .build(); Complete::builder() .id(Uuid::new_v4().to_string()) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 64a413e96a..e55fa904e2 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -7,7 +7,7 @@ use did_resolver_registry::ResolverRegistry; use messages::{ msg_fields::protocols::did_exchange::{ v1_1::request::Request, - v1_x::{complete::AnyComplete, response::AnyResponse}, + v1_x::{complete::Complete, response::AnyResponse}, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -42,7 +42,11 @@ impl DidExchangeRequester { .await? .did_document; let our_did_document = our_peer_did.resolve_did_doc()?; - let request = construct_request(invitation_id.clone(), our_peer_did.to_string()); + let request = construct_request( + invitation_id.clone(), + our_peer_did.to_string(), + DidExchangeTypeV1::new_v1_1(), + ); debug!( "DidExchangeRequester::construct_request << prepared request: {}", @@ -64,13 +68,13 @@ impl DidExchangeRequester { self, response: AnyResponse, resolver_registry: Arc, - ) -> Result, AnyComplete>, TransitionError> + ) -> Result, Complete>, TransitionError> { debug!( "DidExchangeRequester::receive_response >> response: {:?}", response ); - let version = response.get_version_marker(); + let version = response.get_version(); let response = response.into_v1_1(); if response.decorators.thread.thid != self.state.request_id { @@ -103,14 +107,8 @@ impl DidExchangeRequester { did_document }; - let complete_message = match version { - DidExchangeTypeV1::V1_1(_) => AnyComplete::V1_1(construct_didexchange_complete( - self.state.request_id.clone(), - )), - DidExchangeTypeV1::V1_0(_) => AnyComplete::V1_0(construct_didexchange_complete( - self.state.request_id.clone(), - )), - }; + let complete_message = + construct_didexchange_complete(self.state.request_id.clone(), version); debug!( "DidExchangeRequester::receive_response << complete_message: {:?}", complete_message diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 455e033223..6c2fcf90d8 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -6,9 +6,7 @@ use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; use messages::{ msg_fields::protocols::did_exchange::v1_x::{ - complete::Complete, - request::{AnyRequest, Request}, - response::AnyResponse, + complete::Complete, request::Request, response::AnyResponse, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -31,7 +29,7 @@ impl DidExchangeResponder { pub async fn receive_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: AnyRequest, + request: Request, our_peer_did: &PeerDid, invitation_key: Option, ) -> Result, AnyResponse>, AriesVcxError> @@ -41,8 +39,7 @@ impl DidExchangeResponder { {}, invitation_key: {:?}", request, our_peer_did, invitation_key ); - let version = request.get_version_marker(); - let request = request.into_v1_1(); + let version = request.get_version(); let their_ddo = resolve_ddo_from_request(&resolver_registry, &request).await?; let our_did_document = our_peer_did.resolve_did_doc()?; @@ -94,9 +91,9 @@ impl DidExchangeResponder { }) } - pub fn receive_complete( + pub fn receive_complete( self, - complete: Complete, + complete: Complete, ) -> Result, TransitionError> { if complete.decorators.thread.thid != self.state.request_id { return Err(TransitionError { @@ -117,9 +114,9 @@ impl DidExchangeResponder { } } -async fn resolve_ddo_from_request( +async fn resolve_ddo_from_request( resolver_registry: &Arc, - request: &Request, + request: &Request, ) -> Result { Ok(request .content diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 2daaa41d45..5f2c51ea0f 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -162,7 +162,7 @@ async fn did_exchange_test() -> Result<(), Box> { .await .unwrap(); - let responder = responder.receive_complete(complete.into_v1_1()).unwrap(); + let responder = responder.receive_complete(complete).unwrap(); info!("Asserting did document of requester"); assert_key_agreement( diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs index 58c9f109ce..1065fb8dcb 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs @@ -2,18 +2,18 @@ use shared::misc::serde_ignored::SerdeIgnored as NoContent; use crate::{ msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type CompleteDecoratorsV1_0 = CompleteDecorators; -pub type Complete = MsgParts; +/// Alias type for DIDExchange v1.0 Complete message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this message type is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Complete = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::field_reassign_with_default)] mod tests { - use std::marker::PhantomData; - use serde_json::json; use super::*; @@ -23,7 +23,7 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, }; #[test] @@ -36,7 +36,10 @@ mod tests { } }); - let decorators = CompleteDecoratorsV1_0::builder().thread(thread).build(); + let decorators = CompleteDecorators::builder() + .thread(thread) + .version(DidExchangeTypeV1::new_v1_0()) + .build(); test_utils::test_msg( NoContent, @@ -48,10 +51,10 @@ mod tests { #[test] fn test_extended_complete_message() { - let decorators = CompleteDecoratorsV1_0 { + let decorators = CompleteDecorators { thread: make_extended_thread(), timing: Some(make_extended_timing()), - _marker: PhantomData, + version: DidExchangeTypeV1::new_v1_0(), }; let expected = json!({ diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs index 8c003b9ed3..c2f003e7ec 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -6,27 +6,22 @@ pub mod request; pub mod response; use derive_more::From; -use problem_report::ProblemReportContentV1_0; use serde::{de::Error, Deserialize, Serialize}; -use shared::misc::serde_ignored::SerdeIgnored as NoContent; use self::{ - complete::{Complete, CompleteDecoratorsV1_0}, + complete::Complete, problem_report::ProblemReport, - request::{Request, RequestContentV1_0}, + request::Request, response::{Response, ResponseContent}, }; -use super::{ - v1_x::{ - problem_report::ProblemReportDecorators, request::RequestDecorators, - response::ResponseDecorators, - }, - DidExchange, -}; +use super::{v1_x::response::ResponseDecorators, DidExchange}; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType, MsgWithType}, + msg_types::{ + protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, + MsgKindType, MsgWithType, + }, }; #[derive(Clone, Debug, From, PartialEq)] @@ -51,12 +46,21 @@ impl DelayedSerde for DidExchangeV1_0 { let kind = protocol.kind_from_str(kind_str); match kind.map_err(D::Error::custom)? { - DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(|mut c| { + c.content.version = DidExchangeTypeV1::new_v1_0(); + c.into() + }), DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), DidExchangeTypeV1_0::ProblemReport => { - ProblemReport::deserialize(deserializer).map(From::from) + ProblemReport::deserialize(deserializer).map(|mut c| { + c.content.version = DidExchangeTypeV1::new_v1_0(); + c.into() + }) } - DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(|mut c| { + c.decorators.version = DidExchangeTypeV1::new_v1_0(); + c.into() + }), } } @@ -65,18 +69,21 @@ impl DelayedSerde for DidExchangeV1_0 { S: serde::Serializer, { match self { - Self::Request(v) => MsgWithType::from(v).serialize(serializer), + Self::Request(v) => { + MsgWithType::<_, DidExchangeTypeV1_0>::from(v).serialize(serializer) + } Self::Response(v) => MsgWithType::from(v).serialize(serializer), - Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), - Self::Complete(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => { + MsgWithType::<_, DidExchangeTypeV1_0>::from(v).serialize(serializer) + } + Self::Complete(v) => { + MsgWithType::<_, DidExchangeTypeV1_0>::from(v).serialize(serializer) + } } } } -transit_to_aries_msg!(RequestContentV1_0: RequestDecorators, DidExchangeV1_0, DidExchange); transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_0, DidExchange); -transit_to_aries_msg!(ProblemReportContentV1_0: ProblemReportDecorators, DidExchangeV1_0, DidExchange); -transit_to_aries_msg!(NoContent: CompleteDecoratorsV1_0, DidExchangeV1_0, DidExchange); into_msg_with_type!(Request, DidExchangeTypeV1_0, Request); into_msg_with_type!(Response, DidExchangeTypeV1_0, Response); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs index e0f642953b..db06040f23 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs @@ -3,11 +3,13 @@ use crate::{ ProblemReportContent, ProblemReportDecorators, }, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type ProblemReportContentV1_0 = ProblemReportContent; -pub type ProblemReport = MsgParts; +/// Alias type for DIDExchange v1.0 Problem Report message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this message type is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type ProblemReport = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -23,14 +25,15 @@ mod tests { }, misc::test_utils, msg_fields::protocols::did_exchange::v1_x::problem_report::ProblemCode, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, }; #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContentV1_0::builder() + let content = ProblemReportContent::builder() .problem_code(None) .explain(None) + .version(DidExchangeTypeV1::new_v1_0()) .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -49,9 +52,10 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let content = ProblemReportContentV1_0::builder() + let content = ProblemReportContent::builder() .problem_code(Some(ProblemCode::RequestNotAccepted)) .explain(Some("test_conn_problem_report_explain".to_owned())) + .version(DidExchangeTypeV1::new_v1_0()) .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs index 44ece35a67..713ba45fd8 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs @@ -1,11 +1,13 @@ use crate::{ msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; -pub type RequestContentV1_0 = RequestContent; -pub type Request = MsgParts; +/// Alias type for DIDExchange v1.0 Request message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this Request is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Request = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -24,10 +26,10 @@ mod tests { }, misc::test_utils, msg_fields::protocols::did_exchange::v1_0::request::{Request, RequestDecorators}, - msg_types::protocols::did_exchange::DidExchangeTypeV1_0, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, }; - pub fn request_content() -> RequestContentV1_0 { + pub fn request_content() -> RequestContent { let did_doc = AriesDidDoc::default(); RequestContent { label: "test_request_label".to_owned(), @@ -45,7 +47,7 @@ mod tests { ) .build(), ), - _marker: std::marker::PhantomData, + version: DidExchangeTypeV1::new_v1_0(), } } @@ -57,7 +59,10 @@ mod tests { .decorators(RequestDecorators::default()) .build(); let printed_json = format!("{}", msg); - let parsed_request: Request = serde_json::from_str(&printed_json).unwrap(); + let mut parsed_request: Request = serde_json::from_str(&printed_json).unwrap(); + // the serialized format of [Request] directly will not retain the version metadata, + // that information is the responsibility of higher up layers. + parsed_request.content.version = DidExchangeTypeV1::new_v1_0(); assert_eq!(msg, parsed_request); } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs index c4d766b764..77708ee261 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/response.rs @@ -11,7 +11,7 @@ pub type Response = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] pub struct ResponseContent { pub did: String, // TODO: Use Did - #[serde(rename = "did_doc~attach")] + #[serde(rename = "did_doc~attach", skip_serializing_if = "Option::is_none")] pub did_doc: Option, } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs index 677af8d99e..ddddff23e5 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs @@ -2,18 +2,18 @@ use shared::misc::serde_ignored::SerdeIgnored as NoContent; use crate::{ msg_fields::protocols::did_exchange::v1_x::complete::CompleteDecorators, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type CompleteDecoratorsV1_1 = CompleteDecorators; -pub type Complete = MsgParts; +/// Alias type for DIDExchange v1.1 Complete message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this message type is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Complete = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] #[allow(clippy::field_reassign_with_default)] mod tests { - use std::marker::PhantomData; - use serde_json::json; use super::*; @@ -23,7 +23,7 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, }; #[test] @@ -36,7 +36,10 @@ mod tests { } }); - let decorators = CompleteDecoratorsV1_1::builder().thread(thread).build(); + let decorators = CompleteDecorators::builder() + .thread(thread) + .version(DidExchangeTypeV1::new_v1_1()) + .build(); test_utils::test_msg( NoContent, @@ -48,10 +51,10 @@ mod tests { #[test] fn test_extended_complete_message() { - let decorators = CompleteDecoratorsV1_1 { + let decorators = CompleteDecorators { thread: make_extended_thread(), timing: Some(make_extended_timing()), - _marker: PhantomData, + version: DidExchangeTypeV1::new_v1_1(), }; let expected = json!({ diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs index 6438977d43..b7747ae096 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs @@ -1,31 +1,25 @@ -// TODO: Why are not msg fields and types grouped by protocol??? pub mod complete; -// TODO: Duplicates connection problem report, deduplicate pub mod problem_report; pub mod request; pub mod response; use derive_more::From; use serde::{de::Error, Deserialize, Serialize}; -use shared::misc::serde_ignored::SerdeIgnored as NoContent; use self::{ - complete::{Complete, CompleteDecoratorsV1_1}, - problem_report::{ProblemReport, ProblemReportContentV1_1}, - request::{Request, RequestContentV1_1}, + complete::Complete, + problem_report::ProblemReport, + request::Request, response::{Response, ResponseContent}, }; -use super::{ - v1_x::{ - problem_report::ProblemReportDecorators, request::RequestDecorators, - response::ResponseDecorators, - }, - DidExchange, -}; +use super::{v1_x::response::ResponseDecorators, DidExchange}; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, - msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType, MsgWithType}, + msg_types::{ + protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, + MsgKindType, MsgWithType, + }, }; #[derive(Clone, Debug, From, PartialEq)] @@ -50,12 +44,21 @@ impl DelayedSerde for DidExchangeV1_1 { let kind = protocol.kind_from_str(kind_str); match kind.map_err(D::Error::custom)? { - DidExchangeTypeV1_1::Request => Request::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_1::Request => Request::deserialize(deserializer).map(|mut c| { + c.content.version = DidExchangeTypeV1::new_v1_1(); + c.into() + }), DidExchangeTypeV1_1::Response => Response::deserialize(deserializer).map(From::from), DidExchangeTypeV1_1::ProblemReport => { - ProblemReport::deserialize(deserializer).map(From::from) + ProblemReport::deserialize(deserializer).map(|mut c| { + c.content.version = DidExchangeTypeV1::new_v1_1(); + c.into() + }) } - DidExchangeTypeV1_1::Complete => Complete::deserialize(deserializer).map(From::from), + DidExchangeTypeV1_1::Complete => Complete::deserialize(deserializer).map(|mut c| { + c.decorators.version = DidExchangeTypeV1::new_v1_1(); + c.into() + }), } } @@ -64,18 +67,21 @@ impl DelayedSerde for DidExchangeV1_1 { S: serde::Serializer, { match self { - Self::Request(v) => MsgWithType::from(v).serialize(serializer), + Self::Request(v) => { + MsgWithType::<_, DidExchangeTypeV1_1>::from(v).serialize(serializer) + } Self::Response(v) => MsgWithType::from(v).serialize(serializer), - Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), - Self::Complete(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => { + MsgWithType::<_, DidExchangeTypeV1_1>::from(v).serialize(serializer) + } + Self::Complete(v) => { + MsgWithType::<_, DidExchangeTypeV1_1>::from(v).serialize(serializer) + } } } } -transit_to_aries_msg!(RequestContentV1_1: RequestDecorators, DidExchangeV1_1, DidExchange); transit_to_aries_msg!(ResponseContent: ResponseDecorators, DidExchangeV1_1, DidExchange); -transit_to_aries_msg!(ProblemReportContentV1_1: ProblemReportDecorators, DidExchangeV1_1, DidExchange); -transit_to_aries_msg!(NoContent: CompleteDecoratorsV1_1, DidExchangeV1_1, DidExchange); into_msg_with_type!(Request, DidExchangeTypeV1_1, Request); into_msg_with_type!(Response, DidExchangeTypeV1_1, Response); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs index cfad5f9929..ec7625842c 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs @@ -3,11 +3,13 @@ use crate::{ ProblemReportContent, ProblemReportDecorators, }, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type ProblemReportContentV1_1 = ProblemReportContent; -pub type ProblemReport = MsgParts; +/// Alias type for DIDExchange v1.1 problem report message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this message type is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type ProblemReport = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -25,14 +27,15 @@ mod tests { msg_fields::protocols::did_exchange::v1_x::problem_report::{ ProblemCode, ProblemReportDecorators, }, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, }; #[test] fn test_minimal_conn_problem_report() { - let content = ProblemReportContentV1_1::builder() + let content = ProblemReportContent::builder() .problem_code(None) .explain(None) + .version(DidExchangeTypeV1::new_v1_1()) .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -51,9 +54,10 @@ mod tests { #[test] fn test_extended_conn_problem_report() { - let content = ProblemReportContentV1_1::builder() + let content = ProblemReportContent::builder() .problem_code(Some(ProblemCode::RequestNotAccepted)) .explain(Some("test_conn_problem_report_explain".to_owned())) + .version(DidExchangeTypeV1::new_v1_1()) .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs index eff14876e4..9cf901690a 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs @@ -1,11 +1,13 @@ use crate::{ msg_fields::protocols::did_exchange::v1_x::request::{RequestContent, RequestDecorators}, msg_parts::MsgParts, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; -pub type RequestContentV1_1 = RequestContent; -pub type Request = MsgParts; +/// Alias type for DIDExchange v1.1 request message. +/// Note that since this inherits from the V1.X message, the direct serialization +/// of this message type is not recommended, as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Request = MsgParts; #[cfg(test)] #[allow(clippy::unwrap_used)] @@ -24,10 +26,10 @@ mod tests { }, misc::test_utils, msg_fields::protocols::did_exchange::v1_1::request::{Request, RequestDecorators}, - msg_types::protocols::did_exchange::DidExchangeTypeV1_1, + msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, }; - pub fn request_content() -> RequestContentV1_1 { + pub fn request_content() -> RequestContent { let did_doc = AriesDidDoc::default(); RequestContent { label: "test_request_label".to_owned(), @@ -45,7 +47,7 @@ mod tests { ) .build(), ), - _marker: std::marker::PhantomData, + version: DidExchangeTypeV1::new_v1_1(), } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs index a6413265a1..3c7f53daaf 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/response.rs @@ -11,10 +11,10 @@ pub type Response = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] pub struct ResponseContent { pub did: String, // TODO: Use Did - #[serde(rename = "did_doc~attach")] + #[serde(rename = "did_doc~attach", skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub did_doc: Option, - #[serde(rename = "did_rotate~attach")] + #[serde(rename = "did_rotate~attach", skip_serializing_if = "Option::is_none")] #[builder(default, setter(strip_option))] pub did_rotate: Option, } @@ -67,7 +67,9 @@ mod tests { #[test] fn test_minimal_conn_response() { - let content = response_content(); + let mut content = response_content(); + content.did_doc = None; + content.did_rotate = None; let decorators = ResponseDecorators { thread: make_extended_thread(), @@ -76,7 +78,6 @@ mod tests { let expected = json!({ "did": content.did, - "did_doc~attach": content.did_doc, "~thread": decorators.thread }); diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs index 314a9f86aa..dc223cada3 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use serde::{Deserialize, Serialize}; use shared::misc::serde_ignored::SerdeIgnored as NoContent; use typed_builder::TypedBuilder; @@ -7,138 +5,47 @@ use typed_builder::TypedBuilder; use crate::{ decorators::{thread::Thread, timing::Timing}, msg_fields::protocols::did_exchange::{ - v1_0::{complete::Complete as CompleteV1_0, DidExchangeV1_0}, - v1_1::{ - complete::{Complete as CompleteV1_1, CompleteDecoratorsV1_1}, - DidExchangeV1_1, - }, - DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange, }, msg_parts::MsgParts, msg_types::protocols::did_exchange::DidExchangeTypeV1, AriesMessage, }; -pub type Complete = MsgParts>; +/// Alias type for the shared DIDExchange v1.X complete message type. +/// Note the direct serialization of this message type is not recommended, +/// as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Complete = MsgParts; // TODO: Pthid is mandatory in this case! #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct CompleteDecorators { +pub struct CompleteDecorators { #[serde(rename = "~thread")] pub thread: Thread, #[builder(default, setter(strip_option))] #[serde(rename = "~timing")] #[serde(skip_serializing_if = "Option::is_none")] pub timing: Option, - #[builder(default, setter(skip))] - #[serde(skip)] - pub(crate) _marker: PhantomData, -} - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] -#[serde(untagged)] -pub enum AnyComplete { - V1_0(CompleteV1_0), - V1_1(CompleteV1_1), -} - -impl AnyComplete { - pub fn get_version_marker(&self) -> DidExchangeTypeV1 { - match self { - AnyComplete::V1_0(_) => DidExchangeTypeV1::new_v1_0(), - AnyComplete::V1_1(_) => DidExchangeTypeV1::new_v1_1(), - } - } - - pub fn into_v1_1(self) -> CompleteV1_1 { - match self { - AnyComplete::V1_0(r) => r.into_v1_1(), - AnyComplete::V1_1(r) => r, - } - } + #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] + pub(crate) version: DidExchangeTypeV1, } -impl CompleteV1_0 { - pub fn into_v1_1(self) -> CompleteV1_1 { - CompleteV1_1 { - id: self.id, - content: self.content, - decorators: CompleteDecoratorsV1_1 { - thread: self.decorators.thread, - timing: self.decorators.timing, - _marker: PhantomData, - }, - } +impl Complete { + pub fn get_version(&self) -> DidExchangeTypeV1 { + self.decorators.version } } -impl From for AriesMessage { - fn from(value: AnyComplete) -> Self { - match value { - AnyComplete::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Complete(inner)).into(), - AnyComplete::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Complete(inner)).into(), +impl From for AriesMessage { + fn from(value: Complete) -> Self { + match value.get_version() { + DidExchangeTypeV1::V1_0(_) => { + DidExchange::V1_0(DidExchangeV1_0::Complete(value)).into() + } + DidExchangeTypeV1::V1_1(_) => { + DidExchange::V1_1(DidExchangeV1_1::Complete(value)).into() + } } } } - -// #[cfg(test)] -// #[allow(clippy::unwrap_used)] -// #[allow(clippy::field_reassign_with_default)] -// mod tests { -// use serde_json::json; - -// use super::*; -// use crate::{ -// decorators::{ -// thread::tests::{make_extended_thread, make_minimal_thread}, -// timing::tests::make_extended_timing, -// }, -// misc::test_utils, -// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, -// }; - -// #[test] -// fn test_minimal_complete_message() { -// let thread = make_minimal_thread(); - -// let expected = json!({ -// "~thread": { -// "thid": thread.thid -// } -// }); - -// let decorators = CompleteDecorators { -// thread, -// timing: None, -// _marker: PhantomData::<()>, -// }; - -// test_utils::test_msg( -// NoContent, -// decorators, -// DidExchangeTypeV1_0::Complete, -// expected, -// ); -// } - -// #[test] -// fn test_extended_complete_message() { -// let decorators = CompleteDecorators { -// thread: make_extended_thread(), -// timing: Some(make_extended_timing()), -// _marker: PhantomData::<()>, -// }; - -// let expected = json!({ -// "~thread": serde_json::to_value(make_extended_thread()).unwrap(), -// "~timing": serde_json::to_value(make_extended_timing()).unwrap() -// }); - -// test_utils::test_msg( -// NoContent, -// decorators, -// DidExchangeTypeV1_0::Complete, -// expected, -// ); -// } -// } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs index b24fcce7a0..b67e5dfa4c 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs @@ -1,86 +1,31 @@ -use std::marker::PhantomData; - use serde::{Deserialize, Serialize}; use typed_builder::TypedBuilder; use crate::{ decorators::{localization::MsgLocalization, thread::Thread, timing::Timing}, msg_fields::protocols::did_exchange::{ - v1_0::{problem_report::ProblemReport as ProblemReportV1_0, DidExchangeV1_0}, - v1_1::{ - problem_report::{ProblemReport as ProblemReportV1_1, ProblemReportContentV1_1}, - DidExchangeV1_1, - }, - DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange, }, msg_parts::MsgParts, msg_types::protocols::did_exchange::DidExchangeTypeV1, AriesMessage, }; -pub type ProblemReport = - MsgParts, ProblemReportDecorators>; - -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] -#[serde(untagged)] -pub enum AnyProblemReport { - V1_0(ProblemReportV1_0), - V1_1(ProblemReportV1_1), -} - -impl AnyProblemReport { - pub fn get_version_marker(&self) -> DidExchangeTypeV1 { - match self { - AnyProblemReport::V1_0(_) => DidExchangeTypeV1::new_v1_0(), - AnyProblemReport::V1_1(_) => DidExchangeTypeV1::new_v1_1(), - } - } - - pub fn into_v1_1(self) -> ProblemReportV1_1 { - match self { - AnyProblemReport::V1_0(r) => r.into_v1_1(), - AnyProblemReport::V1_1(r) => r, - } - } -} - -impl ProblemReportV1_0 { - pub fn into_v1_1(self) -> ProblemReportV1_1 { - ProblemReportV1_1 { - id: self.id, - content: ProblemReportContentV1_1 { - problem_code: self.content.problem_code, - explain: self.content.explain, - _marker: PhantomData, - }, - decorators: self.decorators, - } - } -} - -impl From for AriesMessage { - fn from(value: AnyProblemReport) -> Self { - match value { - AnyProblemReport::V1_0(inner) => { - DidExchange::V1_0(DidExchangeV1_0::ProblemReport(inner)).into() - } - AnyProblemReport::V1_1(inner) => { - DidExchange::V1_1(DidExchangeV1_1::ProblemReport(inner)).into() - } - } - } -} +/// Alias type for the shared DIDExchange v1.X problem report message type. +/// Note the direct serialization of this message type is not recommended, +/// as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type ProblemReport = MsgParts; -#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct ProblemReportContent { +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct ProblemReportContent { #[serde(rename = "problem-code")] #[serde(skip_serializing_if = "Option::is_none")] pub problem_code: Option, #[serde(skip_serializing_if = "Option::is_none")] pub explain: Option, - #[builder(default, setter(skip))] - #[serde(skip)] - pub(crate) _marker: PhantomData, + #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] + pub(crate) version: DidExchangeTypeV1, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -116,63 +61,21 @@ impl ProblemReportDecorators { } } -// #[cfg(test)] -// #[allow(clippy::unwrap_used)] -// #[allow(clippy::field_reassign_with_default)] -// mod tests { -// use serde_json::json; - -// use super::*; -// use crate::{ -// decorators::{ -// localization::tests::make_extended_msg_localization, -// thread::tests::make_extended_thread, timing::tests::make_extended_timing, -// }, -// misc::test_utils, -// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, -// }; - -// #[test] -// fn test_minimal_conn_problem_report() { -// let content = ProblemReportContent::<()>::default(); - -// let decorators = ProblemReportDecorators::new(make_extended_thread()); - -// let expected = json!({ -// "~thread": decorators.thread -// }); - -// test_utils::test_msg( -// content, -// decorators, -// DidExchangeTypeV1_0::ProblemReport, -// expected, -// ); -// } - -// #[test] -// fn test_extended_conn_problem_report() { -// let mut content = ProblemReportContent::<()>::default(); -// content.problem_code = Some(ProblemCode::RequestNotAccepted); -// content.explain = Some("test_conn_problem_report_explain".to_owned()); - -// let mut decorators = ProblemReportDecorators::new(make_extended_thread()); -// decorators.timing = Some(make_extended_timing()); -// decorators.localization = Some(make_extended_msg_localization()); - -// let expected = json!({ -// "problem-code": content.problem_code, -// "explain": content.explain, -// "~thread": decorators.thread, -// "~timing": decorators.timing, -// "~l10n": decorators.localization -// }); +impl ProblemReport { + pub fn get_version(&self) -> DidExchangeTypeV1 { + self.content.version + } +} -// test_utils::test_msg( -// content, -// decorators, -// DidExchangeTypeV1_0::ProblemReport, -// expected, -// ); -// } -// } +impl From for AriesMessage { + fn from(value: ProblemReport) -> Self { + match value.get_version() { + DidExchangeTypeV1::V1_0(_) => { + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(value)).into() + } + DidExchangeTypeV1::V1_1(_) => { + DidExchange::V1_1(DidExchangeV1_1::ProblemReport(value)).into() + } + } + } +} diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs index 3afaf1be55..3d6d12f9ab 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs @@ -1,5 +1,3 @@ -use std::marker::PhantomData; - use serde::{Deserialize, Serialize}; use shared::maybe_known::MaybeKnown; use typed_builder::TypedBuilder; @@ -11,31 +9,29 @@ use crate::{ timing::Timing, }, msg_fields::protocols::did_exchange::{ - v1_0::{request::Request as RequestV1_0, DidExchangeV1_0}, - v1_1::{ - request::{Request as RequestV1_1, RequestContentV1_1}, - DidExchangeV1_1, - }, - DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange, }, msg_parts::MsgParts, msg_types::protocols::did_exchange::DidExchangeTypeV1, AriesMessage, }; -pub type Request = MsgParts, RequestDecorators>; +/// Alias type for the shared DIDExchange v1.X request message type. +/// Note the direct serialization of this message type is not recommended, +/// as version metadata will be lost. +/// Instead, this type should be converted to/from an AriesMessage +pub type Request = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct RequestContent { +pub struct RequestContent { pub label: String, pub goal_code: Option>, pub goal: Option, pub did: String, // TODO: Use Did #[serde(rename = "did_doc~attach")] pub did_doc: Option, - #[builder(default, setter(skip))] - #[serde(skip)] - pub(crate) _marker: PhantomData, + #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] + pub(crate) version: DidExchangeTypeV1, } #[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] @@ -49,143 +45,17 @@ pub struct RequestDecorators { pub timing: Option, } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, derive_more::From)] -#[serde(untagged)] -pub enum AnyRequest { - V1_0(RequestV1_0), - V1_1(RequestV1_1), -} - -impl AnyRequest { - pub fn get_version_marker(&self) -> DidExchangeTypeV1 { - match self { - AnyRequest::V1_0(_) => DidExchangeTypeV1::new_v1_0(), - AnyRequest::V1_1(_) => DidExchangeTypeV1::new_v1_1(), - } - } - - pub fn into_v1_1(self) -> RequestV1_1 { - match self { - AnyRequest::V1_0(r) => r.into_v1_1(), - AnyRequest::V1_1(r) => r, - } - } -} - -impl RequestV1_0 { - pub fn into_v1_1(self) -> RequestV1_1 { - RequestV1_1 { - id: self.id, - content: RequestContentV1_1 { - label: self.content.label, - goal_code: self.content.goal_code, - goal: self.content.goal, - did: self.content.did, - did_doc: self.content.did_doc, - _marker: PhantomData, - }, - decorators: self.decorators, - } +impl Request { + pub fn get_version(&self) -> DidExchangeTypeV1 { + self.content.version } } -impl From for AriesMessage { - fn from(value: AnyRequest) -> Self { - match value { - AnyRequest::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Request(inner)).into(), - AnyRequest::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Request(inner)).into(), +impl From for AriesMessage { + fn from(value: Request) -> Self { + match value.get_version() { + DidExchangeTypeV1::V1_0(_) => DidExchange::V1_0(DidExchangeV1_0::Request(value)).into(), + DidExchangeTypeV1::V1_1(_) => DidExchange::V1_1(DidExchangeV1_1::Request(value)).into(), } } } - -// #[cfg(test)] -// #[allow(clippy::unwrap_used)] -// #[allow(clippy::field_reassign_with_default)] -// mod tests { -// use diddoc_legacy::aries::diddoc::AriesDidDoc; -// use serde_json::json; - -// use super::*; -// use crate::{ -// decorators::{ -// attachment::{AttachmentData, AttachmentType}, -// thread::tests::make_extended_thread, -// timing::tests::make_extended_timing, -// }, -// misc::test_utils, -// msg_types::protocols::did_exchange::DidExchangeTypeV1_0, -// }; - -// pub fn request_content() -> RequestContent<()> { -// let did_doc = AriesDidDoc::default(); -// RequestContent { -// label: "test_request_label".to_owned(), -// goal_code: Some(MaybeKnown::Known(ThreadGoalCode::AriesRelBuild)), -// goal: Some("test_goal".to_owned()), -// did: did_doc.id.clone(), -// did_doc: Some( -// Attachment::builder() -// .data( -// AttachmentData::builder() -// .content(AttachmentType::Json( -// serde_json::to_value(&did_doc).unwrap(), -// )) -// .build(), -// ) -// .build(), -// ), -// _marker: PhantomData, -// } -// } - -// #[test] -// fn test_print_message() { -// let msg: Request<_> = Request::<()>::builder() -// .id("test_id".to_owned()) -// .content(request_content()) -// .decorators(RequestDecorators::default()) -// .build(); -// let printed_json = format!("{}", msg); -// let parsed_request: Request<_> = serde_json::from_str(&printed_json).unwrap(); -// assert_eq!(msg, parsed_request); -// } - -// #[test] -// fn test_minimal_didexchange_request() { -// let content = request_content(); -// let expected = json!({ -// "label": content.label, -// "goal_code": content.goal_code, -// "goal": content.goal, -// "did": content.did, -// "did_doc~attach": content.did_doc, -// }); -// test_utils::test_msg( -// content, -// RequestDecorators::default(), -// DidExchangeTypeV1_0::Request, -// expected, -// ); -// } - -// #[test] -// fn test_extended_didexchange_request() { -// let content = request_content(); - -// let mut decorators = RequestDecorators::default(); -// decorators.thread = Some(make_extended_thread()); -// decorators.timing = Some(make_extended_timing()); - -// let expected = json!({ -// "label": content.label, -// "goal_code": content.goal_code, -// "goal": content.goal, -// "did": content.did, -// "did_doc~attach": content.did_doc, -// "~thread": decorators.thread, -// "~timing": decorators.timing -// }); - -// test_utils::test_msg(content, decorators, DidExchangeTypeV1_0::Request, expected); -// } -// } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs index cf6bcc3588..9543d98cf2 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/response.rs @@ -23,7 +23,7 @@ pub enum AnyResponse { } impl AnyResponse { - pub fn get_version_marker(&self) -> DidExchangeTypeV1 { + pub fn get_version(&self) -> DidExchangeTypeV1 { match self { AnyResponse::V1_0(_) => DidExchangeTypeV1::new_v1_0(), AnyResponse::V1_1(_) => DidExchangeTypeV1::new_v1_1(), From a0204589043904b47e3822613cb805cf6aa30b0b Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 12:35:53 +1000 Subject: [PATCH 06/32] v1_1 branch processing, and some clippy Signed-off-by: George Mulhearn --- .../src/controllers/didcomm.rs | 24 ++++--------- .../did_exchange/state_machine/helpers.rs | 21 +++++++++--- .../requester/request_sent/mod.rs | 2 ++ .../responder/response_sent/mod.rs | 34 ++++++++++--------- aries/aries_vcx/tests/test_did_exchange.rs | 2 +- 5 files changed, 44 insertions(+), 39 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index 6ec4536a97..739722c6d9 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -197,11 +197,9 @@ impl HarnessAgent { async fn handle_did_exchange_msg(&self, msg: DidExchange) -> HarnessResult<()> { match msg { - DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { - self.queue_didexchange_request(request.into())?; - } - DidExchange::V1_1(DidExchangeV1_1::Request(request)) => { - self.queue_didexchange_request(request.into())?; + DidExchange::V1_0(DidExchangeV1_0::Request(request)) + | DidExchange::V1_1(DidExchangeV1_1::Request(request)) => { + self.queue_didexchange_request(request)?; } DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { let res = self @@ -223,22 +221,14 @@ impl HarnessAgent { error!("Error sending complete: {:?}", err); }; } - DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) => { - self.aries_agent - .did_exchange() - .handle_msg_complete(complete)?; - } - DidExchange::V1_1(DidExchangeV1_1::Complete(complete)) => { + DidExchange::V1_0(DidExchangeV1_0::Complete(complete)) + | DidExchange::V1_1(DidExchangeV1_1::Complete(complete)) => { self.aries_agent .did_exchange() .handle_msg_complete(complete)?; } - DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) => { - self.aries_agent - .did_exchange() - .receive_problem_report(problem_report)?; - } - DidExchange::V1_1(DidExchangeV1_1::ProblemReport(problem_report)) => { + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(problem_report)) + | DidExchange::V1_1(DidExchangeV1_1::ProblemReport(problem_report)) => { self.aries_agent .did_exchange() .receive_problem_report(problem_report)?; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 6839ca3c1b..84f12b03ea 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -10,7 +10,7 @@ use did_doc::schema::{ verification_method::{PublicKeyField, VerificationMethodType}, }; use did_key::DidKey; -use did_parser_nom::DidUrl; +use did_parser_nom::{Did, DidUrl}; use did_peer::peer_did::{ numalgos::numalgo4::{ construction_did_doc::{DidPeer4ConstructionDidDocument, DidPeer4VerificationMethod}, @@ -45,11 +45,11 @@ use crate::{ pub(crate) fn construct_response_v1_0( request_id: String, - our_did_document: &DidDocument, + did: &Did, signed_diddoc_attach: Attachment, ) -> ResponseV1_0 { let content = ResponseV1_0Content::builder() - .did(our_did_document.id().to_string()) + .did(did.to_string()) .did_doc(Some(signed_diddoc_attach)) .build(); let decorators = ResponseDecorators::builder() @@ -65,11 +65,11 @@ pub(crate) fn construct_response_v1_0( pub(crate) fn construct_response_v1_1( request_id: String, - our_did_document: &DidDocument, + did: &Did, signed_didrotate_attach: Attachment, ) -> ResponseV1_1 { let content = ResponseV1_1Content::builder() - .did(our_did_document.id().to_string()) + .did(did.to_string()) .did_rotate(signed_didrotate_attach) .build(); let decorators = ResponseDecorators::builder() @@ -145,6 +145,17 @@ pub(crate) fn ddo_to_attach(ddo: DidDocument) -> Result Attachment { + let content_b64 = base64::engine::Engine::encode(&URL_SAFE_NO_PAD, did.id()); + Attachment::builder() + .data( + AttachmentData::builder() + .content(AttachmentType::Base64(content_b64)) + .build(), + ) + .build() +} + // TODO: Obviously, extract attachment signing // TODO: JWS verification pub(crate) async fn jws_sign_attach( diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index e55fa904e2..a21bb7c32a 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -92,12 +92,14 @@ impl DidExchangeRequester { "DidExchangeRequester::receive_response >> the Response message \ contained attached ddo" ); + // verify JWS signature on attachment attachment_to_diddoc(ddo).map_err(to_transition_error(self.clone()))? } else { debug!( "DidExchangeRequester::receive_response >> the Response message \ contains pairwise DID, resolving to DID Document" ); + // verify JWS signature on attachment IF version == 1.1 let did = &Did::parse(response.content.did).map_err(to_transition_error(self.clone()))?; let DidResolutionOutput { did_document, .. } = resolver_registry diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 6c2fcf90d8..1b8d100969 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -17,8 +17,8 @@ use crate::{ errors::error::{AriesVcxError, AriesVcxErrorKind}, protocols::did_exchange::{ state_machine::helpers::{ - attachment_to_diddoc, construct_response_v1_0, construct_response_v1_1, ddo_to_attach, - jws_sign_attach, + assemble_did_rotate_attachment, attachment_to_diddoc, construct_response_v1_0, + construct_response_v1_1, ddo_to_attach, jws_sign_attach, }, states::{completed::Completed, responder::response_sent::ResponseSent}, transition::{transition_error::TransitionError, transition_result::TransitionResult}, @@ -44,34 +44,36 @@ impl DidExchangeResponder { let their_ddo = resolve_ddo_from_request(&resolver_registry, &request).await?; let our_did_document = our_peer_did.resolve_did_doc()?; - // TODO - use v1.1 rotate attach if possible - let ddo_attachment_unsigned = ddo_to_attach(our_did_document.clone())?; - let ddo_attachment = match invitation_key { + let unsigned_attachment = match version { + DidExchangeTypeV1::V1_1(_) => assemble_did_rotate_attachment(our_peer_did.did()), + DidExchangeTypeV1::V1_0(_) => ddo_to_attach(our_did_document.clone())?, + }; + let attachment = match invitation_key { + Some(invitation_key) => { + // TODO: this must happen only if we rotate DID; We currently do that always + // can skip signing if we don't rotate did document (unique p2p invitations + // with peer DIDs) + jws_sign_attach(unsigned_attachment, invitation_key, wallet).await? + } None => { // TODO: not signing if invitation_key is not provided, that would be case for // implicit invitations. However we should probably sign with // the key the request used as recipient_vk to anoncrypt the request // So argument "invitation_key" should be required - ddo_attachment_unsigned - } - Some(invitation_key) => { - // TODO: this must happen only if we rotate DID; We currently do that always - // can skip signing if we don't rotate did document (unique p2p invitations - // with peer DIDs) - jws_sign_attach(ddo_attachment_unsigned, invitation_key, wallet).await? + unsigned_attachment } }; let response = match version { DidExchangeTypeV1::V1_1(_) => AnyResponse::V1_1(construct_response_v1_1( request.id.clone(), - &our_did_document, - ddo_attachment, + our_peer_did.did(), + attachment, )), DidExchangeTypeV1::V1_0(_) => AnyResponse::V1_0(construct_response_v1_0( request.id.clone(), - &our_did_document, - ddo_attachment, + our_peer_did.did(), + attachment, )), }; debug!( diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 5f2c51ea0f..6930b47148 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -147,7 +147,7 @@ async fn did_exchange_test() -> Result<(), Box> { } = DidExchangeResponder::::receive_request( &agent_inviter.wallet, resolver_registry.clone(), - request.into(), + request, &responders_peer_did, Some(invitation_key), ) From f87074341bf6b2ce03d85797c4e2b1877118ec54 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 13:56:32 +1000 Subject: [PATCH 07/32] remove old todos Signed-off-by: George Mulhearn --- .../messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs index c2f003e7ec..9b518b0009 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -1,6 +1,4 @@ -// TODO: Why are not msg fields and types grouped by protocol??? pub mod complete; -// TODO: Duplicates connection problem report, deduplicate pub mod problem_report; pub mod request; pub mod response; From b1cbe84c1a47d242f4d4a74bd6445b1b7c1f8c15 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 14:39:41 +1000 Subject: [PATCH 08/32] fixes for aath with self for 4/7 performance on RFC0793 & 4/7 on 0023 Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 60 ++++++++++++------- .../src/handlers/did_exchange.rs | 16 +++-- 2 files changed, 48 insertions(+), 28 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index e2fa3560b6..477977db43 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -11,6 +11,7 @@ use aries_vcx_agent::aries_vcx::{ }, protocols::did_exchange::state_machine::requester::helpers::invitation_get_first_did_service, }; +use serde_json::Value; use crate::{ controllers::AathRequest, @@ -35,7 +36,7 @@ impl HarnessAgent { .out_of_band() .get_invitation(&invitation_id)?; let did_inviter: Did = invitation_get_first_did_service(&invitation)?; - let (thid, pthid) = self + let (thid, pthid, my_did) = self .aries_agent .did_exchange() .handle_msg_invitation(did_inviter.to_string(), Some(invitation_id)) @@ -48,7 +49,11 @@ impl HarnessAgent { ); } let connection_id = pthid.unwrap_or(thid); - Ok(json!({ "connection_id" : connection_id }).to_string()) + Ok(json!({ + "connection_id" : connection_id, + "my_did": my_did + }) + .to_string()) } pub fn queue_didexchange_request(&self, request: Request) -> HarnessResult<()> { @@ -69,13 +74,17 @@ impl HarnessAgent { &self, req: &CreateResolvableDidRequest, ) -> HarnessResult { - let (thid, pthid) = self + let (thid, pthid, my_did) = self .aries_agent .did_exchange() .handle_msg_invitation(req.their_public_did.clone(), None) // todo: separate the case with/without invitation on did_exchange handler .await?; let connection_id = pthid.unwrap_or(thid); - Ok(json!({ "connection_id": connection_id }).to_string()) + Ok(json!({ + "connection_id": connection_id, + "my_did": my_did + }) + .to_string()) } // Looks up an oldest unprocessed did-exchange request message @@ -101,17 +110,21 @@ impl HarnessAgent { })? .clone() }; - if let AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(ref request))) = - request - { - let thid = request.decorators.thread.clone().unwrap().thid; - Ok(json!({ "connection_id": thid }).to_string()) - } else { - Err(HarnessError::from_msg( - HarnessErrorType::InvalidState, - "Message is not a request", - )) - } + let request = match request { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) + | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { + request + } + _ => { + return Err(HarnessError::from_msg( + HarnessErrorType::InvalidState, + "Message is not a request", + )) + } + }; + + let thid = request.decorators.thread.clone().unwrap().thid; + Ok(json!({ "connection_id": thid }).to_string()) } // Note: AVF identifies protocols by thid, but AATH sometimes tracks identifies did-exchange @@ -145,10 +158,8 @@ impl HarnessAgent { })? }; let request = match request { - AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) => { - request - } - AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) + | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { request } _ => { @@ -168,7 +179,7 @@ impl HarnessAgent { } None => None, }; - let (thid, pthid) = self + let (thid, pthid, my_did, their_did) = self .aries_agent .did_exchange() .handle_msg_request(request, opt_invitation) @@ -184,7 +195,12 @@ impl HarnessAgent { .did_exchange() .send_response(thid.clone()) .await?; - Ok(json!({ "connection_id": thid }).to_string()) + Ok(json!({ + "connection_id": thid, + "my_did": my_did, + "their_did": their_did + }) + .to_string()) } pub async fn didx_get_state(&self, connection_id: &str) -> HarnessResult { @@ -215,7 +231,7 @@ impl HarnessAgent { #[post("/send-request")] async fn send_did_exchange_request( - req: web::Json>, + req: web::Json>, agent: web::Data>, ) -> impl Responder { agent diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index e984c6b0c4..fd5c6b7a84 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -63,10 +63,11 @@ impl DidcommHandlerDidExchange { &self, their_did: String, invitation_id: Option, - ) -> AgentResult<(String, Option)> { + ) -> AgentResult<(String, Option, String)> { // todo: type the return type let (our_peer_did, _our_verkey) = create_peer_did_4(self.wallet.as_ref(), self.service_endpoint.clone(), vec![]).await?; + let our_did = our_peer_did.did().to_string(); let their_did: Did = their_did.parse()?; let (requester, request) = GenericDidExchange::construct_request( @@ -127,7 +128,7 @@ impl DidcommHandlerDidExchange { VcxHttpClient .send_message(encryption_envelope.0, service.service_endpoint()) .await?; - Ok((thid, pthid)) + Ok((thid, pthid, our_did)) } // todo: whether invitation exists should handle the framework based on (p)thread matching @@ -136,7 +137,7 @@ impl DidcommHandlerDidExchange { &self, request: Request, invitation: Option, - ) -> AgentResult<(String, Option)> { + ) -> AgentResult<(String, Option, String, String)> { // todo: type the return type // Todo: messages should expose fallible API to get thid (for any aries msg). It's common // pattern @@ -165,7 +166,7 @@ impl DidcommHandlerDidExchange { } }; - let (peer_did_4_invitee, _our_verkey) = + let (our_peer_did, _our_verkey) = create_peer_did_4(self.wallet.as_ref(), self.service_endpoint.clone(), vec![]).await?; let pthid = thread @@ -182,14 +183,17 @@ impl DidcommHandlerDidExchange { self.wallet.as_ref(), self.resolver_registry.clone(), request, - &peer_did_4_invitee, + &our_peer_did, invitation_key, ) .await?; self.did_exchange .insert(&thid, (responder.clone(), Some(response.into())))?; - Ok((thid, pthid)) + let our_did = responder.our_did_document().id().to_string(); + let their_did = responder.their_did_doc().id().to_string(); + + Ok((thid, pthid, our_did, their_did)) } // todo: perhaps injectable transports? Or just return the message let the caller send it? From b91367412e2844a59d4af5e64ff3c8a612a7ff1f Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 15:32:17 +1000 Subject: [PATCH 09/32] smalls patches from acapy testing Signed-off-by: George Mulhearn --- .../did_exchange/state_machine/requester/request_sent/mod.rs | 1 + .../src/msg_fields/protocols/did_exchange/v1_x/request.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index a21bb7c32a..170a18a176 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -29,6 +29,7 @@ impl DidExchangeRequester { pub async fn construct_request( resolver_registry: Arc, invitation_id: Option, + // TODO - label pass thru their_did: &Did, our_peer_did: &PeerDid, ) -> Result, AriesVcxError> { diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs index 3d6d12f9ab..4ac427c70e 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs @@ -25,10 +25,12 @@ pub type Request = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] pub struct RequestContent { pub label: String, + #[serde(skip_serializing_if = "Option::is_none")] pub goal_code: Option>, + #[serde(skip_serializing_if = "Option::is_none")] pub goal: Option, pub did: String, // TODO: Use Did - #[serde(rename = "did_doc~attach")] + #[serde(rename = "did_doc~attach", skip_serializing_if = "Option::is_none")] pub did_doc: Option, #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] pub(crate) version: DidExchangeTypeV1, From 5c1f6da7b1915714be2b71f5bf0de28901e14a7c Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 16:01:51 +1000 Subject: [PATCH 10/32] fix up mimetype handling as a result of testing acapy (text/string) Signed-off-by: George Mulhearn --- aries/aries_vcx/src/handlers/util.rs | 2 +- aries/messages/src/decorators/attachment.rs | 32 +++++++++++++++++---- aries/messages/src/misc/mime_type.rs | 2 ++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/aries/aries_vcx/src/handlers/util.rs b/aries/aries_vcx/src/handlers/util.rs index c733da8def..3ee2ac9e2f 100644 --- a/aries/aries_vcx/src/handlers/util.rs +++ b/aries/aries_vcx/src/handlers/util.rs @@ -75,7 +75,7 @@ macro_rules! make_attach_from_str { .data(attach_data) .build(); attach.id = Some($id); - attach.mime_type = Some(messages::misc::MimeType::Json); + attach.mime_type = Some(shared::maybe_known::MaybeKnown::Known(messages::misc::MimeType::Json)); attach }}; } diff --git a/aries/messages/src/decorators/attachment.rs b/aries/messages/src/decorators/attachment.rs index 8ce8249efa..c3cd17f82d 100644 --- a/aries/messages/src/decorators/attachment.rs +++ b/aries/messages/src/decorators/attachment.rs @@ -3,6 +3,7 @@ use std::collections::HashMap; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use shared::maybe_known::MaybeKnown; use typed_builder::TypedBuilder; use url::Url; @@ -13,8 +14,7 @@ use crate::misc::MimeType; #[serde(rename_all = "snake_case")] pub struct Attachment { #[builder(default, setter(strip_option))] - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(rename = "@id")] + #[serde(skip_serializing_if = "Option::is_none", rename = "@id")] pub id: Option, #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] @@ -22,10 +22,12 @@ pub struct Attachment { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub filename: Option, - #[builder(default, setter(strip_option))] - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(rename = "mime-type")] - pub mime_type: Option, + // mimetype wrapped in MaybeKnown to handle any deserialization from any string. + // other agents may be using mimetypes that this crate is not immediately aware of, but + // we should not fail to deserialize as a result. + #[builder(default, setter(transform = |x: MimeType| Some(MaybeKnown::Known(x))))] + #[serde(skip_serializing_if = "Option::is_none", rename = "mime-type")] + pub mime_type: Option>, #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub lastmod_time: Option>, @@ -195,4 +197,22 @@ pub mod tests { test_utils::test_serde(attachment, expected); } + + #[test] + fn test_extended_attachment_with_unknown_mime() { + let mut attachment = make_extended_attachment(); + attachment.mime_type = Some(MaybeKnown::Unknown(String::from("unknown/vcx"))); + + let expected = json!({ + "@id": attachment.id, + "description": attachment.description, + "filename": attachment.filename, + "mime-type": "unknown/vcx", + "lastmod_time": attachment.lastmod_time, + "byte_count": attachment.byte_count, + "data": attachment.data + }); + + test_utils::test_serde(attachment, expected); + } } diff --git a/aries/messages/src/misc/mime_type.rs b/aries/messages/src/misc/mime_type.rs index bd846cfca3..e5eddeb055 100644 --- a/aries/messages/src/misc/mime_type.rs +++ b/aries/messages/src/misc/mime_type.rs @@ -14,6 +14,8 @@ pub enum MimeType { Pdf, #[serde(rename = "text/plain")] Plain, + #[serde(rename = "text/string")] + String, #[serde(rename = "didcomm/aip1")] Aip1, #[serde(rename = "didcomm/aip2;env=rfc19")] From 494f8c87edbaa432a3fc5542982c6ae5308f8a64 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 17:17:16 +1000 Subject: [PATCH 11/32] handle multikey (acapy uses this) Signed-off-by: George Mulhearn --- aries/aries_vcx/src/utils/didcomm_utils.rs | 30 +++++++--- .../src/utils/encryption_envelope.rs | 14 +++-- aries/aries_vcx/tests/test_did_exchange.rs | 8 +-- .../src/schema/verification_method/mod.rs | 17 ++++-- .../verification_method_type.rs | 5 ++ .../src/peer_did/numalgos/numalgo4/mod.rs | 60 ++++++++++++++++++- 6 files changed, 112 insertions(+), 22 deletions(-) diff --git a/aries/aries_vcx/src/utils/didcomm_utils.rs b/aries/aries_vcx/src/utils/didcomm_utils.rs index b044966659..c231af9469 100644 --- a/aries/aries_vcx/src/utils/didcomm_utils.rs +++ b/aries/aries_vcx/src/utils/didcomm_utils.rs @@ -2,7 +2,7 @@ use did_doc::schema::{ did_doc::DidDocument, service::service_key_kind::ServiceKeyKind, types::uri::Uri, verification_method::VerificationMethodType, }; -use public_key::Key; +use public_key::{Key, KeyType}; use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; @@ -34,15 +34,31 @@ fn resolve_service_key_to_typed_key( } } -pub fn resolve_base58_key_agreement(did_document: &DidDocument) -> VcxResult { - let key_types = [ +/// Resolves the first ed25519 base58 public key (a.k.a. verkey) within the DIDDocuments key agreement +/// keys. Useful for resolving keys that can be used for packing DIDCommV1 messages. +pub fn resolve_ed25519_base58_key_agreement(did_document: &DidDocument) -> VcxResult { + let vm_types = [ VerificationMethodType::Ed25519VerificationKey2018, VerificationMethodType::Ed25519VerificationKey2020, - VerificationMethodType::X25519KeyAgreementKey2019, - VerificationMethodType::X25519KeyAgreementKey2020, + VerificationMethodType::Multikey, + // would be nice to search for X25519 VM types which could be derived into ed25519 keys + // for the encryption envelope to use. + // would be nice to search for other VM types which _could_ be ed25519 (jwk etc) ]; - let key_base58 = did_document.get_key_agreement_of_type(&key_types)?; - Ok(key_base58.public_key()?.base58()) + let vm = did_document.get_key_agreement_of_type(&vm_types)?; + let key = vm.public_key()?; + + match key.key_type() { + KeyType::Ed25519 => {} + _ => { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidVerkey, + format!("Cannot resolve key agreement as an Ed25519 key: {vm:?}"), + )) + } + } + + Ok(vm.public_key()?.base58()) } pub fn get_routing_keys(their_did_doc: &DidDocument, service_id: &Uri) -> VcxResult> { diff --git a/aries/aries_vcx/src/utils/encryption_envelope.rs b/aries/aries_vcx/src/utils/encryption_envelope.rs index 51ebca1f23..d21269d326 100644 --- a/aries/aries_vcx/src/utils/encryption_envelope.rs +++ b/aries/aries_vcx/src/utils/encryption_envelope.rs @@ -10,7 +10,7 @@ use uuid::Uuid; use crate::{ errors::error::prelude::*, - utils::didcomm_utils::{get_routing_keys, resolve_base58_key_agreement}, + utils::didcomm_utils::{get_routing_keys, resolve_ed25519_base58_key_agreement}, }; #[derive(Debug)] @@ -62,16 +62,17 @@ impl EncryptionEnvelope { 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 sender_vk = resolve_ed25519_base58_key_agreement(our_did_doc)?; + // CONSIDER - or should recipient keys be resolved from the service? similar to get_routing_keys. + let recipient_key = resolve_ed25519_base58_key_agreement(their_did_doc)?; let routing_keys = get_routing_keys(their_did_doc, their_service_id)?; EncryptionEnvelope::create_from_keys( wallet, data, - Some(&sender_vk.to_string()), - recipient_key.to_string(), - routing_keys.iter().map(|k| k.to_string()).collect(), + Some(&sender_vk), + recipient_key, + routing_keys, ) .await } @@ -80,6 +81,7 @@ impl EncryptionEnvelope { wallet: &impl BaseWallet, data: &[u8], sender_vk: Option<&str>, + // TODO - why not have encryption envelope take typed [Key]s, and enforce they are KeyType::Ed25519 recipient_key: String, routing_keys: Vec, ) -> VcxResult { diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 6930b47148..a340c59e06 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -14,7 +14,7 @@ use aries_vcx::{ states::{requester::request_sent::RequestSent, responder::response_sent::ResponseSent}, transition::transition_result::TransitionResult, }, - utils::{didcomm_utils::resolve_base58_key_agreement, encryption_envelope::EncryptionEnvelope}, + utils::{didcomm_utils::resolve_ed25519_base58_key_agreement, encryption_envelope::EncryptionEnvelope}, }; use aries_vcx_ledger::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; use did_doc::schema::{ @@ -42,8 +42,8 @@ pub mod utils; fn assert_key_agreement(a: DidDocument, b: DidDocument) { log::warn!("comparing did doc a: {}, b: {}", a, b); - let a_key = resolve_base58_key_agreement(&a).unwrap(); - let b_key = resolve_base58_key_agreement(&b).unwrap(); + let a_key = resolve_ed25519_base58_key_agreement(&a).unwrap(); + let b_key = resolve_ed25519_base58_key_agreement(&b).unwrap(); assert_eq!(a_key, b_key); } @@ -200,7 +200,7 @@ async fn did_exchange_test() -> Result<(), Box> { info!("Encrypted message: {:?}", m); let requesters_peer_did = requesters_peer_did.resolve_did_doc()?; - let expected_sender_vk = resolve_base58_key_agreement(&requesters_peer_did)?; + let expected_sender_vk = resolve_ed25519_base58_key_agreement(&requesters_peer_did)?; let unpacked = EncryptionEnvelope::auth_unpack(&agent_invitee.wallet, m.0, &expected_sender_vk).await?; diff --git a/did_core/did_doc/src/schema/verification_method/mod.rs b/did_core/did_doc/src/schema/verification_method/mod.rs index 0e046a55e3..9e0bb57290 100644 --- a/did_core/did_doc/src/schema/verification_method/mod.rs +++ b/did_core/did_doc/src/schema/verification_method/mod.rs @@ -42,10 +42,19 @@ impl VerificationMethod { } pub fn public_key(&self) -> Result { - Ok(Key::new( - self.public_key.key_decoded()?, - self.verification_method_type.try_into()?, - )?) + let key = match &self.public_key { + PublicKeyField::Multibase { + public_key_multibase, + } => Key::from_fingerprint(public_key_multibase)?, + // TODO - FUTURE - other key types could do with some special handling, i.e. + // those where the key_type is encoded within the key field (multibase, jwk, etc) + _ => Key::new( + self.public_key.key_decoded()?, + self.verification_method_type.try_into()?, + )?, + }; + + Ok(key) } } diff --git a/did_core/did_doc/src/schema/verification_method/verification_method_type.rs b/did_core/did_doc/src/schema/verification_method/verification_method_type.rs index 2921fdb40b..9d41289141 100644 --- a/did_core/did_doc/src/schema/verification_method/verification_method_type.rs +++ b/did_core/did_doc/src/schema/verification_method/verification_method_type.rs @@ -18,6 +18,8 @@ pub enum VerificationMethodType { X25519KeyAgreementKey2019, X25519KeyAgreementKey2020, EcdsaSecp256k1RecoveryMethod2020, + /// https://www.w3.org/TR/vc-data-integrity/#multikey + Multikey, } impl Display for VerificationMethodType { @@ -46,6 +48,9 @@ impl Display for VerificationMethodType { VerificationMethodType::EcdsaSecp256k1RecoveryMethod2020 => { write!(f, "EcdsaSecp256k1RecoveryMethod2020") } + VerificationMethodType::Multikey => { + write!(f, "Multikey") + } } } } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs index a7af761137..b0bbc7a61c 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs @@ -117,12 +117,13 @@ mod tests { use std::collections::HashMap; use did_doc::schema::{ - service::{typed::ServiceType, Service}, + service::{service_key_kind::ServiceKeyKind, typed::ServiceType, Service}, types::uri::Uri, utils::OneOrList, verification_method::{PublicKeyField, VerificationMethodType}, }; use did_parser_nom::DidUrl; + use public_key::KeyType; use crate::peer_did::{ numalgos::numalgo4::{ @@ -222,4 +223,61 @@ mod tests { let peer_did = PeerDid::::parse(peer_did).unwrap(); peer_did.long_form().unwrap_err(); } + + #[test] + fn test_resolve_acapy_test_vector1() { + let peer_did: &str = "did:peer:4zQmcQCH8nWEBBA6BpSEDxHyhPwHdi5CVGcvsZcjhb618zbA:z5CTtVoAxKjH1V1sKizLy5kLvV6AbmACYfcGmfVUDGn4A7BpnVQEESXEYYUG7W479kDHaqLnk7NJuu4w7ftTd9REipB2CQgW9fjzPvmsXyyHzot9o1tgYHNnqFDXgCXwFYJfjkzz3m6mex1WMN4XHWWNM4NB7exDA2maVGis7gJnVAiNrBExaihyeKJ4nBXrB3ArQ1TyuZ39F9qTeCSrBntTTa85wtUtHz5M1oE7Sj1CZeAEQzDnAMToP9idSrSXUo5z8q9Un325d8MtQgxyKGW2a9VYyW189C722GKQbGQSU3dRSwCanVHJwCh9q2G2eNVPeuydAHXmouCUCq3cVHeUkatv73DSoBV17LEJgq8dAYfvSAutG7LFyvrRW5wNjcQMT7WdFHRCqhtzz18zu6fSTQWM4PQPLMVEaKbs51EeYGiGurhu1ChQMjXqnpcRcpCP7RAEgyWSjMER6e3gdCVsBhQSoqGk1UN8NfVah8pxGg2i5Gd1754Ys6aBEhTashFa47Ke7oPoZ6LZiRMETYhUr1cQY65TQhMzyrR6RzLudeRVgcRdKiTTmP2fFi5H8nCHPSGb4wncUxgn3N5CbFaUC"; + let peer_did = PeerDid::::parse(peer_did).unwrap(); + + let resolved_did_doc = peer_did.resolve_did_doc().unwrap(); + assert_eq!(resolved_did_doc.id().to_string(), "did:peer:4zQmcQCH8nWEBBA6BpSEDxHyhPwHdi5CVGcvsZcjhb618zbA:z5CTtVoAxKjH1V1sKizLy5kLvV6AbmACYfcGmfVUDGn4A7BpnVQEESXEYYUG7W479kDHaqLnk7NJuu4w7ftTd9REipB2CQgW9fjzPvmsXyyHzot9o1tgYHNnqFDXgCXwFYJfjkzz3m6mex1WMN4XHWWNM4NB7exDA2maVGis7gJnVAiNrBExaihyeKJ4nBXrB3ArQ1TyuZ39F9qTeCSrBntTTa85wtUtHz5M1oE7Sj1CZeAEQzDnAMToP9idSrSXUo5z8q9Un325d8MtQgxyKGW2a9VYyW189C722GKQbGQSU3dRSwCanVHJwCh9q2G2eNVPeuydAHXmouCUCq3cVHeUkatv73DSoBV17LEJgq8dAYfvSAutG7LFyvrRW5wNjcQMT7WdFHRCqhtzz18zu6fSTQWM4PQPLMVEaKbs51EeYGiGurhu1ChQMjXqnpcRcpCP7RAEgyWSjMER6e3gdCVsBhQSoqGk1UN8NfVah8pxGg2i5Gd1754Ys6aBEhTashFa47Ke7oPoZ6LZiRMETYhUr1cQY65TQhMzyrR6RzLudeRVgcRdKiTTmP2fFi5H8nCHPSGb4wncUxgn3N5CbFaUC"); + assert_eq!( + resolved_did_doc.also_known_as()[0].to_string(), + "did:peer:4zQmcQCH8nWEBBA6BpSEDxHyhPwHdi5CVGcvsZcjhb618zbA" + ); + + // vm/key + assert_eq!(resolved_did_doc.verification_method().len(), 1); + let vm = resolved_did_doc.verification_method_by_id("key-0").unwrap(); + assert_eq!( + vm.verification_method_type(), + &VerificationMethodType::Multikey + ); + assert_eq!( + vm.public_key_field(), + &PublicKeyField::Multibase { + public_key_multibase: String::from( + "z6MkuNenWjqDeZ4DjkHoqX6WdDYTfUUqcR7ASezo846GHe74" + ) + } + ); + let key = vm.public_key().unwrap(); + assert_eq!( + key.fingerprint(), + "z6MkuNenWjqDeZ4DjkHoqX6WdDYTfUUqcR7ASezo846GHe74" + ); + assert_eq!(key.key_type(), &KeyType::Ed25519); + + // servie + assert_eq!(resolved_did_doc.service().len(), 1); + let service = resolved_did_doc + .get_service_by_id(&"#didcomm-0".parse().unwrap()) + .unwrap(); + assert_eq!( + service.service_type(), + &OneOrList::One(ServiceType::DIDCommV1) + ); + assert_eq!( + service.service_endpoint().to_string(), + "http://host.docker.internal:9031/" + ); + let service_recip = service + .extra_field_recipient_keys() + .unwrap(); + assert_eq!(service_recip, vec![ServiceKeyKind::Reference("#key-0".parse().unwrap())]); + log::info!( + "resolved document: {}", + serde_json::to_string_pretty(&resolved_did_doc).unwrap() + ); + } } From 6ec33a4a6feba338aa04077053519dfcc86013f6 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 18:04:00 +1000 Subject: [PATCH 12/32] make invite handshake 1.1 Signed-off-by: George Mulhearn --- aries/agents/aries-vcx-agent/src/handlers/out_of_band.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aries/agents/aries-vcx-agent/src/handlers/out_of_band.rs b/aries/agents/aries-vcx-agent/src/handlers/out_of_band.rs index b955dd49c5..6d01745a55 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/out_of_band.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/out_of_band.rs @@ -44,7 +44,7 @@ impl ServiceOutOfBand { let sender = OutOfBandSender::create() .append_service(&OobService::Did(peer_did.to_string())) .append_handshake_protocol(Protocol::DidExchangeType(DidExchangeType::V1( - DidExchangeTypeV1::new_v1_0(), + DidExchangeTypeV1::new_v1_1(), )))?; self.out_of_band.insert( From a5ae36f5baf06afbfa8595aaa536213def261b05 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 18:17:55 +1000 Subject: [PATCH 13/32] include invitation id Signed-off-by: George Mulhearn --- .../state_machine/requester/helpers.rs | 29 +++++++++---------- .../requester/request_sent/mod.rs | 3 +- .../states/requester/request_sent.rs | 9 ++++-- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index 6d7fc3f366..12d0415e32 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -49,22 +49,19 @@ pub fn construct_request( .build() } -pub fn construct_didexchange_complete(request_id: String, version: DidExchangeTypeV1) -> Complete { - // assuming we'd want to support RFC 100% and include pthread in complete message, we can add - // new function argument: `invitation_id: Option` - // We choose not to do this, as it's rather historic artifact and doesn't have justification in - // practice see https://github.com/hyperledger/aries-rfcs/issues/817 - // We can then build thread decorator conditionally: - // let thread = match invitation_id { - // Some(invitation_id) => Thread::builder() - // .thid(request_id) - // .pthid(invitation_id) - // .build(), - // None => Thread::builder() - // .thid(request_id) - // .build() - // }; - let thread = Thread::builder().thid(request_id).build(); +pub fn construct_didexchange_complete( + // pthid inclusion is overkill in practice, but needed. see: https://github.com/hyperledger/aries-rfcs/issues/817 + invitation_id: Option, + request_id: String, + version: DidExchangeTypeV1, +) -> Complete { + let thread = match invitation_id { + Some(invitation_id) => Thread::builder() + .thid(request_id) + .pthid(invitation_id) + .build(), + None => Thread::builder().thid(request_id).build(), + }; let decorators = CompleteDecorators::builder() .thread(thread) .timing(Timing::builder().out_time(Utc::now()).build()) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 170a18a176..6fbeef7b29 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -57,6 +57,7 @@ impl DidExchangeRequester { state: DidExchangeRequester::from_parts( RequestSent { request_id: request.id.clone(), + invitation_id, }, their_did_document, our_did_document, @@ -111,7 +112,7 @@ impl DidExchangeRequester { }; let complete_message = - construct_didexchange_complete(self.state.request_id.clone(), version); + construct_didexchange_complete(self.state.invitation_id, self.state.request_id.clone(), version); debug!( "DidExchangeRequester::receive_response << complete_message: {:?}", complete_message diff --git a/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs b/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs index 6f844b217a..c2bd03b778 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs @@ -2,9 +2,12 @@ use crate::protocols::did_exchange::states::traits::ThreadId; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct RequestSent { - pub request_id: String, /* Note: Historical artifact in Aries RFC, used to fill pthread - * value in Complete message See more info here: https://github.com/hyperledger/aries-rfcs/issues/817 - * pub invitation_id: Option */ + pub request_id: String, + /* Note: Historical artifact in Aries RFC, used to fill pthread + * value in Complete message + * See more info here: https://github.com/hyperledger/aries-rfcs/issues/817 + */ + pub invitation_id: Option, } impl ThreadId for RequestSent { From 83a251079f7f5503ff8d920af59fa80aeed996f6 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 19 Jun 2024 18:39:57 +1000 Subject: [PATCH 14/32] pthid in response (for acapy) Signed-off-by: George Mulhearn --- .../did_exchange/state_machine/helpers.rs | 24 +++++++++++++++++-- .../responder/response_sent/mod.rs | 9 +++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 84f12b03ea..fff419df83 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -44,16 +44,26 @@ use crate::{ }; pub(crate) fn construct_response_v1_0( + // pthid inclusion is overkill in practice, but needed. see: https://github.com/hyperledger/aries-rfcs/issues/817 + request_pthid: Option, request_id: String, did: &Did, signed_diddoc_attach: Attachment, ) -> ResponseV1_0 { + let thread = match request_pthid { + Some(request_pthid) => Thread::builder() + .thid(request_id) + .pthid(request_pthid) + .build(), + None => Thread::builder().thid(request_id).build(), + }; + let content = ResponseV1_0Content::builder() .did(did.to_string()) .did_doc(Some(signed_diddoc_attach)) .build(); let decorators = ResponseDecorators::builder() - .thread(Thread::builder().thid(request_id).build()) + .thread(thread) .timing(Timing::builder().out_time(Utc::now()).build()) .build(); ResponseV1_0::builder() @@ -64,16 +74,26 @@ pub(crate) fn construct_response_v1_0( } pub(crate) fn construct_response_v1_1( + // pthid inclusion is overkill in practice, but needed. see: https://github.com/hyperledger/aries-rfcs/issues/817 + request_pthid: Option, request_id: String, did: &Did, signed_didrotate_attach: Attachment, ) -> ResponseV1_1 { + let thread = match request_pthid { + Some(request_pthid) => Thread::builder() + .thid(request_id) + .pthid(request_pthid) + .build(), + None => Thread::builder().thid(request_id).build(), + }; + let content = ResponseV1_1Content::builder() .did(did.to_string()) .did_rotate(signed_didrotate_attach) .build(); let decorators = ResponseDecorators::builder() - .thread(Thread::builder().thid(request_id).build()) + .thread(thread) .timing(Timing::builder().out_time(Utc::now()).build()) .build(); ResponseV1_1::builder() diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 1b8d100969..4fa2c20392 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -64,14 +64,19 @@ impl DidExchangeResponder { } }; + let request_id = request.id.clone(); + let request_pthid = request.decorators.thread.and_then(|thid| thid.pthid); + let response = match version { DidExchangeTypeV1::V1_1(_) => AnyResponse::V1_1(construct_response_v1_1( - request.id.clone(), + request_pthid, + request_id, our_peer_did.did(), attachment, )), DidExchangeTypeV1::V1_0(_) => AnyResponse::V1_0(construct_response_v1_0( - request.id.clone(), + request_pthid, + request_id, our_peer_did.did(), attachment, )), From 5a5e3277beca14ea8232acda90f82b16eae18371 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Thu, 20 Jun 2024 07:41:37 +1000 Subject: [PATCH 15/32] merge fix and add hack for local aath testing Signed-off-by: George Mulhearn --- aries/agents/aries-vcx-agent/src/http.rs | 4 +++- .../src/protocols/did_exchange/state_machine/helpers.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/aries/agents/aries-vcx-agent/src/http.rs b/aries/agents/aries-vcx-agent/src/http.rs index e141a865d1..3efbca6b86 100644 --- a/aries/agents/aries-vcx-agent/src/http.rs +++ b/aries/agents/aries-vcx-agent/src/http.rs @@ -6,7 +6,9 @@ pub struct VcxHttpClient; #[async_trait] impl Transport for VcxHttpClient { - async fn send_message(&self, msg: Vec, service_endpoint: &Url) -> VcxResult<()> { + async fn send_message(&self, msg: Vec, _service_endpoint: &Url) -> VcxResult<()> { + // TODO - 1288 - REMOVE THIS. + let service_endpoint = &"http://localhost:9031".parse().unwrap(); shared::http_client::post_message(msg, service_endpoint).await?; Ok(()) } diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index b126a54d4e..8771dc2ab5 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -168,7 +168,7 @@ pub(crate) fn ddo_to_attach(ddo: DidDocument) -> Result Attachment { - let content_b64 = base64::engine::Engine::encode(&URL_SAFE_NO_PAD, did.id()); + let content_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, did.id()); Attachment::builder() .data( AttachmentData::builder() From c173cdac62e85f58f7ba8eecb1058e37185b7324 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Thu, 20 Jun 2024 14:12:52 +1000 Subject: [PATCH 16/32] fixes for didpeer2 Signed-off-by: George Mulhearn --- .../peer_did/numalgos/numalgo2/encoding.rs | 8 -- .../src/peer_did/numalgos/numalgo2/helpers.rs | 24 ++-- .../src/peer_did/numalgos/numalgo2/mod.rs | 107 ++++++++++++++++-- .../numalgos/numalgo2/service_abbreviation.rs | 40 +++---- .../numalgos/numalgo2/verification_method.rs | 40 ++++--- 5 files changed, 153 insertions(+), 66 deletions(-) diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs index f973619e0d..6c26dacac8 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs @@ -26,14 +26,6 @@ pub(crate) fn append_encoded_key_segments( for ka in did_document.key_agreement() { did = append_encoded_key_segment(did, did_document, ka, ElementPurpose::Encryption)?; } - for vm in did_document.verification_method() { - did = append_encoded_key_segment( - did, - did_document, - &VerificationMethodKind::Resolved(vm.to_owned()), - ElementPurpose::Verification, - )?; - } for a in did_document.authentication() { did = append_encoded_key_segment(did, did_document, a, ElementPurpose::Verification)?; } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs index 29ea1fbcf7..7d7776b6cc 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs @@ -19,6 +19,7 @@ pub fn diddoc_from_peerdid2_elements( public_key_encoding: PublicKeyEncoding, ) -> Result { let mut service_index: usize = 0; + let mut vm_index: usize = 1; // Skipping one here because the first element is empty string for element in did.id()[1..].split('.').skip(1) { @@ -26,6 +27,7 @@ pub fn diddoc_from_peerdid2_elements( element, did_doc, &mut service_index, + &mut vm_index, did, public_key_encoding, )?; @@ -38,6 +40,7 @@ fn add_attributes_from_element( element: &str, mut did_doc: DidDocument, service_index: &mut usize, + vm_index: &mut usize, did: &Did, public_key_encoding: PublicKeyEncoding, ) -> Result { @@ -57,6 +60,7 @@ fn add_attributes_from_element( did_doc = add_key_from_element( purposeless_element, did_doc, + vm_index, did, public_key_encoding, purpose, @@ -83,26 +87,30 @@ fn add_service_from_element( fn add_key_from_element( element: &str, mut did_doc: DidDocument, + vm_index: &mut usize, did: &Did, public_key_encoding: PublicKeyEncoding, purpose: ElementPurpose, ) -> Result { let key = Key::from_fingerprint(element)?; - let vms = get_verification_methods_by_key(&key, did, public_key_encoding)?; + let vms = get_verification_methods_by_key(&key, did, public_key_encoding, vm_index)?; for vm in vms.into_iter() { + let vm_reference = vm.id().to_owned(); + did_doc.add_verification_method(vm); + // https://identity.foundation/peer-did-method-spec/#purpose-codes match purpose { ElementPurpose::Assertion => { - did_doc.add_assertion_method_object(vm); + did_doc.add_assertion_method_ref(vm_reference); } ElementPurpose::Encryption => { - did_doc.add_key_agreement_object(vm); + did_doc.add_key_agreement_ref(vm_reference); } ElementPurpose::Verification => { - did_doc.add_verification_method(vm); + did_doc.add_authentication_ref(vm_reference); } - ElementPurpose::CapabilityInvocation => did_doc.add_capability_invocation_object(vm), - ElementPurpose::CapabilityDelegation => did_doc.add_capability_delegation_object(vm), + ElementPurpose::CapabilityInvocation => did_doc.add_capability_invocation_ref(vm_reference), + ElementPurpose::CapabilityDelegation => did_doc.add_capability_delegation_ref(vm_reference), _ => return Err(DidPeerError::UnsupportedPurpose(purpose.into())), } } @@ -204,6 +212,7 @@ mod tests { let did_doc = add_key_from_element( purposeless_key_element, ddo_builder, + &mut 0, &did, public_key_encoding, ElementPurpose::Verification, @@ -212,7 +221,7 @@ mod tests { assert_eq!(did_doc.verification_method().len(), 1); let vm = did_doc.verification_method().first().unwrap(); - assert_eq!(vm.id().to_string(), "#6MkqRYqQ"); + assert_eq!(vm.id().to_string(), "#key-0"); assert_eq!(vm.controller().to_string(), did.to_string()); } @@ -222,6 +231,7 @@ mod tests { assert!(add_key_from_element( "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V", DidDocument::new(did.clone()), + &mut 0, &did, PublicKeyEncoding::Multibase, ElementPurpose::Service diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/mod.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/mod.rs index c561acbc97..49d70f189a 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/mod.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/mod.rs @@ -62,7 +62,11 @@ impl Numalgo for Numalgo2 { #[cfg(test)] mod test { - use did_doc::schema::did_doc::DidDocument; + use did_doc::schema::{ + did_doc::DidDocument, service::service_key_kind::ServiceKeyKind, + verification_method::PublicKeyField, + }; + use did_parser_nom::DidUrl; use pretty_assertions::assert_eq; use serde_json::{from_value, json}; @@ -73,25 +77,31 @@ mod test { #[test] fn test_peer_did_2_encode_decode() { + // NOTE 20/6/24: universal resolver resolves an additional "assertionMethod" key for the "V" + // key despite the spec not saying to do this. let expected_did_peer = "did:peer:2.Ez6MkkukgyKAdBN46UAHvia2nxmioo74F6YdvW1nBT1wfKKha.Vz6MkfoapUdLHHgSMq5PYhdHYCoqGuRku2i17cQ9zAoR5cLSm.SeyJpZCI6IiNmb29iYXIiLCJ0IjpbImRpZC1jb21tdW5pY2F0aW9uIl0sInMiOiJodHRwOi8vZHVtbXl1cmwub3JnLyIsInIiOlsiIzZNa2t1a2d5Il0sImEiOlsiZGlkY29tbS9haXAyO2Vudj1yZmMxOSJdfQ"; let value = json!({ "id": expected_did_peer, "verificationMethod": [ { - "id": "#6MkfoapU", + "id": "#key-1", "controller": expected_did_peer, "type": "Ed25519VerificationKey2020", - "publicKeyBase58": "2MKmtP5qx8wtiaYr24KhMiHH5rV3cpkkvPF4LXT4h7fP" - } - ], - "keyAgreement": [ + "publicKeyMultibase": "z6MkkukgyKAdBN46UAHvia2nxmioo74F6YdvW1nBT1wfKKha" + }, { - "id": "#6Mkkukgy", + "id": "#key-2", "controller": expected_did_peer, "type": "Ed25519VerificationKey2020", - "publicKeyBase58": "7TVeP4vBqpZdMfTE314x7gAoyXnPgfPZozsFcjyeQ6vC" + "publicKeyMultibase": "z6MkfoapUdLHHgSMq5PYhdHYCoqGuRku2i17cQ9zAoR5cLSm" } ], + "keyAgreement": [ + "#key-1" + ], + "authentication": [ + "#key-2" + ], "service": [ { "id": "#foobar", @@ -111,8 +121,87 @@ mod test { assert_eq!(did_peer.to_string(), expected_did_peer); let ddo_decoded: DidDocument = did_peer - .to_did_doc_builder(PublicKeyEncoding::Base58) + .to_did_doc_builder(PublicKeyEncoding::Multibase) .unwrap(); + dbg!(&ddo_decoded); assert_eq!(ddo_original, ddo_decoded); } + + #[test] + fn test_acapy_did_peer_2() { + // test vector from AATH testing with acapy 0.12.1 + let did = "did:peer:2.Vz6MkqY3gWxHEp47gCXBmnc5k7sAQChwV76YpZAHZ8erDHatK.SeyJpZCI6IiNkaWRjb21tLTAiLCJ0IjoiZGlkLWNvbW11bmljYXRpb24iLCJwcmlvcml0eSI6MCwicmVjaXBpZW50S2V5cyI6WyIja2V5LTEiXSwiciI6W10sInMiOiJodHRwOi8vaG9zdC5kb2NrZXIuaW50ZXJuYWw6OTAzMSJ9"; + let did = PeerDid::::parse(did).unwrap(); + + let doc = did + .to_did_doc_builder(PublicKeyEncoding::Multibase) + .unwrap(); + assert_eq!(doc.verification_method().len(), 1); + let vm = doc.verification_method_by_id("key-1").unwrap(); + assert_eq!( + vm.public_key().unwrap().fingerprint(), + "z6MkqY3gWxHEp47gCXBmnc5k7sAQChwV76YpZAHZ8erDHatK" + ); + assert_eq!( + vm.public_key_field(), + &PublicKeyField::Multibase { + public_key_multibase: String::from( + "z6MkqY3gWxHEp47gCXBmnc5k7sAQChwV76YpZAHZ8erDHatK" + ) + } + ); + + assert_eq!(doc.service().len(), 1); + let service = doc + .get_service_by_id(&"#didcomm-0".parse().unwrap()) + .unwrap(); + assert_eq!( + service.service_endpoint().to_string(), + "http://host.docker.internal:9031/" + ); + let recips = service.extra_field_recipient_keys().unwrap(); + assert_eq!(recips.len(), 1); + assert_eq!( + recips[0], + ServiceKeyKind::Reference(DidUrl::parse("#key-1".to_string()).unwrap()) + ); + } + + #[test] + fn test_resolving_spec_defined_example() { + // https://identity.foundation/peer-did-method-spec/#example-peer-did-2 + // NOTE: excluding the services, as they use a different type of service to the typical + // service DIDDoc structure + let did = "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.\ + Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR"; + let did = PeerDid::::parse(did).unwrap(); + + let doc = did + .to_did_doc_builder(PublicKeyEncoding::Multibase) + .unwrap(); + let expected_doc: DidDocument = serde_json::from_value(json!({ + "id": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR", + "verificationMethod": [ + { + "id": "#key-1", + "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR", + "type": "Ed25519VerificationKey2020", + "publicKeyMultibase": "z6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc" + }, + { + "id": "#key-2", + "controller": "did:peer:2.Vz6Mkj3PUd1WjvaDhNZhhhXQdz5UnZXmS7ehtx8bsPpD47kKc.Ez6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR", + "type": "X25519KeyAgreementKey2020", + "publicKeyMultibase": "z6LSg8zQom395jKLrGiBNruB9MM6V8PWuf2FpEy4uRFiqQBR" + } + ], + "authentication": [ + "#key-1" + ], + "keyAgreement": [ + "#key-2" + ] + })).unwrap(); + assert_eq!(doc, expected_doc); + } } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/service_abbreviation.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/service_abbreviation.rs index d3810e22e7..739b865072 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/service_abbreviation.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/service_abbreviation.rs @@ -9,7 +9,7 @@ use did_doc::schema::{ utils::OneOrList, }; use serde::{Deserialize, Serialize}; -use serde_json::from_value; +use serde_json::{from_value, Value}; use url::Url; use crate::error::DidPeerError; @@ -32,6 +32,9 @@ pub struct ServiceAbbreviatedDidPeer2 { #[serde(default)] #[serde(skip_serializing_if = "Vec::is_empty")] accept: Vec, + #[serde(flatten)] + #[serde(skip_serializing_if = "HashMap::is_empty")] + extra: HashMap, } impl ServiceAbbreviatedDidPeer2 { @@ -48,24 +51,9 @@ impl ServiceAbbreviatedDidPeer2 { service_endpoint, routing_keys, accept, + extra: Default::default(), } } - - pub fn service_type(&self) -> &OneOrList { - &self.service_type - } - - pub fn service_endpoint(&self) -> &Url { - &self.service_endpoint - } - - pub fn routing_keys(&self) -> &[ServiceKeyKind] { - &self.routing_keys - } - - pub fn accept(&self) -> &[ServiceAcceptType] { - &self.accept - } } // todo: This is encoding is lossy but shouldn't be. @@ -139,7 +127,7 @@ pub(crate) fn deabbreviate_service( abbreviated: ServiceAbbreviatedDidPeer2, index: usize, ) -> Result { - let service_type = match abbreviated.service_type().clone() { + let service_type = match abbreviated.service_type { OneOrList::One(service_type) => { let typed = match service_type.as_str() { "dm" => ServiceType::DIDCommV2, @@ -167,23 +155,25 @@ pub(crate) fn deabbreviate_service( let mut service = Service::new( id, - abbreviated.service_endpoint().clone(), + abbreviated.service_endpoint, service_type, - HashMap::default(), + abbreviated.extra, ); - let routing_keys = abbreviated.routing_keys(); + let routing_keys = abbreviated.routing_keys; if !routing_keys.is_empty() { - service.add_extra_field_routing_keys(routing_keys.to_vec())?; + service.add_extra_field_routing_keys(routing_keys)?; } - let accept = abbreviated.accept(); + let accept = abbreviated.accept; if !accept.is_empty() { - service.add_extra_field_accept(accept.to_vec())?; + service.add_extra_field_accept(accept)?; } Ok(service) } #[cfg(test)] mod tests { + use std::collections::HashMap; + use did_doc::schema::{ service::{ service_accept_type::ServiceAcceptType, service_key_kind::ServiceKeyKind, @@ -207,6 +197,7 @@ mod tests { service_endpoint: Url::parse("https://example.org").unwrap(), routing_keys: vec![], accept: vec![], + extra: HashMap::new(), }; let index = 0; @@ -230,6 +221,7 @@ mod tests { service_endpoint: service_endpoint.clone(), routing_keys: routing_keys.clone(), accept: accept.clone(), + extra: HashMap::new(), }; let index = 0; diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs index d493b25cde..657becc81e 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/verification_method.rs @@ -10,8 +10,8 @@ pub fn get_verification_methods_by_key( key: &Key, did: &Did, public_key_encoding: PublicKeyEncoding, + vm_index: &mut usize, ) -> Result, DidPeerError> { - let id = to_did_url_reference(key)?; let vm_type = match key.key_type() { KeyType::Ed25519 => VerificationMethodType::Ed25519VerificationKey2020, KeyType::Bls12381g1 => VerificationMethodType::Bls12381G1Key2020, @@ -26,16 +26,18 @@ pub fn get_verification_methods_by_key( &Key::new(key.key()[48..].to_vec(), KeyType::Bls12381g2)?, did.to_owned(), public_key_encoding, + vm_index, )); } }; - Ok(build_verification_methods_from_type_and_key( + + build_verification_methods_from_type_and_key( vm_type, key, - id, did.to_owned(), public_key_encoding, - )) + vm_index, + ) } pub fn get_key_by_verification_method(vm: &VerificationMethod) -> Result { @@ -58,17 +60,20 @@ pub fn get_key_by_verification_method(vm: &VerificationMethod) -> Result Vec { + vm_index: &mut usize, +) -> Result, DidPeerError> { + let id = nth_key_did_url_reference(*vm_index)?; + *vm_index += 1; + let vm = VerificationMethod::builder() .id(id) - .controller(did.to_owned()) + .controller(did) .verification_method_type(vm_type) .public_key(key_to_key_field(key, public_key_encoding)) .build(); - vec![vm] + Ok(vec![vm]) } fn build_verification_methods_from_bls_multikey( @@ -76,9 +81,12 @@ fn build_verification_methods_from_bls_multikey( g2_key: &Key, did: Did, public_key_encoding: PublicKeyEncoding, + vm_index: &mut usize, ) -> Vec { - let id1 = to_did_url_reference(g1_key).unwrap(); - let id2 = to_did_url_reference(g2_key).unwrap(); + let id1 = nth_key_did_url_reference(*vm_index).unwrap(); + *vm_index += 1; + let id2 = nth_key_did_url_reference(*vm_index).unwrap(); + *vm_index += 1; let vm1 = VerificationMethod::builder() .id(id1) .controller(did.to_owned()) @@ -105,14 +113,8 @@ fn key_to_key_field(key: &Key, public_key_encoding: PublicKeyEncoding) -> Public } } -fn to_did_url_reference(key: &Key) -> Result { - DidUrl::from_fragment( - key.prefixless_fingerprint() - .chars() - .take(8) - .collect::(), - ) - .map_err(Into::into) +fn nth_key_did_url_reference(n: usize) -> Result { + DidUrl::from_fragment(format!("key-{n}")).map_err(Into::into) } #[cfg(test)] @@ -188,6 +190,7 @@ mod tests { key, &did(), PublicKeyEncoding::Multibase, + &mut 0, ) .unwrap(); assert_eq!(vms.len(), 1); @@ -204,6 +207,7 @@ mod tests { key, &did(), PublicKeyEncoding::Base58, + &mut 0, ) .unwrap(); assert_eq!(vms.len(), 1); From 55a799175bd54a9b96ae68afa7a30c4ed4245cb6 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Fri, 21 Jun 2024 08:21:10 +1000 Subject: [PATCH 17/32] improve VM handling to understand more DIDDoc styles (acapy AATH testing) Signed-off-by: George Mulhearn --- .../did_exchange/state_machine/helpers.rs | 6 ++- aries/aries_vcx/src/utils/didcomm_utils.rs | 52 ++++++++++++++----- .../src/utils/encryption_envelope.rs | 19 +++++-- did_core/did_doc/src/schema/did_doc.rs | 25 ++++++++- .../verification_method_kind.rs | 10 ++++ .../numalgos/numalgo4/construction_did_doc.rs | 4 +- 6 files changed, 93 insertions(+), 23 deletions(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 8771dc2ab5..176c31193f 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -134,14 +134,16 @@ pub async fn create_peer_did_4( info!("Prepared service for peer:did:4 generation: {} ", service); let vm_ka = DidPeer4VerificationMethod::builder() - .id(vm_ka_id) + .id(vm_ka_id.clone()) .verification_method_type(VerificationMethodType::Ed25519VerificationKey2020) .public_key(PublicKeyField::Multibase { public_key_multibase: key_enc.fingerprint(), }) .build(); let mut construction_did_doc = DidPeer4ConstructionDidDocument::new(); - construction_did_doc.add_key_agreement(vm_ka); + construction_did_doc.add_verification_method(vm_ka); + construction_did_doc.add_key_agreement_ref(vm_ka_id); + construction_did_doc.add_service(service); info!( diff --git a/aries/aries_vcx/src/utils/didcomm_utils.rs b/aries/aries_vcx/src/utils/didcomm_utils.rs index c231af9469..10ffe90c7d 100644 --- a/aries/aries_vcx/src/utils/didcomm_utils.rs +++ b/aries/aries_vcx/src/utils/didcomm_utils.rs @@ -34,8 +34,8 @@ fn resolve_service_key_to_typed_key( } } -/// Resolves the first ed25519 base58 public key (a.k.a. verkey) within the DIDDocuments key agreement -/// keys. Useful for resolving keys that can be used for packing DIDCommV1 messages. +/// Resolves the first ed25519 base58 public key (a.k.a. verkey) within the DIDDocuments key +/// agreement keys. Useful for resolving keys that can be used for packing DIDCommV1 messages. pub fn resolve_ed25519_base58_key_agreement(did_document: &DidDocument) -> VcxResult { let vm_types = [ VerificationMethodType::Ed25519VerificationKey2018, @@ -61,17 +61,45 @@ pub fn resolve_ed25519_base58_key_agreement(did_document: &DidDocument) -> VcxRe Ok(vm.public_key()?.base58()) } -pub fn get_routing_keys(their_did_doc: &DidDocument, service_id: &Uri) -> VcxResult> { +pub fn get_ed25519_base58_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, their_did_doc)?.base58()); - } - Ok(naked_routing_keys) + let Ok(routing_keys) = service.extra_field_routing_keys() else { + return Ok(vec![]); + }; + + let mut naked_routing_keys = Vec::new(); + + for key in routing_keys.iter() { + let pub_key = resolve_service_key_to_typed_key(key, their_did_doc)?; + + if pub_key.key_type() == &KeyType::Ed25519 { + naked_routing_keys.push(pub_key.base58()); + } + } + + Ok(naked_routing_keys) +} + +pub fn get_ed25519_base58_recipient_keys( + their_did_doc: &DidDocument, + service_id: &Uri, +) -> VcxResult> { + let service = their_did_doc.get_service_by_id(service_id)?; + let Ok(recipient_keys) = service.extra_field_recipient_keys() else { + return Ok(vec![]); + }; + + let mut naked_recipient_keys = Vec::new(); + + for key in recipient_keys.iter() { + let pub_key = resolve_service_key_to_typed_key(key, their_did_doc)?; + if pub_key.key_type() == &KeyType::Ed25519 { + naked_recipient_keys.push(pub_key.base58()); } - Err(_err) => Ok(Vec::new()), } + + Ok(naked_recipient_keys) } diff --git a/aries/aries_vcx/src/utils/encryption_envelope.rs b/aries/aries_vcx/src/utils/encryption_envelope.rs index d21269d326..30fc4e75a9 100644 --- a/aries/aries_vcx/src/utils/encryption_envelope.rs +++ b/aries/aries_vcx/src/utils/encryption_envelope.rs @@ -8,9 +8,10 @@ use messages::{ use public_key::{Key, KeyType}; use uuid::Uuid; +use super::didcomm_utils::get_ed25519_base58_recipient_keys; use crate::{ errors::error::prelude::*, - utils::didcomm_utils::{get_routing_keys, resolve_ed25519_base58_key_agreement}, + utils::didcomm_utils::{get_ed25519_base58_routing_keys, resolve_ed25519_base58_key_agreement}, }; #[derive(Debug)] @@ -63,9 +64,16 @@ impl EncryptionEnvelope { their_service_id: &Uri, ) -> VcxResult { let sender_vk = resolve_ed25519_base58_key_agreement(our_did_doc)?; - // CONSIDER - or should recipient keys be resolved from the service? similar to get_routing_keys. - let recipient_key = resolve_ed25519_base58_key_agreement(their_did_doc)?; - let routing_keys = get_routing_keys(their_did_doc, their_service_id)?; + + let recipient_key = { + let service_keys = get_ed25519_base58_recipient_keys(their_did_doc, their_service_id)?; + match service_keys.into_iter().next() { + Some(key) => key, + // as a backup, use the first key agreement key, or none + None => resolve_ed25519_base58_key_agreement(their_did_doc)?, + } + }; + let routing_keys = get_ed25519_base58_routing_keys(their_did_doc, their_service_id)?; EncryptionEnvelope::create_from_keys( wallet, @@ -81,7 +89,8 @@ impl EncryptionEnvelope { wallet: &impl BaseWallet, data: &[u8], sender_vk: Option<&str>, - // TODO - why not have encryption envelope take typed [Key]s, and enforce they are KeyType::Ed25519 + // TODO - why not have encryption envelope take typed [Key]s, and enforce they are + // KeyType::Ed25519 recipient_key: String, routing_keys: Vec, ) -> VcxResult { diff --git a/did_core/did_doc/src/schema/did_doc.rs b/did_core/did_doc/src/schema/did_doc.rs index e955316031..50423c6eaf 100644 --- a/did_core/did_doc/src/schema/did_doc.rs +++ b/did_core/did_doc/src/schema/did_doc.rs @@ -187,10 +187,31 @@ impl DidDocument { self.extra.get(key) } + /// Scan the DIDDocument for a [VerificationMethod] that matches the given reference. pub fn dereference_key(&self, reference: &DidUrl) -> Option<&VerificationMethod> { - self.verification_method + let vms = self.verification_method.iter(); + + // keys are typically in the VMs ^, but may be embedded in the other fields: + let assertions = self.assertion_method.iter().filter_map(|k| k.resolved()); + let key_agreements = self.key_agreement.iter().filter_map(|k| k.resolved()); + let authentications = self.authentication.iter().filter_map(|k| k.resolved()); + let cap_invocations = self + .capability_invocation + .iter() + .filter_map(|k| k.resolved()); + let cap_delegations = self + .capability_delegation .iter() - .find(|vm| vm.id().fragment() == reference.fragment()) + .filter_map(|k| k.resolved()); + + let mut all_vms = vms + .chain(assertions) + .chain(key_agreements) + .chain(authentications) + .chain(cap_invocations) + .chain(cap_delegations); + + all_vms.find(|vm| vm.id().fragment() == reference.fragment()) } pub fn validate(&self) -> Result<(), DidDocumentBuilderError> { diff --git a/did_core/did_doc/src/schema/verification_method/verification_method_kind.rs b/did_core/did_doc/src/schema/verification_method/verification_method_kind.rs index 20b11b33f0..3d5aa2916c 100644 --- a/did_core/did_doc/src/schema/verification_method/verification_method_kind.rs +++ b/did_core/did_doc/src/schema/verification_method/verification_method_kind.rs @@ -12,3 +12,13 @@ pub enum VerificationMethodKind { Resolved(VerificationMethod), Resolvable(DidUrl), } + +impl VerificationMethodKind { + /// Convenience function to try get the resolved enum variant (if it is that variant) + pub fn resolved(&self) -> Option<&VerificationMethod> { + match &self { + VerificationMethodKind::Resolved(x) => Some(x), + VerificationMethodKind::Resolvable(_) => None, + } + } +} diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/construction_did_doc.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/construction_did_doc.rs index f2c4be1fa0..88a6e32d0e 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/construction_did_doc.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/construction_did_doc.rs @@ -142,9 +142,9 @@ impl DidPeer4ConstructionDidDocument { .push(DidPeer4VerificationMethodKind::Resolved(method)); } - pub fn add_key_agreement_ref(&mut self, refernece: DidUrl) { + pub fn add_key_agreement_ref(&mut self, reference: DidUrl) { self.key_agreement - .push(DidPeer4VerificationMethodKind::Resolvable(refernece)); + .push(DidPeer4VerificationMethodKind::Resolvable(reference)); } pub fn add_capability_invocation(&mut self, method: DidPeer4VerificationMethod) { From 3121644ccc398059d044f1ace1b31d9ee6acf2fd Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Fri, 21 Jun 2024 10:02:22 +1000 Subject: [PATCH 18/32] fmt Signed-off-by: George Mulhearn --- aries/agents/aries-vcx-agent/src/http.rs | 4 +--- aries/aries_vcx/src/handlers/util.rs | 4 +++- .../state_machine/requester/request_sent/mod.rs | 7 +++++-- .../did_exchange/states/requester/request_sent.rs | 2 +- aries/aries_vcx/tests/test_did_exchange.rs | 5 ++++- did_core/did_doc/src/schema/verification_method/mod.rs | 2 +- .../did_peer/src/peer_did/numalgos/numalgo2/helpers.rs | 8 ++++++-- .../did_peer/src/peer_did/numalgos/numalgo4/mod.rs | 9 +++++---- 8 files changed, 26 insertions(+), 15 deletions(-) diff --git a/aries/agents/aries-vcx-agent/src/http.rs b/aries/agents/aries-vcx-agent/src/http.rs index 3efbca6b86..e141a865d1 100644 --- a/aries/agents/aries-vcx-agent/src/http.rs +++ b/aries/agents/aries-vcx-agent/src/http.rs @@ -6,9 +6,7 @@ pub struct VcxHttpClient; #[async_trait] impl Transport for VcxHttpClient { - async fn send_message(&self, msg: Vec, _service_endpoint: &Url) -> VcxResult<()> { - // TODO - 1288 - REMOVE THIS. - let service_endpoint = &"http://localhost:9031".parse().unwrap(); + async fn send_message(&self, msg: Vec, service_endpoint: &Url) -> VcxResult<()> { shared::http_client::post_message(msg, service_endpoint).await?; Ok(()) } diff --git a/aries/aries_vcx/src/handlers/util.rs b/aries/aries_vcx/src/handlers/util.rs index 3ee2ac9e2f..4dacce738a 100644 --- a/aries/aries_vcx/src/handlers/util.rs +++ b/aries/aries_vcx/src/handlers/util.rs @@ -75,7 +75,9 @@ macro_rules! make_attach_from_str { .data(attach_data) .build(); attach.id = Some($id); - attach.mime_type = Some(shared::maybe_known::MaybeKnown::Known(messages::misc::MimeType::Json)); + attach.mime_type = Some(shared::maybe_known::MaybeKnown::Known( + messages::misc::MimeType::Json, + )); attach }}; } diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 6fbeef7b29..cf42814c9e 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -111,8 +111,11 @@ impl DidExchangeRequester { did_document }; - let complete_message = - construct_didexchange_complete(self.state.invitation_id, self.state.request_id.clone(), version); + let complete_message = construct_didexchange_complete( + self.state.invitation_id, + self.state.request_id.clone(), + version, + ); debug!( "DidExchangeRequester::receive_response << complete_message: {:?}", complete_message diff --git a/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs b/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs index c2bd03b778..dcfb89ebfa 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/states/requester/request_sent.rs @@ -4,7 +4,7 @@ use crate::protocols::did_exchange::states::traits::ThreadId; pub struct RequestSent { pub request_id: String, /* Note: Historical artifact in Aries RFC, used to fill pthread - * value in Complete message + * value in Complete message * See more info here: https://github.com/hyperledger/aries-rfcs/issues/817 */ pub invitation_id: Option, diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index a340c59e06..ee6a846224 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -14,7 +14,10 @@ use aries_vcx::{ states::{requester::request_sent::RequestSent, responder::response_sent::ResponseSent}, transition::transition_result::TransitionResult, }, - utils::{didcomm_utils::resolve_ed25519_base58_key_agreement, encryption_envelope::EncryptionEnvelope}, + utils::{ + didcomm_utils::resolve_ed25519_base58_key_agreement, + encryption_envelope::EncryptionEnvelope, + }, }; use aries_vcx_ledger::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; use did_doc::schema::{ diff --git a/did_core/did_doc/src/schema/verification_method/mod.rs b/did_core/did_doc/src/schema/verification_method/mod.rs index 9e0bb57290..0198c2acef 100644 --- a/did_core/did_doc/src/schema/verification_method/mod.rs +++ b/did_core/did_doc/src/schema/verification_method/mod.rs @@ -52,7 +52,7 @@ impl VerificationMethod { self.public_key.key_decoded()?, self.verification_method_type.try_into()?, )?, - }; + }; Ok(key) } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs index 7d7776b6cc..1e19b3b089 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/helpers.rs @@ -109,8 +109,12 @@ fn add_key_from_element( ElementPurpose::Verification => { did_doc.add_authentication_ref(vm_reference); } - ElementPurpose::CapabilityInvocation => did_doc.add_capability_invocation_ref(vm_reference), - ElementPurpose::CapabilityDelegation => did_doc.add_capability_delegation_ref(vm_reference), + ElementPurpose::CapabilityInvocation => { + did_doc.add_capability_invocation_ref(vm_reference) + } + ElementPurpose::CapabilityDelegation => { + did_doc.add_capability_delegation_ref(vm_reference) + } _ => return Err(DidPeerError::UnsupportedPurpose(purpose.into())), } } diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs index 4aa1c43d8f..a726673d6a 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo4/mod.rs @@ -278,10 +278,11 @@ mod tests { service.service_endpoint().to_string(), "http://host.docker.internal:9031/" ); - let service_recip = service - .extra_field_recipient_keys() - .unwrap(); - assert_eq!(service_recip, vec![ServiceKeyKind::Reference("#key-0".parse().unwrap())]); + let service_recip = service.extra_field_recipient_keys().unwrap(); + assert_eq!( + service_recip, + vec![ServiceKeyKind::Reference("#key-0".parse().unwrap())] + ); log::info!( "resolved document: {}", serde_json::to_string_pretty(&resolved_did_doc).unwrap() From ba3570ad7912aa8b5ffdede1a09020b4d08d3fba Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Fri, 21 Jun 2024 10:27:20 +1000 Subject: [PATCH 19/32] clean switcher Signed-off-by: George Mulhearn --- aries/aries_vcx/src/handlers/util.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/aries/aries_vcx/src/handlers/util.rs b/aries/aries_vcx/src/handlers/util.rs index 4dacce738a..2ed30d0c75 100644 --- a/aries/aries_vcx/src/handlers/util.rs +++ b/aries/aries_vcx/src/handlers/util.rs @@ -243,30 +243,24 @@ pub fn verify_thread_id(thread_id: &str, message: &AriesMessage) -> VcxResult<() AriesMessage::CoordinateMediation(CoordinateMediation::Keylist(msg)) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(msg))) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(msg))) + | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(msg))) => { matches_opt_thread_id!(msg, thread_id) } AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Response(msg))) => { matches_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Complete(msg))) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Complete(msg))) + | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Complete(msg))) => { matches_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::ProblemReport(msg))) => { + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::ProblemReport(msg))) + | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::ProblemReport(msg))) => { matches_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(msg))) => { - matches_opt_thread_id!(msg, thread_id) - } AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Response(msg))) => { matches_thread_id!(msg, thread_id) } - AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Complete(msg))) => { - matches_thread_id!(msg, thread_id) - } - AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::ProblemReport(msg))) => { - matches_thread_id!(msg, thread_id) - } }; if !is_match { From 9866a2a136e12c1b4a52e6cf24a74bfe0421416d Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Fri, 21 Jun 2024 11:15:16 +1000 Subject: [PATCH 20/32] label pass, and some fixes Signed-off-by: George Mulhearn --- .../agents/aries-vcx-agent/src/handlers/did_exchange.rs | 1 + .../protocols/did_exchange/state_machine/generic/mod.rs | 2 ++ .../src/protocols/did_exchange/state_machine/mod.rs | 9 +++------ .../did_exchange/state_machine/requester/helpers.rs | 3 ++- .../state_machine/requester/request_sent/mod.rs | 3 ++- aries/aries_vcx/src/utils/didcomm_utils.rs | 2 ++ aries/aries_vcx/tests/test_did_exchange.rs | 1 + 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index fd5c6b7a84..d5325150f9 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -75,6 +75,7 @@ impl DidcommHandlerDidExchange { invitation_id, &their_did, &our_peer_did, + "".to_owned(), ) .await?; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index 3c0978d660..27a62fae0c 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -89,6 +89,7 @@ impl GenericDidExchange { invitation_id: Option, their_did: &Did, our_peer_did: &PeerDid, + our_label: String, ) -> Result<(Self, Request), AriesVcxError> { let TransitionResult { state, output } = DidExchangeRequester::::construct_request( @@ -96,6 +97,7 @@ impl GenericDidExchange { invitation_id, their_did, our_peer_did, + our_label, ) .await?; Ok(( diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs index 6d585b2a82..e4aee62f37 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs @@ -10,11 +10,8 @@ use chrono::Utc; use did_doc::schema::did_doc::DidDocument; use messages::{ decorators::{thread::Thread, timing::Timing}, - msg_fields::protocols::did_exchange::{ - v1_1::problem_report::ProblemReport as ProblemReportV1_1, - v1_x::problem_report::{ - ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, - }, + msg_fields::protocols::did_exchange::v1_x::problem_report::{ + ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -42,7 +39,7 @@ impl DidExchange { self, reason: String, problem_code: Option, - ) -> TransitionResult, ProblemReportV1_1> { + ) -> TransitionResult, ProblemReport> { let content = ProblemReportContent::builder() .problem_code(problem_code) .explain(Some(reason.clone())) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index 12d0415e32..6eaf6913df 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -22,6 +22,7 @@ use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; pub fn construct_request( invitation_id: Option, our_did: String, + our_label: String, version: DidExchangeTypeV1, ) -> Request { let msg_id = Uuid::new_v4().to_string(); @@ -35,7 +36,7 @@ pub fn construct_request( .timing(Timing::builder().out_time(Utc::now()).build()) .build(); let content = RequestContent::builder() - .label("".into()) + .label(our_label) .did(our_did) .did_doc(None) .goal(Some("To establish a connection".into())) // Rejected if non-empty by acapy diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index cf42814c9e..547f8cab8e 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -29,9 +29,9 @@ impl DidExchangeRequester { pub async fn construct_request( resolver_registry: Arc, invitation_id: Option, - // TODO - label pass thru their_did: &Did, our_peer_did: &PeerDid, + our_label: String, ) -> Result, AriesVcxError> { debug!( "DidExchangeRequester::construct_request >> their_did: {}, our_peer_did: \ @@ -46,6 +46,7 @@ impl DidExchangeRequester { let request = construct_request( invitation_id.clone(), our_peer_did.to_string(), + our_label, DidExchangeTypeV1::new_v1_1(), ); diff --git a/aries/aries_vcx/src/utils/didcomm_utils.rs b/aries/aries_vcx/src/utils/didcomm_utils.rs index 10ffe90c7d..2a369f26ff 100644 --- a/aries/aries_vcx/src/utils/didcomm_utils.rs +++ b/aries/aries_vcx/src/utils/didcomm_utils.rs @@ -40,6 +40,8 @@ pub fn resolve_ed25519_base58_key_agreement(did_document: &DidDocument) -> VcxRe let vm_types = [ VerificationMethodType::Ed25519VerificationKey2018, VerificationMethodType::Ed25519VerificationKey2020, + VerificationMethodType::X25519KeyAgreementKey2019, + VerificationMethodType::X25519KeyAgreementKey2020, VerificationMethodType::Multikey, // would be nice to search for X25519 VM types which could be derived into ed25519 keys // for the encryption envelope to use. diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index ee6a846224..eb791d41be 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -128,6 +128,7 @@ async fn did_exchange_test() -> Result<(), Box> { Some(invitation.id), &did_inviter, &requesters_peer_did, + "some-label".to_owned(), ) .await .unwrap(); From 7ad8670e73a900cff9cc76caf6afb91c70745d1b Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Fri, 21 Jun 2024 11:35:21 +1000 Subject: [PATCH 21/32] test fixes Signed-off-by: George Mulhearn --- .../peer_did/numalgos/numalgo2/encoding.rs | 7 ++++-- .../did_peer/tests/fixtures/basic.rs | 22 +++++++++---------- .../tests/fixtures/no_routing_keys.rs | 21 +++++++++--------- .../did_peer/tests/fixtures/no_services.rs | 19 ++++++++-------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs index 6c26dacac8..93d798856a 100644 --- a/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs +++ b/did_core/did_methods/did_peer/src/peer_did/numalgos/numalgo2/encoding.rs @@ -173,7 +173,9 @@ mod tests { ); let mut did_document = DidDocument::new(Did::parse(did_full.clone()).unwrap()); - did_document.add_key_agreement_object(vm_0); + did_document.add_key_agreement_ref(vm_0.id().to_owned()); + did_document.add_verification_method(vm_0); + did_document.add_authentication_ref(vm_1.id().to_owned()); did_document.add_verification_method(vm_1); let did = append_encoded_key_segments(did.to_string(), &did_document).unwrap(); @@ -269,7 +271,7 @@ mod tests { let mut did_document = DidDocument::new(did_full.parse().unwrap()); did_document.add_assertion_method_object(vm_0); did_document.add_key_agreement_object(vm_1); - did_document.add_verification_method(vm_2); + did_document.add_authentication_object(vm_2); let did = append_encoded_key_segments(did.to_string(), &did_document).unwrap(); assert_eq!(did, did_full); @@ -294,6 +296,7 @@ mod tests { let mut did_document = DidDocument::new(did_full.parse().unwrap()); did_document.add_verification_method(vm); + did_document.add_authentication_ref(DidUrl::from_fragment(reference.to_string()).unwrap()); did_document.add_key_agreement_ref(DidUrl::from_fragment(reference.to_string()).unwrap()); let did = append_encoded_key_segments(did.to_string(), &did_document).unwrap(); diff --git a/did_core/did_methods/did_peer/tests/fixtures/basic.rs b/did_core/did_methods/did_peer/tests/fixtures/basic.rs index 618c00fece..9edf68ec9e 100644 --- a/did_core/did_methods/did_peer/tests/fixtures/basic.rs +++ b/did_core/did_methods/did_peer/tests/fixtures/basic.rs @@ -13,29 +13,27 @@ pub static DID_DOC_BASIC: &str = r##" "alsoKnownAs": ["did:peer:3zQmaTbkb2T8CbKPzXSCgsdWHxgX3qvjmpmTQwfATu3crFCv"], "verificationMethod": [ { - "id": "#6MkqRYqQ", + "id": "#key-1", + "type": "X25519KeyAgreementKey2020", + "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0", + "publicKeyBase58": "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr" + }, + { + "id": "#key-2", "type": "Ed25519VerificationKey2020", "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0", "publicKeyBase58": "ByHnpUCFb1vAfh9CFZ8ZkmUZguURW8nSw889hy6rD8L7" }, { - "id": "#6MkgoLTn", + "id": "#key-3", "type": "Ed25519VerificationKey2020", "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0", "publicKeyBase58": "3M5RCDjPTWPkKSN3sxUmmMqHbmRPegYP1tjcKyrDbt9J" } ], - "authentication": [], + "authentication": ["#key-2", "#key-3"], "assertionMethod": [], - "keyAgreement": [ - { - "id": "#6LSbysY2", - "type": "X25519KeyAgreementKey2020", - "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCIsInIiOlsiZGlkOmV4YW1wbGU6c29tZW1lZGlhdG9yI3NvbWVrZXkiXSwiYSI6WyJkaWRjb21tL3YyIiwiZGlkY29tbS9haXAyO2Vudj1yZmM1ODciXX0", - "publicKeyBase58": "JhNWeSVLMYccCk7iopQW4guaSJTojqpMEELgSLhKwRr" - } - - ], + "keyAgreement": ["#key-1"], "capabilityInvocation": [], "capabilityDelegation": [], "service": [ diff --git a/did_core/did_methods/did_peer/tests/fixtures/no_routing_keys.rs b/did_core/did_methods/did_peer/tests/fixtures/no_routing_keys.rs index 24ed44e722..feeb8b1ec6 100644 --- a/did_core/did_methods/did_peer/tests/fixtures/no_routing_keys.rs +++ b/did_core/did_methods/did_peer/tests/fixtures/no_routing_keys.rs @@ -13,28 +13,27 @@ pub static DID_DOC_NO_ROUTING_KEYS: &str = r##" "alsoKnownAs": ["did:peer:3zQmVKBM36ZvoTCEecoNWAmLvDcePbksQ2Ag2pxyGa24eUp8"], "verificationMethod": [ { - "id": "#6MkqRYqQ", + "id": "#key-1", + "type": "X25519KeyAgreementKey2020", + "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9", + "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc" + }, + { + "id": "#key-2", "type": "Ed25519VerificationKey2020", "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9", "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V" }, { - "id": "#6MkgoLTn", + "id": "#key-3", "type": "Ed25519VerificationKey2020", "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9", "publicKeyMultibase": "z6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg" } ], - "authentication": [], + "authentication": ["#key-2", "#key-3"], "assertionMethod": [], - "keyAgreement": [ - { - "id": "#6LSbysY2", - "type": "X25519KeyAgreementKey2020", - "controller": "did:peer:2.Ez6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V.Vz6MkgoLTnTypo3tDRwCkZXSccTPHRLhF4ZnjhueYAFpEX6vg.SeyJpZCI6IiNzZXJ2aWNlLTAiLCJ0IjoiZG0iLCJzIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9lbmRwb2ludCJ9", - "publicKeyMultibase": "z6LSbysY2xFMRpGMhb7tFTLMpeuPRaqaWM1yECx2AtzE3KCc" - } - ], + "keyAgreement": ["#key-1"], "capabilityInvocation": [], "capabilityDelegation": [], "service": [ diff --git a/did_core/did_methods/did_peer/tests/fixtures/no_services.rs b/did_core/did_methods/did_peer/tests/fixtures/no_services.rs index 58d345e3b7..d6cd3762bd 100644 --- a/did_core/did_methods/did_peer/tests/fixtures/no_services.rs +++ b/did_core/did_methods/did_peer/tests/fixtures/no_services.rs @@ -11,22 +11,21 @@ pub static DID_DOC_NO_SERVICES: &str = r##" "alsoKnownAs": ["did:peer:3zQmdysQimott3jS93beGPVX8sTRSRFJWt1FsihPcSy9kZfB"], "verificationMethod": [ { - "id": "#6MkqRYqQ", + "id": "#key-1", + "type": "X25519KeyAgreementKey2020", + "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V", + "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud" + }, + { + "id": "#key-2", "type": "Ed25519VerificationKey2020", "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V", "publicKeyMultibase": "z6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V" } ], - "authentication": [], + "authentication": ["#key-2"], "assertionMethod": [], - "keyAgreement": [ - { - "id": "#6LSpSrLx", - "type": "X25519KeyAgreementKey2020", - "controller": "did:peer:2.Ez6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud.Vz6MkqRYqQiSgvZQdnBytw86Qbs2ZWUkGv22od935YF4s8M7V", - "publicKeyMultibase": "z6LSpSrLxbAhg2SHwKk7kwpsH7DM7QjFS5iK6qP87eViohud" - } - ], + "keyAgreement": ["#key-1"], "capabilityInvocation": [], "capabilityDelegation": [] } From a03f6ae707f2d01506be921ead30f555e437d559 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Mon, 24 Jun 2024 13:55:59 +1000 Subject: [PATCH 22/32] response sign verification mostly impled Signed-off-by: George Mulhearn --- .../src/handlers/did_exchange.rs | 12 +- .../src/protocols/did_exchange/mod.rs | 23 ++- .../did_exchange/state_machine/generic/mod.rs | 6 +- .../did_exchange/state_machine/helpers.rs | 131 +++++++++++++----- .../requester/request_sent/mod.rs | 130 +++++++++++++---- aries/aries_vcx/src/utils/didcomm_utils.rs | 2 +- aries/aries_vcx/tests/test_did_exchange.rs | 9 +- 7 files changed, 241 insertions(+), 72 deletions(-) diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index d5325150f9..7483992fd3 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -14,7 +14,7 @@ use aries_vcx::{ AriesMessage, }, protocols::did_exchange::{ - resolve_enc_key_from_invitation, + resolve_enc_key_from_did_doc, resolve_enc_key_from_invitation, state_machine::{ generic::{GenericDidExchange, ThinState}, helpers::create_peer_did_4, @@ -236,8 +236,16 @@ impl DidcommHandlerDidExchange { let (requester, _) = self.did_exchange.get(&thid)?; + let inviter_ddo = requester.their_did_doc(); + let inviter_key = resolve_enc_key_from_did_doc(inviter_ddo)?; + let (requester, complete) = requester - .handle_response(response, self.resolver_registry.clone()) + .handle_response( + self.wallet.as_ref(), + &inviter_key, + response, + &self.resolver_registry, + ) .await?; let ddo_their = requester.their_did_doc(); let ddo_our = requester.our_did_document(); diff --git a/aries/aries_vcx/src/protocols/did_exchange/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/mod.rs index c5629831af..af2a6010cc 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/mod.rs @@ -11,7 +11,10 @@ use messages::msg_fields::protocols::out_of_band::invitation::{ }; use public_key::Key; -use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; +use crate::{ + errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}, + utils::didcomm_utils::resolve_service_key_to_typed_key, +}; pub mod state_machine; pub mod states; @@ -103,11 +106,25 @@ pub async fn resolve_enc_key_from_invitation( "resolve_enc_key_from_invitation >> Resolved did document {}", output.did_document ); - let key = resolve_first_key_agreement(&output.did_document)?; - Ok(key.public_key()?) + let did_doc = output.did_document; + resolve_enc_key_from_did_doc(&did_doc) } OobService::AriesService(_service) => { unimplemented!("Embedded Aries Service not yet supported by did-exchange") } } } + +pub fn resolve_enc_key_from_did_doc(did_doc: &DidDocument) -> Result { + // prefer first service key if available + if let Some(service_recipient_key) = did_doc + .service() + .first() + .and_then(|s| s.extra_field_recipient_keys().into_iter().flatten().next()) + { + return resolve_service_key_to_typed_key(&service_recipient_key, did_doc); + } + + let key = resolve_first_key_agreement(did_doc)?; + Ok(key.public_key()?) +} diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index 27a62fae0c..5cdd9d2ce3 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -130,14 +130,16 @@ impl GenericDidExchange { pub async fn handle_response( self, + wallet: &impl BaseWallet, + invitation_key: &Key, response: AnyResponse, - resolver_registry: Arc, + resolver_registry: &Arc, ) -> Result<(Self, Complete), (Self, AriesVcxError)> { match self { GenericDidExchange::Requester(requester_state) => match requester_state { RequesterState::RequestSent(request_sent_state) => { match request_sent_state - .receive_response(response, resolver_registry) + .receive_response(wallet, invitation_key, response, resolver_registry) .await { Ok(TransitionResult { state, output }) => Ok(( diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 176c31193f..8a4087ccf6 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -180,51 +180,108 @@ pub(crate) fn assemble_did_rotate_attachment(did: &Did) -> Attachment { .build() } -// TODO: Obviously, extract attachment signing -// TODO: JWS verification +// TODO: if this becomes a common method, move to a shared location. +/// Creates a JWS signature of the attachment with the provided verkey. The created JWS +/// signature is appended to the attachment, in alignment with Aries RFC 0017: +/// https://hyperledger.github.io/aries-rfcs/latest/concepts/0017-attachments/#signing-attachments. pub(crate) async fn jws_sign_attach( mut attach: Attachment, verkey: Key, wallet: &impl BaseWallet, ) -> Result { - if let AttachmentType::Base64(attach_base64) = &attach.data.content { - let did_key: DidKey = verkey.clone().try_into()?; - let verkey_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, verkey.key()); + let AttachmentType::Base64(attach_base64) = &attach.data.content else { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "Cannot sign non-base64-encoded attachment", + )); + }; + if verkey.key_type() != &KeyType::Ed25519 { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidVerkey, + "Only JWS signatures with Ed25519 based keys are currently supported.", + )); + } - let protected_header = json!({ - "alg": "EdDSA", - "jwk": { - "kty": "OKP", - "kid": did_key.to_string(), - "crv": "Ed25519", - "x": verkey_b64 - } - }); - let unprotected_header = json!({ - // TODO: Needs to be both protected and unprotected, does it make sense? + let did_key: DidKey = verkey.clone().try_into()?; + let verkey_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, verkey.key()); + + let protected_header = json!({ + "alg": "EdDSA", + "jwk": { + "kty": "OKP", "kid": did_key.to_string(), - }); - let b64_protected = - base64::engine::Engine::encode(&URL_SAFE_LENIENT, protected_header.to_string()); - let sign_input = format!("{}.{}", b64_protected, attach_base64).into_bytes(); - let signed = wallet.sign(&verkey, &sign_input).await?; - let signature_base64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, signed); + "crv": "Ed25519", + "x": verkey_b64 + } + }); + let unprotected_header = json!({ + "kid": did_key.to_string(), + }); + let b64_protected = + base64::engine::Engine::encode(&URL_SAFE_LENIENT, protected_header.to_string()); + let sign_input = format!("{}.{}", b64_protected, attach_base64).into_bytes(); + let signed: Vec = wallet.sign(&verkey, &sign_input).await?; + let signature_base64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, signed); - let jws = { - let mut jws = HashMap::new(); - jws.insert("header".to_string(), unprotected_header); - jws.insert("protected".to_string(), Value::String(b64_protected)); - jws.insert("signature".to_string(), Value::String(signature_base64)); - jws - }; - attach.data.jws = Some(jws); - Ok(attach) - } else { - Err(AriesVcxError::from_msg( - AriesVcxErrorKind::InvalidState, - "Cannot sign non-base64-encoded attachment", - )) - } + let jws = { + let mut jws = HashMap::new(); + jws.insert("header".to_string(), unprotected_header); + jws.insert("protected".to_string(), Value::String(b64_protected)); + jws.insert("signature".to_string(), Value::String(signature_base64)); + jws + }; + attach.data.jws = Some(jws); + Ok(attach) +} + +/// Verifies that the given has a JWS signature attached, which is a valid signature given +/// the expected signer key. +/// +// NOTE: Does not handle attachments with multiple signatures. +// NOTE: this is the specific use case where the signer is known by the function caller. Therefore +// we do not need to attempt to decode key within the protected nor unprotected header. +pub(crate) async fn jws_verify_attachment( + attach: &Attachment, + expected_signer: &Key, + wallet: &impl BaseWallet, +) -> Result { + let AttachmentType::Base64(attach_base64) = &attach.data.content else { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "Cannot verify JWS of a non-base64-encoded attachment", + )); + }; + let Some(ref jws) = attach.data.jws else { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "Attachment has no JWS signature attached. Cannot verify.", + )); + }; + + let (Some(b64_protected), Some(b64_signature)) = ( + jws.get("protected").and_then(|s| s.as_str()), + jws.get("signature").and_then(|s| s.as_str()), + ) else { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "Attachment has an invalid JWS with missing fields. Cannot verify.", + )); + }; + + let sign_input = format!("{}.{}", b64_protected, attach_base64).into_bytes(); + let signature = + base64::engine::Engine::decode(&URL_SAFE_LENIENT, b64_signature).map_err(|_| { + AriesVcxError::from_msg( + AriesVcxErrorKind::EncodeError, + "Attachment JWS signature was not correctly base64Url encoded.", + ) + })?; + + let res = wallet + .verify(expected_signer, &sign_input, &signature) + .await?; + + Ok(res) } // TODO - ideally this should be resilient to the case where the attachment is a legacy aries DIDDoc diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 547f8cab8e..3c44343129 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -1,28 +1,34 @@ use std::sync::Arc; +use aries_vcx_wallet::wallet::base_wallet::BaseWallet; +use base64::Engine; +use did_doc::schema::did_doc::DidDocument; use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver::traits::resolvable::resolution_output::DidResolutionOutput; use did_resolver_registry::ResolverRegistry; use messages::{ + decorators::attachment::AttachmentType, msg_fields::protocols::did_exchange::{ - v1_1::request::Request, + v1_1::{request::Request, response::Response}, v1_x::{complete::Complete, response::AnyResponse}, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; +use public_key::Key; use super::DidExchangeRequester; use crate::{ errors::error::{AriesVcxError, AriesVcxErrorKind}, protocols::did_exchange::{ state_machine::{ - helpers::{attachment_to_diddoc, to_transition_error}, + helpers::{attachment_to_diddoc, jws_verify_attachment, to_transition_error}, requester::helpers::{construct_didexchange_complete, construct_request}, }, states::{completed::Completed, requester::request_sent::RequestSent}, transition::{transition_error::TransitionError, transition_result::TransitionResult}, }, + utils::base64::URL_SAFE_LENIENT, }; impl DidExchangeRequester { @@ -69,8 +75,10 @@ impl DidExchangeRequester { pub async fn receive_response( self, + wallet: &impl BaseWallet, + invitation_key: &Key, response: AnyResponse, - resolver_registry: Arc, + resolver_registry: &Arc, ) -> Result, Complete>, TransitionError> { debug!( @@ -89,28 +97,15 @@ impl DidExchangeRequester { state: self, }); } - // TODO - process differently depending on version - let did_document = if let Some(ddo) = response.content.did_doc { - debug!( - "DidExchangeRequester::receive_response >> the Response message \ - contained attached ddo" - ); - // verify JWS signature on attachment - attachment_to_diddoc(ddo).map_err(to_transition_error(self.clone()))? - } else { - debug!( - "DidExchangeRequester::receive_response >> the Response message \ - contains pairwise DID, resolving to DID Document" - ); - // verify JWS signature on attachment IF version == 1.1 - let did = - &Did::parse(response.content.did).map_err(to_transition_error(self.clone()))?; - let DidResolutionOutput { did_document, .. } = resolver_registry - .resolve(did, &Default::default()) - .await - .map_err(to_transition_error(self.clone()))?; - did_document - }; + + let did_document = extract_and_verify_responder_did_doc( + wallet, + invitation_key, + response, + resolver_registry, + ) + .await + .map_err(to_transition_error(self.clone()))?; let complete_message = construct_didexchange_complete( self.state.invitation_id, @@ -134,3 +129,88 @@ impl DidExchangeRequester { }) } } + +async fn extract_and_verify_responder_did_doc( + wallet: &impl BaseWallet, + invitation_key: &Key, + response: Response, + resolver_registry: &Arc, +) -> Result { + let their_did = response.content.did; + + if let Some(did_doc_attach) = response.content.did_doc { + let verified_signature = + jws_verify_attachment(&did_doc_attach, invitation_key, wallet).await?; + if !verified_signature { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "DIDExchange response did not have a valid DIDDoc signature from the expected \ + inviter", + )); + } + + let did_doc = attachment_to_diddoc(did_doc_attach)?; + if did_doc.id().to_string() != their_did { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "DIDExchange response had a DIDDoc which did not match the response DID", + )); + } + return Ok(did_doc); + } + + if let Some(did_rotate_attach) = response.content.did_rotate { + let verified_signature = + jws_verify_attachment(&did_rotate_attach, invitation_key, wallet).await?; + if !verified_signature { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "DIDExchange response did not have a valid DID rotate signature from the expected \ + inviter", + )); + } + + let AttachmentType::Base64(signed_did_b64) = did_rotate_attach.data.content else { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::EncodeError, + "DIDExchange response did not have a valid DID rotate attachment", + )); + }; + + let did_bytes = URL_SAFE_LENIENT.decode(signed_did_b64).map_err(|_| { + AriesVcxError::from_msg( + AriesVcxErrorKind::EncodeError, + "DIDExchange response did not have a valid base64 did rotate attachment", + ) + })?; + let signed_did = String::from_utf8(did_bytes).map_err(|_| { + AriesVcxError::from_msg( + AriesVcxErrorKind::EncodeError, + "DIDExchange response did not have a valid UTF8 did rotate attachment", + ) + })?; + + if signed_did != their_did { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + format!( + "DIDExchange response had a DID rotate which did not match the response DID. \ + Wanted {their_did}, found {signed_did}" + ), + )); + } + + let did = &Did::parse(their_did)?; + let DidResolutionOutput { + did_document: did_doc, + .. + } = resolver_registry.resolve(did, &Default::default()).await?; + return Ok(did_doc); + } + + // default to error + Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "DIDExchange response could not be verified. No DIDDoc nor DIDRotate was attached.", + )) +} diff --git a/aries/aries_vcx/src/utils/didcomm_utils.rs b/aries/aries_vcx/src/utils/didcomm_utils.rs index 2a369f26ff..50ce4efc0f 100644 --- a/aries/aries_vcx/src/utils/didcomm_utils.rs +++ b/aries/aries_vcx/src/utils/didcomm_utils.rs @@ -6,7 +6,7 @@ use public_key::{Key, KeyType}; use crate::errors::error::{AriesVcxError, AriesVcxErrorKind, VcxResult}; -fn resolve_service_key_to_typed_key( +pub(crate) fn resolve_service_key_to_typed_key( key: &ServiceKeyKind, did_document: &DidDocument, ) -> VcxResult { diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index eb791d41be..2ad620c030 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -153,7 +153,7 @@ async fn did_exchange_test() -> Result<(), Box> { resolver_registry.clone(), request, &responders_peer_did, - Some(invitation_key), + Some(invitation_key.clone()), ) .await .unwrap(); @@ -162,7 +162,12 @@ async fn did_exchange_test() -> Result<(), Box> { state: requester, output: complete, } = requester - .receive_response(response, resolver_registry) + .receive_response( + &agent_invitee.wallet, + &invitation_key, + response, + &resolver_registry, + ) .await .unwrap(); From ed46a358ce1cb06b264d8a64c12a1794d5897829 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Mon, 24 Jun 2024 13:56:37 +1000 Subject: [PATCH 23/32] fix did rotate content Signed-off-by: George Mulhearn --- .../src/protocols/did_exchange/state_machine/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 176c31193f..91dbf5c83f 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -170,7 +170,7 @@ pub(crate) fn ddo_to_attach(ddo: DidDocument) -> Result Attachment { - let content_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, did.id()); + let content_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, did.did()); Attachment::builder() .data( AttachmentData::builder() From 40f1f286efd9da216d3ac9277878d44d1a3154be Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Mon, 24 Jun 2024 14:40:45 +1000 Subject: [PATCH 24/32] negative test Signed-off-by: George Mulhearn --- .../did_exchange/state_machine/helpers.rs | 1 - .../transition/transition_result.rs | 1 + aries/aries_vcx/tests/test_did_exchange.rs | 231 ++++++++++++++---- 3 files changed, 185 insertions(+), 48 deletions(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 3ffb44c8cc..4690f76102 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -236,7 +236,6 @@ pub(crate) async fn jws_sign_attach( /// Verifies that the given has a JWS signature attached, which is a valid signature given /// the expected signer key. -/// // NOTE: Does not handle attachments with multiple signatures. // NOTE: this is the specific use case where the signer is known by the function caller. Therefore // we do not need to attempt to decode key within the protected nor unprotected header. diff --git a/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs b/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs index 15b1153054..6e4b79a165 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/transition/transition_result.rs @@ -1,5 +1,6 @@ // TODO: Somehow enforce using both #[must_use] +#[derive(Debug)] pub struct TransitionResult { pub state: T, pub output: U, diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 2ad620c030..0b35f92daf 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -4,6 +4,7 @@ use std::{error::Error, sync::Arc, thread, time::Duration}; use aries_vcx::{ common::ledger::transactions::write_endpoint_from_service, + errors::error::AriesVcxErrorKind, protocols::did_exchange::{ resolve_enc_key_from_invitation, state_machine::{ @@ -19,7 +20,12 @@ use aries_vcx::{ encryption_envelope::EncryptionEnvelope, }, }; -use aries_vcx_ledger::ledger::indy_vdr_ledger::DefaultIndyLedgerRead; +use aries_vcx_anoncreds::anoncreds::base_anoncreds::BaseAnonCreds; +use aries_vcx_ledger::ledger::{ + base_ledger::{AnoncredsLedgerRead, AnoncredsLedgerWrite, IndyLedgerRead, IndyLedgerWrite}, + indy_vdr_ledger::DefaultIndyLedgerRead, +}; +use aries_vcx_wallet::wallet::base_wallet::BaseWallet; use did_doc::schema::{ did_doc::DidDocument, service::typed::{didcommv1::ServiceDidCommV1, ServiceType}, @@ -36,6 +42,7 @@ use messages::msg_fields::protocols::out_of_band::invitation::{ use pretty_assertions::assert_eq; use test_utils::devsetup::{dev_build_profile_vdr_ledger, SetupPoolDirectory}; use url::Url; +use utils::test_agent::TestAgent; use crate::utils::test_agent::{ create_test_agent, create_test_agent_endorser_2, create_test_agent_trustee, @@ -50,56 +57,29 @@ fn assert_key_agreement(a: DidDocument, b: DidDocument) { assert_eq!(a_key, b_key); } -#[tokio::test] -#[ignore] -async fn did_exchange_test() -> Result<(), Box> { - let setup = SetupPoolDirectory::init().await; +async fn did_exchange_test( + inviter_did: String, + agent_inviter: TestAgent< + impl IndyLedgerRead + AnoncredsLedgerRead, + impl IndyLedgerWrite + AnoncredsLedgerWrite, + impl BaseAnonCreds, + impl BaseWallet, + >, + agent_invitee: TestAgent< + impl IndyLedgerRead + AnoncredsLedgerRead, + impl IndyLedgerWrite + AnoncredsLedgerWrite, + impl BaseAnonCreds, + impl BaseWallet, + >, + resolver_registry: Arc, +) -> Result<(), Box> { let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); - let agent_trustee = create_test_agent_trustee(setup.genesis_file_path.clone()).await; - // todo: patrik: update create_test_agent_endorser_2 to not consume trustee agent - let agent_inviter = - create_test_agent_endorser_2(&setup.genesis_file_path, agent_trustee).await?; - let create_service = ServiceDidCommV1::new( - Uri::new("#service-0").unwrap(), - dummy_url.clone(), - 0, - vec![], - vec![], - ); - write_endpoint_from_service( - &agent_inviter.wallet, - &agent_inviter.ledger_write, - &agent_inviter.institution_did, - &create_service.try_into()?, - ) - .await?; - thread::sleep(Duration::from_millis(100)); - - let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; - - let (ledger_read_2, _) = dev_build_profile_vdr_ledger(setup.genesis_file_path); - let ledger_read_2_arc = Arc::new(ledger_read_2); - - // if we were to use, more generally, the `dev_build_featured_indy_ledger`, we would need to - // here the type based on the feature flag (indy vs proxy vdr client) which is pain - // we need to improve DidSovResolver such that Rust compiler can fully infer the return type - let did_sov_resolver: DidSovResolver, DefaultIndyLedgerRead> = - DidSovResolver::new(ledger_read_2_arc); - - let resolver_registry = Arc::new( - ResolverRegistry::new() - .register_resolver::("peer".into(), PeerDidResolver::new()) - .register_resolver("sov".into(), did_sov_resolver), - ); let invitation = Invitation::builder() .id("test_invite_id".to_owned()) .content( InvitationContent::builder() - .services(vec![OobService::Did(format!( - "did:sov:{}", - agent_inviter.institution_did - ))]) + .services(vec![OobService::Did(inviter_did)]) .build(), ) .build(); @@ -138,7 +118,7 @@ async fn did_exchange_test() -> Result<(), Box> { ); let (responders_peer_did, _our_verkey) = - create_peer_did_4(&agent_invitee.wallet, dummy_url.clone(), vec![]).await?; + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; let responders_did_document = responders_peer_did.resolve_did_doc()?; info!("Responder prepares did document: {responders_did_document}"); @@ -211,9 +191,166 @@ async fn did_exchange_test() -> Result<(), Box> { let requesters_peer_did = requesters_peer_did.resolve_did_doc()?; let expected_sender_vk = resolve_ed25519_base58_key_agreement(&requesters_peer_did)?; let unpacked = - EncryptionEnvelope::auth_unpack(&agent_invitee.wallet, m.0, &expected_sender_vk).await?; + EncryptionEnvelope::auth_unpack(&agent_inviter.wallet, m.0, &expected_sender_vk).await?; info!("Unpacked message: {:?}", unpacked); Ok(()) } + +#[tokio::test] +#[ignore] +async fn did_exchange_test_sov_inviter() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + let agent_trustee = create_test_agent_trustee(setup.genesis_file_path.clone()).await; + // todo: patrik: update create_test_agent_endorser_2 to not consume trustee agent + let agent_inviter = + create_test_agent_endorser_2(&setup.genesis_file_path, agent_trustee).await?; + let create_service = ServiceDidCommV1::new( + Uri::new("#service-0").unwrap(), + dummy_url.clone(), + 0, + vec![], + vec![], + ); + write_endpoint_from_service( + &agent_inviter.wallet, + &agent_inviter.ledger_write, + &agent_inviter.institution_did, + &create_service.try_into()?, + ) + .await?; + thread::sleep(Duration::from_millis(100)); + + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let (ledger_read_2, _) = dev_build_profile_vdr_ledger(setup.genesis_file_path); + let ledger_read_2_arc = Arc::new(ledger_read_2); + + // if we were to use, more generally, the `dev_build_featured_indy_ledger`, we would need to + // here the type based on the feature flag (indy vs proxy vdr client) which is pain + // we need to improve DidSovResolver such that Rust compiler can fully infer the return type + let did_sov_resolver: DidSovResolver, DefaultIndyLedgerRead> = + DidSovResolver::new(ledger_read_2_arc); + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()) + .register_resolver("sov".into(), did_sov_resolver), + ); + + did_exchange_test( + format!("did:sov:{}", agent_inviter.institution_did), + agent_inviter, + agent_invitee, + resolver_registry, + ) + .await +} + +#[tokio::test] +#[ignore] +async fn did_exchange_test_peer_to_peer() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let agent_inviter = create_test_agent(setup.genesis_file_path.clone()).await; + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()), + ); + + let (inviter_peer_did, _) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + did_exchange_test( + inviter_peer_did.to_string(), + agent_inviter, + agent_invitee, + resolver_registry, + ) + .await +} + +#[tokio::test] +#[ignore] +async fn did_exchange_test_with_invalid_rotation_signature() -> Result<(), Box> { + let setup = SetupPoolDirectory::init().await; + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let agent_inviter = create_test_agent(setup.genesis_file_path.clone()).await; + let agent_invitee = create_test_agent(setup.genesis_file_path.clone()).await; + + let resolver_registry = Arc::new( + ResolverRegistry::new() + .register_resolver::("peer".into(), PeerDidResolver::new()), + ); + + let (inviter_peer_did, _) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + let dummy_url: Url = "http://dummyurl.org".parse().unwrap(); + + let invitation = Invitation::builder() + .id("test_invite_id".to_owned()) + .content( + InvitationContent::builder() + .services(vec![OobService::Did(inviter_peer_did.to_string())]) + .build(), + ) + .build(); + let real_invitation_key = + resolve_enc_key_from_invitation(&invitation, &resolver_registry).await?; + + let (requesters_peer_did, _our_verkey) = + create_peer_did_4(&agent_invitee.wallet, dummy_url.clone(), vec![]).await?; + let did_inviter: Did = invitation_get_first_did_service(&invitation)?; + + let TransitionResult { + state: requester, + output: request, + } = DidExchangeRequester::::construct_request( + resolver_registry.clone(), + Some(invitation.id), + &did_inviter, + &requesters_peer_did, + "some-label".to_owned(), + ) + .await?; + + let (responders_peer_did, incorrect_invitation_key) = + create_peer_did_4(&agent_inviter.wallet, dummy_url.clone(), vec![]).await?; + + // create a response with a DID Rotate signed by the wrong key (not the original invitation key) + let TransitionResult { + output: response, + state: _, + } = DidExchangeResponder::::receive_request( + &agent_inviter.wallet, + resolver_registry.clone(), + request, + &responders_peer_did, + // sign with NOT the invitation key + Some(incorrect_invitation_key), + ) + .await?; + + // receiving the response should fail when verifying the signature + let res = requester + .receive_response( + &agent_invitee.wallet, + &real_invitation_key, + response, + &resolver_registry, + ) + .await; + assert_eq!( + res.unwrap_err().error.kind(), + AriesVcxErrorKind::InvalidInput + ); + + Ok(()) +} From 732f2605b602e77555f47150a8ceb380de88af0f Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Mon, 24 Jun 2024 17:49:53 +1000 Subject: [PATCH 25/32] small patch re acapy testing Signed-off-by: George Mulhearn --- .../src/protocols/did_exchange/state_machine/helpers.rs | 4 ++++ .../state_machine/requester/request_sent/mod.rs | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 4690f76102..06e800257b 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -250,6 +250,10 @@ pub(crate) async fn jws_verify_attachment( "Cannot verify JWS of a non-base64-encoded attachment", )); }; + // aries attachments do not REQUIRE that the attachment has no padding, + // but JWS does, so remove it; just incase. + let attach_base64 = attach_base64.replace("=", ""); + let Some(ref jws) = attach.data.jws else { return Err(AriesVcxError::from_msg( AriesVcxErrorKind::InvalidInput, diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 3c44343129..a4c4886524 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -139,6 +139,10 @@ async fn extract_and_verify_responder_did_doc( let their_did = response.content.did; if let Some(did_doc_attach) = response.content.did_doc { + debug!( + "Verifying signature of DIDDoc attached to response: {did_doc_attach:?} against \ + expected key {invitation_key:?}" + ); let verified_signature = jws_verify_attachment(&did_doc_attach, invitation_key, wallet).await?; if !verified_signature { @@ -160,6 +164,10 @@ async fn extract_and_verify_responder_did_doc( } if let Some(did_rotate_attach) = response.content.did_rotate { + debug!( + "Verifying signature of DID Rotate attached to response: {did_rotate_attach:?} \ + against expected key {invitation_key:?}" + ); let verified_signature = jws_verify_attachment(&did_rotate_attach, invitation_key, wallet).await?; if !verified_signature { From 5f5133d57b2a1a8207002a6afd0edc42efcf48d8 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 25 Jun 2024 09:42:49 +1000 Subject: [PATCH 26/32] pass in handshake ver Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 10 +++-- .../src/handlers/did_exchange.rs | 3 ++ .../did_exchange/state_machine/generic/mod.rs | 11 +++-- .../state_machine/requester/helpers.rs | 41 ++++++++++++++++++- .../requester/request_sent/mod.rs | 3 +- aries/aries_vcx/tests/test_did_exchange.rs | 6 ++- .../src/msg_types/protocols/did_exchange.rs | 6 +++ 7 files changed, 70 insertions(+), 10 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index 477977db43..607c64e87e 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -9,7 +9,9 @@ use aries_vcx_agent::aries_vcx::{ }, AriesMessage, }, - protocols::did_exchange::state_machine::requester::helpers::invitation_get_first_did_service, + protocols::did_exchange::state_machine::requester::helpers::{ + invitation_get_acceptable_did_exchange_version, invitation_get_first_did_service, + }, }; use serde_json::Value; @@ -35,11 +37,13 @@ impl HarnessAgent { .aries_agent .out_of_band() .get_invitation(&invitation_id)?; + + let version = invitation_get_acceptable_did_exchange_version(&invitation)?; let did_inviter: Did = invitation_get_first_did_service(&invitation)?; let (thid, pthid, my_did) = self .aries_agent .did_exchange() - .handle_msg_invitation(did_inviter.to_string(), Some(invitation_id)) + .handle_msg_invitation(did_inviter.to_string(), Some(invitation_id), version) .await?; if let Some(ref pthid) = pthid { self.store_mapping_pthid_thid(pthid.clone(), thid.clone()); @@ -77,7 +81,7 @@ impl HarnessAgent { let (thid, pthid, my_did) = self .aries_agent .did_exchange() - .handle_msg_invitation(req.their_public_did.clone(), None) // todo: separate the case with/without invitation on did_exchange handler + .handle_msg_invitation(req.their_public_did.clone(), None, Default::default()) // todo: separate the case with/without invitation on did_exchange handler .await?; let connection_id = pthid.unwrap_or(thid); Ok(json!({ diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index d5325150f9..dffbe37a20 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -11,6 +11,7 @@ use aries_vcx::{ }, out_of_band::invitation::Invitation as OobInvitation, }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, AriesMessage, }, protocols::did_exchange::{ @@ -63,6 +64,7 @@ impl DidcommHandlerDidExchange { &self, their_did: String, invitation_id: Option, + version: DidExchangeTypeV1, ) -> AgentResult<(String, Option, String)> { // todo: type the return type let (our_peer_did, _our_verkey) = @@ -76,6 +78,7 @@ impl DidcommHandlerDidExchange { &their_did, &our_peer_did, "".to_owned(), + version, ) .await?; diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index 27a62fae0c..cf4301f006 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -5,9 +5,12 @@ use did_doc::schema::did_doc::DidDocument; use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; -use messages::msg_fields::protocols::did_exchange::{ - v1_1::request::Request, - v1_x::{complete::Complete, problem_report::ProblemReport, response::AnyResponse}, +use messages::{ + msg_fields::protocols::did_exchange::{ + v1_1::request::Request, + v1_x::{complete::Complete, problem_report::ProblemReport, response::AnyResponse}, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use public_key::Key; pub use thin_state::ThinState; @@ -90,6 +93,7 @@ impl GenericDidExchange { their_did: &Did, our_peer_did: &PeerDid, our_label: String, + version: DidExchangeTypeV1, ) -> Result<(Self, Request), AriesVcxError> { let TransitionResult { state, output } = DidExchangeRequester::::construct_request( @@ -98,6 +102,7 @@ impl GenericDidExchange { their_did, our_peer_did, our_label, + version, ) .await?; Ok(( diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index 6eaf6913df..f985a40afc 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -12,7 +12,10 @@ use messages::{ }, out_of_band::invitation::{Invitation, OobService}, }, - msg_types::protocols::did_exchange::DidExchangeTypeV1, + msg_types::{ + protocols::did_exchange::{DidExchangeType, DidExchangeTypeV1}, + Protocol, + }, }; use shared::maybe_known::MaybeKnown; use uuid::Uuid; @@ -94,3 +97,39 @@ pub fn invitation_get_first_did_service(invitation: &Invitation) -> VcxResult VcxResult { + // determine acceptable protocol + let mut did_exch_v1_1_accepted = false; + let mut did_exch_v1_0_accepted = false; + for proto in invitation.content.handshake_protocols.iter().flatten() { + let MaybeKnown::Known(Protocol::DidExchangeType(DidExchangeType::V1(exch_proto))) = proto + else { + continue; + }; + if matches!(exch_proto, DidExchangeTypeV1::V1_1(_)) { + did_exch_v1_1_accepted = true; + continue; + } + if matches!(exch_proto, DidExchangeTypeV1::V1_0(_)) { + did_exch_v1_0_accepted = true; + } + } + + let version = match (did_exch_v1_1_accepted, did_exch_v1_0_accepted) { + (true, _) => DidExchangeTypeV1::new_v1_1(), + (false, true) => DidExchangeTypeV1::new_v1_0(), + _ => { + return Err(AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidInput, + "OOB invitation does not have a suitable handshake protocol for DIDExchange", + )) + } + }; + + Ok(version) +} diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 547f8cab8e..99bbffd484 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -32,6 +32,7 @@ impl DidExchangeRequester { their_did: &Did, our_peer_did: &PeerDid, our_label: String, + version: DidExchangeTypeV1, ) -> Result, AriesVcxError> { debug!( "DidExchangeRequester::construct_request >> their_did: {}, our_peer_did: \ @@ -47,7 +48,7 @@ impl DidExchangeRequester { invitation_id.clone(), our_peer_did.to_string(), our_label, - DidExchangeTypeV1::new_v1_1(), + version, ); debug!( diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index eb791d41be..1af5f167ae 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -30,8 +30,9 @@ use did_peer::resolver::PeerDidResolver; use did_resolver_registry::ResolverRegistry; use did_resolver_sov::resolution::DidSovResolver; use log::info; -use messages::msg_fields::protocols::out_of_band::invitation::{ - Invitation, InvitationContent, OobService, +use messages::{ + msg_fields::protocols::out_of_band::invitation::{Invitation, InvitationContent, OobService}, + msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use pretty_assertions::assert_eq; use test_utils::devsetup::{dev_build_profile_vdr_ledger, SetupPoolDirectory}; @@ -129,6 +130,7 @@ async fn did_exchange_test() -> Result<(), Box> { &did_inviter, &requesters_peer_did, "some-label".to_owned(), + DidExchangeTypeV1::new_v1_1(), ) .await .unwrap(); diff --git a/aries/messages/src/msg_types/protocols/did_exchange.rs b/aries/messages/src/msg_types/protocols/did_exchange.rs index dd375270db..ff9eb294e1 100644 --- a/aries/messages/src/msg_types/protocols/did_exchange.rs +++ b/aries/messages/src/msg_types/protocols/did_exchange.rs @@ -40,6 +40,12 @@ pub enum DidExchangeTypeV1_1 { Complete, } +impl Default for DidExchangeTypeV1 { + fn default() -> Self { + Self::new_v1_1() + } +} + #[cfg(test)] mod tests { use serde_json::json; From ec59ed98c0287d35f87744239f9772b6d3365857 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Tue, 25 Jun 2024 09:51:14 +1000 Subject: [PATCH 27/32] clippy and rebase Signed-off-by: George Mulhearn --- .../src/protocols/did_exchange/state_machine/helpers.rs | 2 +- aries/aries_vcx/tests/test_did_exchange.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 06e800257b..447e62089a 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -252,7 +252,7 @@ pub(crate) async fn jws_verify_attachment( }; // aries attachments do not REQUIRE that the attachment has no padding, // but JWS does, so remove it; just incase. - let attach_base64 = attach_base64.replace("=", ""); + let attach_base64 = attach_base64.replace('=', ""); let Some(ref jws) = attach.data.jws else { return Err(AriesVcxError::from_msg( diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index ce1d299312..ab3448a6a3 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -320,6 +320,7 @@ async fn did_exchange_test_with_invalid_rotation_signature() -> Result<(), Box Date: Tue, 25 Jun 2024 14:06:33 +1000 Subject: [PATCH 28/32] unnecessary mockall dep Signed-off-by: George Mulhearn --- did_core/did_methods/did_resolver_sov/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/did_core/did_methods/did_resolver_sov/Cargo.toml b/did_core/did_methods/did_resolver_sov/Cargo.toml index 59af563001..518557c4ca 100644 --- a/did_core/did_methods/did_resolver_sov/Cargo.toml +++ b/did_core/did_methods/did_resolver_sov/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" did_resolver = { path = "../../did_resolver" } aries_vcx_ledger = { path = "../../../aries/aries_vcx_ledger" } async-trait = "0.1.68" -mockall = "0.11.4" serde_json = "1.0.96" serde = { version = "1.0.160", features = ["derive"] } chrono = { version = "0.4.24", default-features = false } @@ -16,6 +15,7 @@ url = "2.3.1" log = "0.4.16" [dev-dependencies] +mockall = "0.11.4" aries_vcx = { path = "../../../aries/aries_vcx" } tokio = { version = "1.27.0", default-features = false, features = ["macros", "rt"] } uuid = "1.3.1" From 6a054c6c7fd5270fcdefe672455ef1616711957f Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 26 Jun 2024 11:48:20 +1000 Subject: [PATCH 29/32] any-wrapper approach Signed-off-by: George Mulhearn --- .../src/controllers/did_exchange.rs | 14 +++--- .../src/controllers/didcomm.rs | 13 ++++-- .../src/handlers/did_exchange.rs | 39 +++++----------- .../did_exchange/state_machine/generic/mod.rs | 14 +++--- .../did_exchange/state_machine/mod.rs | 8 ++-- .../state_machine/requester/helpers.rs | 28 +++++++---- .../requester/request_sent/mod.rs | 13 +++--- .../responder/response_sent/mod.rs | 7 ++- aries/aries_vcx/tests/test_did_exchange.rs | 4 +- aries/messages/src/misc/mod.rs | 26 ++++++++--- .../protocols/did_exchange/v1_0/complete.rs | 37 ++++++++------- .../protocols/did_exchange/v1_0/mod.rs | 20 ++------ .../did_exchange/v1_0/problem_report.rs | 34 ++++++++------ .../protocols/did_exchange/v1_0/request.rs | 39 ++++++++++------ .../protocols/did_exchange/v1_1/complete.rs | 37 ++++++++------- .../protocols/did_exchange/v1_1/mod.rs | 20 ++------ .../did_exchange/v1_1/problem_report.rs | 32 +++++++------ .../protocols/did_exchange/v1_1/request.rs | 34 ++++++++++---- .../protocols/did_exchange/v1_x/complete.rs | 46 +++++++++++++------ .../did_exchange/v1_x/problem_report.rs | 44 ++++++++++++------ .../protocols/did_exchange/v1_x/request.rs | 42 +++++++++++++---- 21 files changed, 320 insertions(+), 231 deletions(-) diff --git a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs index 607c64e87e..501a40f320 100644 --- a/aries/agents/aath-backchannel/src/controllers/did_exchange.rs +++ b/aries/agents/aath-backchannel/src/controllers/did_exchange.rs @@ -5,7 +5,7 @@ use aries_vcx_agent::aries_vcx::{ did_parser_nom::Did, messages::{ msg_fields::protocols::did_exchange::{ - v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::Request, DidExchange, + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::AnyRequest, DidExchange, }, AriesMessage, }, @@ -60,7 +60,7 @@ impl HarnessAgent { .to_string()) } - pub fn queue_didexchange_request(&self, request: Request) -> HarnessResult<()> { + pub fn queue_didexchange_request(&self, request: AnyRequest) -> HarnessResult<()> { info!("queue_didexchange_request >> request: {:?}", request); let mut msg_buffer = self.didx_msg_buffer.write().map_err(|_| { HarnessError::from_msg( @@ -162,9 +162,11 @@ impl HarnessAgent { })? }; let request = match request { - AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(request))) - | AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(request))) => { - request + AriesMessage::DidExchange(DidExchange::V1_0(DidExchangeV1_0::Request(r))) => { + AnyRequest::V1_0(r) + } + AriesMessage::DidExchange(DidExchange::V1_1(DidExchangeV1_1::Request(r))) => { + AnyRequest::V1_1(r) } _ => { return Err(HarnessError::from_msg( @@ -174,7 +176,7 @@ impl HarnessAgent { } }; - let request_thread = &request.decorators.thread; + let request_thread = &request.inner().decorators.thread; let opt_invitation = match request_thread.as_ref().and_then(|th| th.pthid.as_ref()) { Some(pthid) => { diff --git a/aries/agents/aath-backchannel/src/controllers/didcomm.rs b/aries/agents/aath-backchannel/src/controllers/didcomm.rs index 739722c6d9..ef8637f928 100644 --- a/aries/agents/aath-backchannel/src/controllers/didcomm.rs +++ b/aries/agents/aath-backchannel/src/controllers/didcomm.rs @@ -6,7 +6,10 @@ use aries_vcx_agent::aries_vcx::{ msg_fields::protocols::{ connection::Connection, cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, - did_exchange::{v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, DidExchange}, + did_exchange::{ + v1_0::DidExchangeV1_0, v1_1::DidExchangeV1_1, v1_x::request::AnyRequest, + DidExchange, + }, notification::Notification, present_proof::{v1::PresentProofV1, PresentProof}, }, @@ -197,9 +200,11 @@ impl HarnessAgent { async fn handle_did_exchange_msg(&self, msg: DidExchange) -> HarnessResult<()> { match msg { - DidExchange::V1_0(DidExchangeV1_0::Request(request)) - | DidExchange::V1_1(DidExchangeV1_1::Request(request)) => { - self.queue_didexchange_request(request)?; + DidExchange::V1_0(DidExchangeV1_0::Request(request)) => { + self.queue_didexchange_request(AnyRequest::V1_0(request))?; + } + DidExchange::V1_1(DidExchangeV1_1::Request(request)) => { + self.queue_didexchange_request(AnyRequest::V1_1(request))?; } DidExchange::V1_0(DidExchangeV1_0::Response(response)) => { let res = self diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index dffbe37a20..958f4bdd4c 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -6,7 +6,7 @@ use aries_vcx::{ messages::{ msg_fields::protocols::{ did_exchange::v1_x::{ - complete::Complete, problem_report::ProblemReport, request::Request, + complete::Complete, problem_report::ProblemReport, request::AnyRequest, response::AnyResponse, }, out_of_band::invitation::Invitation as OobInvitation, @@ -87,31 +87,16 @@ impl DidcommHandlerDidExchange { // /agent/command/did-exchange/{id} where {id} is actually {pthid}. // We should have internal strategy to manage threads ourselves, and build necessary // extensions/mappings/accommodations in AATH backchannel - warn!("send_request >>> request: {}", request); - let pthid = request - .clone() - .decorators - .thread - .ok_or_else(|| { - AgentError::from_msg( - AgentErrorKind::InvalidState, - "Request did not contain a thread", - ) - })? - .pthid; - + warn!("send_request >>> request: {:?}", request); + let req_thread = request.inner().decorators.thread.as_ref().ok_or_else(|| { + AgentError::from_msg( + AgentErrorKind::InvalidState, + "Request did not contain a thread", + ) + })?; + let pthid = req_thread.pthid.clone(); // todo: messages must provide easier way to access this without all the shenanigans - let thid = request - .clone() - .decorators - .thread - .ok_or_else(|| { - AgentError::from_msg( - AgentErrorKind::InvalidState, - "Request did not contain a thread id", - ) - })? - .thid; + let thid = req_thread.thid.clone(); let ddo_their = requester.their_did_doc(); let ddo_our = requester.our_did_document(); @@ -139,13 +124,13 @@ impl DidcommHandlerDidExchange { // rather than being supplied by upper layers pub async fn handle_msg_request( &self, - request: Request, + request: AnyRequest, invitation: Option, ) -> AgentResult<(String, Option, String, String)> { // todo: type the return type // Todo: messages should expose fallible API to get thid (for any aries msg). It's common // pattern - let thread = request.decorators.thread.as_ref(); + let thread = request.inner().decorators.thread.as_ref(); let thid = thread .ok_or_else(|| { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index cf4301f006..08de2843fc 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -6,9 +6,11 @@ use did_parser_nom::Did; use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; use messages::{ - msg_fields::protocols::did_exchange::{ - v1_1::request::Request, - v1_x::{complete::Complete, problem_report::ProblemReport, response::AnyResponse}, + msg_fields::protocols::did_exchange::v1_x::{ + complete::{AnyComplete, Complete}, + problem_report::ProblemReport, + request::AnyRequest, + response::AnyResponse, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -94,7 +96,7 @@ impl GenericDidExchange { our_peer_did: &PeerDid, our_label: String, version: DidExchangeTypeV1, - ) -> Result<(Self, Request), AriesVcxError> { + ) -> Result<(Self, AnyRequest), AriesVcxError> { let TransitionResult { state, output } = DidExchangeRequester::::construct_request( resolver_registry, @@ -114,7 +116,7 @@ impl GenericDidExchange { pub async fn handle_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: Request, + request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, ) -> Result<(Self, AnyResponse), AriesVcxError> { @@ -137,7 +139,7 @@ impl GenericDidExchange { self, response: AnyResponse, resolver_registry: Arc, - ) -> Result<(Self, Complete), (Self, AriesVcxError)> { + ) -> Result<(Self, AnyComplete), (Self, AriesVcxError)> { match self { GenericDidExchange::Requester(requester_state) => match requester_state { RequesterState::RequestSent(request_sent_state) => { diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs index e4aee62f37..c54f331aff 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/mod.rs @@ -11,9 +11,8 @@ use did_doc::schema::did_doc::DidDocument; use messages::{ decorators::{thread::Thread, timing::Timing}, msg_fields::protocols::did_exchange::v1_x::problem_report::{ - ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, + AnyProblemReport, ProblemCode, ProblemReport, ProblemReportContent, ProblemReportDecorators, }, - msg_types::protocols::did_exchange::DidExchangeTypeV1, }; use uuid::Uuid; @@ -39,11 +38,10 @@ impl DidExchange { self, reason: String, problem_code: Option, - ) -> TransitionResult, ProblemReport> { + ) -> TransitionResult, AnyProblemReport> { let content = ProblemReportContent::builder() .problem_code(problem_code) .explain(Some(reason.clone())) - .version(DidExchangeTypeV1::new_v1_1()) .build(); let decorators = ProblemReportDecorators::builder() .thread( @@ -69,7 +67,7 @@ impl DidExchange { our_did_document: self.our_did_document, their_did_document: self.their_did_document, }, - output: problem_report, + output: AnyProblemReport::V1_1(problem_report), } } diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs index f985a40afc..cd00d4cf91 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/helpers.rs @@ -7,8 +7,8 @@ use messages::{ }, msg_fields::protocols::{ did_exchange::v1_x::{ - complete::{Complete, CompleteDecorators}, - request::{Request, RequestContent, RequestDecorators}, + complete::{AnyComplete, Complete, CompleteDecorators}, + request::{AnyRequest, Request, RequestContent, RequestDecorators}, }, out_of_band::invitation::{Invitation, OobService}, }, @@ -27,7 +27,7 @@ pub fn construct_request( our_did: String, our_label: String, version: DidExchangeTypeV1, -) -> Request { +) -> AnyRequest { let msg_id = Uuid::new_v4().to_string(); let thid = msg_id.clone(); let thread = match invitation_id { @@ -44,13 +44,17 @@ pub fn construct_request( .did_doc(None) .goal(Some("To establish a connection".into())) // Rejected if non-empty by acapy .goal_code(Some(MaybeKnown::Known(ThreadGoalCode::AriesRelBuild))) // Rejected if non-empty by acapy - .version(version) .build(); - Request::builder() + let req = Request::builder() .id(msg_id) .content(content) .decorators(decorators) - .build() + .build(); + + match version { + DidExchangeTypeV1::V1_1(_) => AnyRequest::V1_1(req), + DidExchangeTypeV1::V1_0(_) => AnyRequest::V1_0(req), + } } pub fn construct_didexchange_complete( @@ -58,7 +62,7 @@ pub fn construct_didexchange_complete( invitation_id: Option, request_id: String, version: DidExchangeTypeV1, -) -> Complete { +) -> AnyComplete { let thread = match invitation_id { Some(invitation_id) => Thread::builder() .thid(request_id) @@ -69,12 +73,16 @@ pub fn construct_didexchange_complete( let decorators = CompleteDecorators::builder() .thread(thread) .timing(Timing::builder().out_time(Utc::now()).build()) - .version(version) .build(); - Complete::builder() + let msg = Complete::builder() .id(Uuid::new_v4().to_string()) .decorators(decorators) - .build() + .build(); + + match version { + DidExchangeTypeV1::V1_1(_) => AnyComplete::V1_1(msg), + DidExchangeTypeV1::V1_0(_) => AnyComplete::V1_0(msg), + } } /// We are going to support only DID service values in did-exchange protocol unless there's explicit diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 99bbffd484..30c351239d 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -5,9 +5,8 @@ use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver::traits::resolvable::resolution_output::DidResolutionOutput; use did_resolver_registry::ResolverRegistry; use messages::{ - msg_fields::protocols::did_exchange::{ - v1_1::request::Request, - v1_x::{complete::Complete, response::AnyResponse}, + msg_fields::protocols::did_exchange::v1_x::{ + complete::AnyComplete, request::AnyRequest, response::AnyResponse, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -33,7 +32,7 @@ impl DidExchangeRequester { our_peer_did: &PeerDid, our_label: String, version: DidExchangeTypeV1, - ) -> Result, AriesVcxError> { + ) -> Result, AriesVcxError> { debug!( "DidExchangeRequester::construct_request >> their_did: {}, our_peer_did: \ {}", @@ -52,13 +51,13 @@ impl DidExchangeRequester { ); debug!( - "DidExchangeRequester::construct_request << prepared request: {}", + "DidExchangeRequester::construct_request << prepared request: {:?}", request ); Ok(TransitionResult { state: DidExchangeRequester::from_parts( RequestSent { - request_id: request.id.clone(), + request_id: request.inner().id.clone(), invitation_id, }, their_did_document, @@ -72,7 +71,7 @@ impl DidExchangeRequester { self, response: AnyResponse, resolver_registry: Arc, - ) -> Result, Complete>, TransitionError> + ) -> Result, AnyComplete>, TransitionError> { debug!( "DidExchangeRequester::receive_response >> response: {:?}", diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 4fa2c20392..524eee4f77 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -6,7 +6,9 @@ use did_peer::peer_did::{numalgos::numalgo4::Numalgo4, PeerDid}; use did_resolver_registry::ResolverRegistry; use messages::{ msg_fields::protocols::did_exchange::v1_x::{ - complete::Complete, request::Request, response::AnyResponse, + complete::Complete, + request::{AnyRequest, Request}, + response::AnyResponse, }, msg_types::protocols::did_exchange::DidExchangeTypeV1, }; @@ -29,7 +31,7 @@ impl DidExchangeResponder { pub async fn receive_request( wallet: &impl BaseWallet, resolver_registry: Arc, - request: Request, + request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, ) -> Result, AnyResponse>, AriesVcxError> @@ -40,6 +42,7 @@ impl DidExchangeResponder { request, our_peer_did, invitation_key ); let version = request.get_version(); + let request = request.into_inner(); let their_ddo = resolve_ddo_from_request(&resolver_registry, &request).await?; let our_did_document = our_peer_did.resolve_did_doc()?; diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index 1af5f167ae..ad1b2ae096 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -135,7 +135,7 @@ async fn did_exchange_test() -> Result<(), Box> { .await .unwrap(); info!( - "Invitee processes invitation, builds up request {}", + "Invitee processes invitation, builds up request {:?}", &request ); @@ -168,7 +168,7 @@ async fn did_exchange_test() -> Result<(), Box> { .await .unwrap(); - let responder = responder.receive_complete(complete).unwrap(); + let responder = responder.receive_complete(complete.into_inner()).unwrap(); info!("Asserting did document of requester"); assert_key_agreement( diff --git a/aries/messages/src/misc/mod.rs b/aries/messages/src/misc/mod.rs index b264511e6f..ae768dd633 100644 --- a/aries/messages/src/misc/mod.rs +++ b/aries/messages/src/misc/mod.rs @@ -70,25 +70,37 @@ pub mod test_utils { assert_eq!(Protocol::from(protocol_type), deserialized) } - pub fn test_msg(content: T, decorators: U, msg_kind: V, mut expected: Value) + pub fn test_msg(content: T, decorators: U, msg_kind: V, expected: Value) where AriesMessage: From>, V: MessageKind, Protocol: From, { let id = "test".to_owned(); - let msg_type = build_msg_type(msg_kind); - - let obj = expected.as_object_mut().expect("JSON object"); - obj.insert("@id".to_owned(), json!(id)); - obj.insert("@type".to_owned(), json!(msg_type)); let msg = MsgParts::::builder() .id(id) .content(content) .decorators(decorators) .build(); - let msg = AriesMessage::from(msg); + + test_constructed_msg(msg, msg_kind, expected); + } + + pub fn test_constructed_msg(complete: M, msg_kind: V, mut expected: Value) + where + AriesMessage: From, + V: MessageKind, + Protocol: From, + { + let id = "test".to_owned(); + let msg_type = build_msg_type(msg_kind); + + let obj = expected.as_object_mut().expect("JSON object"); + obj.insert("@id".to_owned(), json!(id)); + obj.insert("@type".to_owned(), json!(msg_type)); + + let msg = AriesMessage::from(complete); test_serde(msg, expected); } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs index 1065fb8dcb..1cab9fbbec 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/complete.rs @@ -6,7 +6,7 @@ use crate::{ /// Alias type for DIDExchange v1.0 Complete message. /// Note that since this inherits from the V1.X message, the direct serialization -/// of this message type is not recommended, as version metadata will be lost. +/// of this message type is not recommended, as it will be indistinguisable from V1.1. /// Instead, this type should be converted to/from an AriesMessage pub type Complete = MsgParts; @@ -23,7 +23,8 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, + msg_fields::protocols::did_exchange::v1_x::complete::AnyComplete, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; #[test] @@ -36,17 +37,17 @@ mod tests { } }); - let decorators = CompleteDecorators::builder() - .thread(thread) - .version(DidExchangeTypeV1::new_v1_0()) - .build(); + let decorators = CompleteDecorators::builder().thread(thread).build(); - test_utils::test_msg( - NoContent, - decorators, - DidExchangeTypeV1_0::Complete, - expected, + let msg = AnyComplete::V1_0( + Complete::builder() + .id("test".to_owned()) + .content(NoContent) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::Complete, expected); } #[test] @@ -54,7 +55,6 @@ mod tests { let decorators = CompleteDecorators { thread: make_extended_thread(), timing: Some(make_extended_timing()), - version: DidExchangeTypeV1::new_v1_0(), }; let expected = json!({ @@ -62,11 +62,14 @@ mod tests { "~timing": serde_json::to_value(make_extended_timing()).unwrap() }); - test_utils::test_msg( - NoContent, - decorators, - DidExchangeTypeV1_0::Complete, - expected, + let msg = AnyComplete::V1_0( + Complete::builder() + .id("test".to_owned()) + .content(NoContent) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::Complete, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs index 9b518b0009..37a5adde35 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/mod.rs @@ -16,10 +16,7 @@ use super::{v1_x::response::ResponseDecorators, DidExchange}; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, - msg_types::{ - protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, - MsgKindType, MsgWithType, - }, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_0, MsgKindType, MsgWithType}, }; #[derive(Clone, Debug, From, PartialEq)] @@ -44,21 +41,12 @@ impl DelayedSerde for DidExchangeV1_0 { let kind = protocol.kind_from_str(kind_str); match kind.map_err(D::Error::custom)? { - DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(|mut c| { - c.content.version = DidExchangeTypeV1::new_v1_0(); - c.into() - }), + DidExchangeTypeV1_0::Request => Request::deserialize(deserializer).map(From::from), DidExchangeTypeV1_0::Response => Response::deserialize(deserializer).map(From::from), DidExchangeTypeV1_0::ProblemReport => { - ProblemReport::deserialize(deserializer).map(|mut c| { - c.content.version = DidExchangeTypeV1::new_v1_0(); - c.into() - }) + ProblemReport::deserialize(deserializer).map(From::from) } - DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(|mut c| { - c.decorators.version = DidExchangeTypeV1::new_v1_0(); - c.into() - }), + DidExchangeTypeV1_0::Complete => Complete::deserialize(deserializer).map(From::from), } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs index db06040f23..6c8a3352cd 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/problem_report.rs @@ -24,8 +24,10 @@ mod tests { thread::tests::make_extended_thread, timing::tests::make_extended_timing, }, misc::test_utils, - msg_fields::protocols::did_exchange::v1_x::problem_report::ProblemCode, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, + msg_fields::protocols::did_exchange::v1_x::problem_report::{ + AnyProblemReport, ProblemCode, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; #[test] @@ -33,7 +35,6 @@ mod tests { let content = ProblemReportContent::builder() .problem_code(None) .explain(None) - .version(DidExchangeTypeV1::new_v1_0()) .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -42,12 +43,15 @@ mod tests { "~thread": decorators.thread }); - test_utils::test_msg( - content, - decorators, - DidExchangeTypeV1_0::ProblemReport, - expected, + let msg = AnyProblemReport::V1_0( + ProblemReport::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::ProblemReport, expected); } #[test] @@ -55,7 +59,6 @@ mod tests { let content = ProblemReportContent::builder() .problem_code(Some(ProblemCode::RequestNotAccepted)) .explain(Some("test_conn_problem_report_explain".to_owned())) - .version(DidExchangeTypeV1::new_v1_0()) .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -70,11 +73,14 @@ mod tests { "~l10n": decorators.localization }); - test_utils::test_msg( - content, - decorators, - DidExchangeTypeV1_0::ProblemReport, - expected, + let msg = AnyProblemReport::V1_0( + ProblemReport::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::ProblemReport, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs index 713ba45fd8..ed8a1eca0b 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_0/request.rs @@ -5,7 +5,7 @@ use crate::{ /// Alias type for DIDExchange v1.0 Request message. /// Note that since this inherits from the V1.X message, the direct serialization -/// of this Request is not recommended, as version metadata will be lost. +/// of this Request is not recommended, as it will be indistinguisable from Request V1.1. /// Instead, this type should be converted to/from an AriesMessage pub type Request = MsgParts; @@ -25,8 +25,11 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_fields::protocols::did_exchange::v1_0::request::{Request, RequestDecorators}, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_0}, + msg_fields::protocols::did_exchange::{ + v1_0::request::{Request, RequestDecorators}, + v1_x::request::AnyRequest, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1_0, }; pub fn request_content() -> RequestContent { @@ -47,7 +50,6 @@ mod tests { ) .build(), ), - version: DidExchangeTypeV1::new_v1_0(), } } @@ -59,10 +61,7 @@ mod tests { .decorators(RequestDecorators::default()) .build(); let printed_json = format!("{}", msg); - let mut parsed_request: Request = serde_json::from_str(&printed_json).unwrap(); - // the serialized format of [Request] directly will not retain the version metadata, - // that information is the responsibility of higher up layers. - parsed_request.content.version = DidExchangeTypeV1::new_v1_0(); + let parsed_request: Request = serde_json::from_str(&printed_json).unwrap(); assert_eq!(msg, parsed_request); } @@ -76,12 +75,16 @@ mod tests { "did": content.did, "did_doc~attach": content.did_doc, }); - test_utils::test_msg( - content, - RequestDecorators::default(), - DidExchangeTypeV1_0::Request, - expected, + + let msg = AnyRequest::V1_0( + Request::builder() + .id("test".to_owned()) + .content(content) + .decorators(RequestDecorators::default()) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::Request, expected); } #[test] @@ -102,6 +105,14 @@ mod tests { "~timing": decorators.timing }); - test_utils::test_msg(content, decorators, DidExchangeTypeV1_0::Request, expected); + let msg = AnyRequest::V1_0( + Request::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), + ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_0::Request, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs index ddddff23e5..7b9e3db321 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/complete.rs @@ -6,7 +6,7 @@ use crate::{ /// Alias type for DIDExchange v1.1 Complete message. /// Note that since this inherits from the V1.X message, the direct serialization -/// of this message type is not recommended, as version metadata will be lost. +/// of this message type is not recommended, as it will be indistinguisable from V1.0. /// Instead, this type should be converted to/from an AriesMessage pub type Complete = MsgParts; @@ -23,7 +23,8 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, + msg_fields::protocols::did_exchange::v1_x::complete::AnyComplete, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; #[test] @@ -36,17 +37,17 @@ mod tests { } }); - let decorators = CompleteDecorators::builder() - .thread(thread) - .version(DidExchangeTypeV1::new_v1_1()) - .build(); + let decorators = CompleteDecorators::builder().thread(thread).build(); - test_utils::test_msg( - NoContent, - decorators, - DidExchangeTypeV1_1::Complete, - expected, + let msg = AnyComplete::V1_1( + Complete::builder() + .id("test".to_owned()) + .content(NoContent) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::Complete, expected); } #[test] @@ -54,7 +55,6 @@ mod tests { let decorators = CompleteDecorators { thread: make_extended_thread(), timing: Some(make_extended_timing()), - version: DidExchangeTypeV1::new_v1_1(), }; let expected = json!({ @@ -62,11 +62,14 @@ mod tests { "~timing": serde_json::to_value(make_extended_timing()).unwrap() }); - test_utils::test_msg( - NoContent, - decorators, - DidExchangeTypeV1_1::Complete, - expected, + let msg = AnyComplete::V1_1( + Complete::builder() + .id("test".to_owned()) + .content(NoContent) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::Complete, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs index b7747ae096..698c7a8bba 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/mod.rs @@ -16,10 +16,7 @@ use super::{v1_x::response::ResponseDecorators, DidExchange}; use crate::{ misc::utils::{into_msg_with_type, transit_to_aries_msg}, msg_fields::traits::DelayedSerde, - msg_types::{ - protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, - MsgKindType, MsgWithType, - }, + msg_types::{protocols::did_exchange::DidExchangeTypeV1_1, MsgKindType, MsgWithType}, }; #[derive(Clone, Debug, From, PartialEq)] @@ -44,21 +41,12 @@ impl DelayedSerde for DidExchangeV1_1 { let kind = protocol.kind_from_str(kind_str); match kind.map_err(D::Error::custom)? { - DidExchangeTypeV1_1::Request => Request::deserialize(deserializer).map(|mut c| { - c.content.version = DidExchangeTypeV1::new_v1_1(); - c.into() - }), + DidExchangeTypeV1_1::Request => Request::deserialize(deserializer).map(From::from), DidExchangeTypeV1_1::Response => Response::deserialize(deserializer).map(From::from), DidExchangeTypeV1_1::ProblemReport => { - ProblemReport::deserialize(deserializer).map(|mut c| { - c.content.version = DidExchangeTypeV1::new_v1_1(); - c.into() - }) + ProblemReport::deserialize(deserializer).map(From::from) } - DidExchangeTypeV1_1::Complete => Complete::deserialize(deserializer).map(|mut c| { - c.decorators.version = DidExchangeTypeV1::new_v1_1(); - c.into() - }), + DidExchangeTypeV1_1::Complete => Complete::deserialize(deserializer).map(From::from), } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs index ec7625842c..86a998da92 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/problem_report.rs @@ -25,9 +25,9 @@ mod tests { }, misc::test_utils, msg_fields::protocols::did_exchange::v1_x::problem_report::{ - ProblemCode, ProblemReportDecorators, + AnyProblemReport, ProblemCode, ProblemReportDecorators, }, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; #[test] @@ -35,7 +35,6 @@ mod tests { let content = ProblemReportContent::builder() .problem_code(None) .explain(None) - .version(DidExchangeTypeV1::new_v1_1()) .build(); let decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -44,12 +43,15 @@ mod tests { "~thread": decorators.thread }); - test_utils::test_msg( - content, - decorators, - DidExchangeTypeV1_1::ProblemReport, - expected, + let msg = AnyProblemReport::V1_1( + ProblemReport::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::ProblemReport, expected); } #[test] @@ -57,7 +59,6 @@ mod tests { let content = ProblemReportContent::builder() .problem_code(Some(ProblemCode::RequestNotAccepted)) .explain(Some("test_conn_problem_report_explain".to_owned())) - .version(DidExchangeTypeV1::new_v1_1()) .build(); let mut decorators = ProblemReportDecorators::new(make_extended_thread()); @@ -72,11 +73,14 @@ mod tests { "~l10n": decorators.localization }); - test_utils::test_msg( - content, - decorators, - DidExchangeTypeV1_1::ProblemReport, - expected, + let msg = AnyProblemReport::V1_1( + ProblemReport::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::ProblemReport, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs index 9cf901690a..44456ea24e 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_1/request.rs @@ -5,7 +5,7 @@ use crate::{ /// Alias type for DIDExchange v1.1 request message. /// Note that since this inherits from the V1.X message, the direct serialization -/// of this message type is not recommended, as version metadata will be lost. +/// of this message type is not recommended, as it will be indistinguisable from Request V1.0. /// Instead, this type should be converted to/from an AriesMessage pub type Request = MsgParts; @@ -25,8 +25,11 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_fields::protocols::did_exchange::v1_1::request::{Request, RequestDecorators}, - msg_types::protocols::did_exchange::{DidExchangeTypeV1, DidExchangeTypeV1_1}, + msg_fields::protocols::did_exchange::{ + v1_1::request::{Request, RequestDecorators}, + v1_x::request::AnyRequest, + }, + msg_types::protocols::did_exchange::DidExchangeTypeV1_1, }; pub fn request_content() -> RequestContent { @@ -47,7 +50,6 @@ mod tests { ) .build(), ), - version: DidExchangeTypeV1::new_v1_1(), } } @@ -73,12 +75,16 @@ mod tests { "did": content.did, "did_doc~attach": content.did_doc, }); - test_utils::test_msg( - content, - RequestDecorators::default(), - DidExchangeTypeV1_1::Request, - expected, + + let msg = AnyRequest::V1_1( + Request::builder() + .id("test".to_owned()) + .content(content) + .decorators(RequestDecorators::default()) + .build(), ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::Request, expected); } #[test] @@ -99,6 +105,14 @@ mod tests { "~timing": decorators.timing }); - test_utils::test_msg(content, decorators, DidExchangeTypeV1_1::Request, expected); + let msg = AnyRequest::V1_1( + Request::builder() + .id("test".to_owned()) + .content(content) + .decorators(decorators) + .build(), + ); + + test_utils::test_constructed_msg(msg, DidExchangeTypeV1_1::Request, expected); } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs index dc223cada3..f225d817f1 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/complete.rs @@ -14,7 +14,7 @@ use crate::{ /// Alias type for the shared DIDExchange v1.X complete message type. /// Note the direct serialization of this message type is not recommended, -/// as version metadata will be lost. +/// as it will be indistinguisable between V1.1 & V1.0. /// Instead, this type should be converted to/from an AriesMessage pub type Complete = MsgParts; @@ -27,25 +27,43 @@ pub struct CompleteDecorators { #[serde(rename = "~timing")] #[serde(skip_serializing_if = "Option::is_none")] pub timing: Option, - #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] - pub(crate) version: DidExchangeTypeV1, } -impl Complete { +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum AnyComplete { + V1_0(Complete), + V1_1(Complete), +} + +impl AnyComplete { pub fn get_version(&self) -> DidExchangeTypeV1 { - self.decorators.version + match self { + AnyComplete::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyComplete::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } +} + +impl AnyComplete { + pub fn into_inner(self) -> Complete { + match self { + AnyComplete::V1_0(r) | AnyComplete::V1_1(r) => r, + } + } + + pub fn inner(&self) -> &Complete { + match self { + AnyComplete::V1_0(r) | AnyComplete::V1_1(r) => r, + } } } -impl From for AriesMessage { - fn from(value: Complete) -> Self { - match value.get_version() { - DidExchangeTypeV1::V1_0(_) => { - DidExchange::V1_0(DidExchangeV1_0::Complete(value)).into() - } - DidExchangeTypeV1::V1_1(_) => { - DidExchange::V1_1(DidExchangeV1_1::Complete(value)).into() - } +impl From for AriesMessage { + fn from(value: AnyComplete) -> Self { + match value { + AnyComplete::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Complete(inner)).into(), + AnyComplete::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Complete(inner)).into(), } } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs index b67e5dfa4c..1f78c6e021 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs @@ -24,8 +24,6 @@ pub struct ProblemReportContent { pub problem_code: Option, #[serde(skip_serializing_if = "Option::is_none")] pub explain: Option, - #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] - pub(crate) version: DidExchangeTypeV1, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] @@ -61,21 +59,41 @@ impl ProblemReportDecorators { } } -impl ProblemReport { +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum AnyProblemReport { + V1_0(ProblemReport), + V1_1(ProblemReport), +} + +impl AnyProblemReport { pub fn get_version(&self) -> DidExchangeTypeV1 { - self.content.version + match self { + AnyProblemReport::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyProblemReport::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } +} + +impl AnyProblemReport { + pub fn into_inner(self) -> ProblemReport { + match self { + AnyProblemReport::V1_0(r) | AnyProblemReport::V1_1(r) => r, + } + } + + pub fn inner(&self) -> &ProblemReport { + match self { + AnyProblemReport::V1_0(r) | AnyProblemReport::V1_1(r) => r, + } } } -impl From for AriesMessage { - fn from(value: ProblemReport) -> Self { - match value.get_version() { - DidExchangeTypeV1::V1_0(_) => { - DidExchange::V1_0(DidExchangeV1_0::ProblemReport(value)).into() - } - DidExchangeTypeV1::V1_1(_) => { - DidExchange::V1_1(DidExchangeV1_1::ProblemReport(value)).into() - } +impl From for AriesMessage { + fn from(value: AnyProblemReport) -> Self { + match value { + AnyProblemReport::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::ProblemReport(inner)).into(), + AnyProblemReport::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::ProblemReport(inner)).into(), } } } diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs index 4ac427c70e..1d2d8838bc 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/request.rs @@ -18,7 +18,7 @@ use crate::{ /// Alias type for the shared DIDExchange v1.X request message type. /// Note the direct serialization of this message type is not recommended, -/// as version metadata will be lost. +/// as it will be indistinguisable between V1.1 & V1.0. /// Instead, this type should be converted to/from an AriesMessage pub type Request = MsgParts; @@ -32,8 +32,6 @@ pub struct RequestContent { pub did: String, // TODO: Use Did #[serde(rename = "did_doc~attach", skip_serializing_if = "Option::is_none")] pub did_doc: Option, - #[serde(skip, default = "DidExchangeTypeV1::new_v1_1")] - pub(crate) version: DidExchangeTypeV1, } #[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] @@ -47,17 +45,41 @@ pub struct RequestDecorators { pub timing: Option, } -impl Request { +#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)] +#[serde(untagged)] +pub enum AnyRequest { + V1_0(Request), + V1_1(Request), +} + +impl AnyRequest { pub fn get_version(&self) -> DidExchangeTypeV1 { - self.content.version + match self { + AnyRequest::V1_0(_) => DidExchangeTypeV1::new_v1_0(), + AnyRequest::V1_1(_) => DidExchangeTypeV1::new_v1_1(), + } + } +} + +impl AnyRequest { + pub fn into_inner(self) -> Request { + match self { + AnyRequest::V1_0(r) | AnyRequest::V1_1(r) => r, + } + } + + pub fn inner(&self) -> &Request { + match self { + AnyRequest::V1_0(r) | AnyRequest::V1_1(r) => r, + } } } -impl From for AriesMessage { - fn from(value: Request) -> Self { - match value.get_version() { - DidExchangeTypeV1::V1_0(_) => DidExchange::V1_0(DidExchangeV1_0::Request(value)).into(), - DidExchangeTypeV1::V1_1(_) => DidExchange::V1_1(DidExchangeV1_1::Request(value)).into(), +impl From for AriesMessage { + fn from(value: AnyRequest) -> Self { + match value { + AnyRequest::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::Request(inner)).into(), + AnyRequest::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::Request(inner)).into(), } } } From 8265ec11691824b6ebc51d0ca4279bcb33455659 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 26 Jun 2024 11:50:46 +1000 Subject: [PATCH 30/32] lint Signed-off-by: George Mulhearn --- .../protocols/did_exchange/v1_x/problem_report.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs index 1f78c6e021..e8f3d862d3 100644 --- a/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs +++ b/aries/messages/src/msg_fields/protocols/did_exchange/v1_x/problem_report.rs @@ -92,8 +92,12 @@ impl AnyProblemReport { impl From for AriesMessage { fn from(value: AnyProblemReport) -> Self { match value { - AnyProblemReport::V1_0(inner) => DidExchange::V1_0(DidExchangeV1_0::ProblemReport(inner)).into(), - AnyProblemReport::V1_1(inner) => DidExchange::V1_1(DidExchangeV1_1::ProblemReport(inner)).into(), + AnyProblemReport::V1_0(inner) => { + DidExchange::V1_0(DidExchangeV1_0::ProblemReport(inner)).into() + } + AnyProblemReport::V1_1(inner) => { + DidExchange::V1_1(DidExchangeV1_1::ProblemReport(inner)).into() + } } } } From 883880499a471b57faa347115bec4dc4c26dcfbb Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Wed, 26 Jun 2024 13:36:58 +1000 Subject: [PATCH 31/32] borrow registries instead Signed-off-by: George Mulhearn --- aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs | 4 ++-- .../protocols/did_exchange/state_machine/generic/mod.rs | 4 ++-- .../state_machine/requester/request_sent/mod.rs | 2 +- .../state_machine/responder/response_sent/mod.rs | 4 ++-- aries/aries_vcx/tests/test_did_exchange.rs | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs index 5ae8625421..b602110917 100644 --- a/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs +++ b/aries/agents/aries-vcx-agent/src/handlers/did_exchange.rs @@ -73,7 +73,7 @@ impl DidcommHandlerDidExchange { let their_did: Did = their_did.parse()?; let (requester, request) = GenericDidExchange::construct_request( - self.resolver_registry.clone(), + &self.resolver_registry, invitation_id, &their_did, &our_peer_did, @@ -170,7 +170,7 @@ impl DidcommHandlerDidExchange { let (responder, response) = GenericDidExchange::handle_request( self.wallet.as_ref(), - self.resolver_registry.clone(), + &self.resolver_registry, request, &our_peer_did, invitation_key, diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs index c4c0ca980b..fc5adacb05 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/generic/mod.rs @@ -90,7 +90,7 @@ impl GenericDidExchange { } pub async fn construct_request( - resolver_registry: Arc, + resolver_registry: &Arc, invitation_id: Option, their_did: &Did, our_peer_did: &PeerDid, @@ -115,7 +115,7 @@ impl GenericDidExchange { pub async fn handle_request( wallet: &impl BaseWallet, - resolver_registry: Arc, + resolver_registry: &Arc, request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs index 9ae6a1b4c5..a171d91087 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/requester/request_sent/mod.rs @@ -33,7 +33,7 @@ use crate::{ impl DidExchangeRequester { pub async fn construct_request( - resolver_registry: Arc, + resolver_registry: &Arc, invitation_id: Option, their_did: &Did, our_peer_did: &PeerDid, diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs index 524eee4f77..27e1ffba44 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/responder/response_sent/mod.rs @@ -30,7 +30,7 @@ use crate::{ impl DidExchangeResponder { pub async fn receive_request( wallet: &impl BaseWallet, - resolver_registry: Arc, + resolver_registry: &Arc, request: AnyRequest, our_peer_did: &PeerDid, invitation_key: Option, @@ -44,7 +44,7 @@ impl DidExchangeResponder { let version = request.get_version(); let request = request.into_inner(); - let their_ddo = resolve_ddo_from_request(&resolver_registry, &request).await?; + let their_ddo = resolve_ddo_from_request(resolver_registry, &request).await?; let our_did_document = our_peer_did.resolve_did_doc()?; let unsigned_attachment = match version { diff --git a/aries/aries_vcx/tests/test_did_exchange.rs b/aries/aries_vcx/tests/test_did_exchange.rs index b1b0ad42be..bb3f34c8a9 100644 --- a/aries/aries_vcx/tests/test_did_exchange.rs +++ b/aries/aries_vcx/tests/test_did_exchange.rs @@ -105,7 +105,7 @@ async fn did_exchange_test( state: requester, output: request, } = DidExchangeRequester::::construct_request( - resolver_registry.clone(), + &resolver_registry, Some(invitation.id), &did_inviter, &requesters_peer_did, @@ -132,7 +132,7 @@ async fn did_exchange_test( state: responder, } = DidExchangeResponder::::receive_request( &agent_inviter.wallet, - resolver_registry.clone(), + &resolver_registry, request, &responders_peer_did, Some(invitation_key.clone()), @@ -315,7 +315,7 @@ async fn did_exchange_test_with_invalid_rotation_signature() -> Result<(), Box::construct_request( - resolver_registry.clone(), + &resolver_registry, Some(invitation.id), &did_inviter, &requesters_peer_did, @@ -333,7 +333,7 @@ async fn did_exchange_test_with_invalid_rotation_signature() -> Result<(), Box::receive_request( &agent_inviter.wallet, - resolver_registry.clone(), + &resolver_registry, request, &responders_peer_did, // sign with NOT the invitation key From e181f4fda463cf262705f5aafcaa427fdcbd29b9 Mon Sep 17 00:00:00 2001 From: George Mulhearn Date: Thu, 4 Jul 2024 12:05:48 +1000 Subject: [PATCH 32/32] jws testing Signed-off-by: George Mulhearn --- .../src/protocols/did_exchange/mod.rs | 5 ++ .../did_exchange/state_machine/helpers.rs | 87 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/aries/aries_vcx/src/protocols/did_exchange/mod.rs b/aries/aries_vcx/src/protocols/did_exchange/mod.rs index af2a6010cc..df8d3f4f03 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/mod.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/mod.rs @@ -115,6 +115,11 @@ pub async fn resolve_enc_key_from_invitation( } } +/// Attempts to resolve a [Key] in the [DidDocument] that can be used for sending encrypted +/// messages. The approach is: +/// * check the service for a recipient key, +/// * if there is none, use the first key agreement key in the DIDDoc, +/// * else fail pub fn resolve_enc_key_from_did_doc(did_doc: &DidDocument) -> Result { // prefer first service key if available if let Some(service_recipient_key) = did_doc diff --git a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs index 447e62089a..bafbe57eb3 100644 --- a/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs +++ b/aries/aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs @@ -321,3 +321,90 @@ where state, } } + +#[cfg(test)] +mod tests { + use std::error::Error; + + use aries_vcx_wallet::wallet::base_wallet::did_wallet::DidWallet; + use messages::decorators::attachment::{Attachment, AttachmentData, AttachmentType}; + use public_key::Key; + use test_utils::devsetup::build_setup_profile; + + use crate::{ + protocols::did_exchange::state_machine::helpers::{jws_sign_attach, jws_verify_attachment}, + utils::base64::URL_SAFE_LENIENT, + }; + + // assert self fulfilling + #[tokio::test] + async fn test_jws_sign_and_verify_attachment() -> Result<(), Box> { + let setup = build_setup_profile().await; + let wallet = &setup.wallet; + let signer_did = wallet.create_and_store_my_did(None, None).await?; + let signer = signer_did.verkey(); + + let content_b64 = base64::engine::Engine::encode(&URL_SAFE_LENIENT, "hello world"); + let attach = Attachment::builder() + .data( + AttachmentData::builder() + .content(AttachmentType::Base64(content_b64)) + .build(), + ) + .build(); + + let signed_attach = jws_sign_attach(attach, signer.clone(), wallet).await?; + + // should contain signed JWS + assert_eq!(signed_attach.data.jws.as_ref().unwrap().len(), 3); + + // verify + assert!(jws_verify_attachment(&signed_attach, signer, wallet).await?); + + // verify with wrong key should be false + let wrong_did = wallet.create_and_store_my_did(None, None).await?; + let wrong_signer = wrong_did.verkey(); + assert!(!jws_verify_attachment(&signed_attach, wrong_signer, wallet).await?); + + Ok(()) + } + + // test vector taken from an ACApy 0.12.1 DIDExchange response + #[tokio::test] + async fn test_jws_verify_attachment_with_acapy_test_vector() -> Result<(), Box> { + let setup = build_setup_profile().await; + let wallet = &setup.wallet; + + let json = json!({ + "@id": "18bec73c-c621-4ef2-b3d8-085c59ac9e2b", + "mime-type": "text/string", + "data": { + "jws": { + "signature": "QxC2oLxAYav-fPOvjkn4OpMLng9qOo2fjsy0MoQotDgyVM_PRjYlatsrw6_rADpRpWR_GMpBVlBskuKxpsJIBQ", + "header": { + "kid": "did:key:z6MkpNusbzt7HSBwrBiRpZmbyLiBEsNGs2fotoYhykU8Muaz" + }, + "protected": "eyJhbGciOiAiRWREU0EiLCAiandrIjogeyJrdHkiOiAiT0tQIiwgImNydiI6ICJFZDI1NTE5IiwgIngiOiAiazNlOHZRTHpSZlFhZFhzVDBMUkMxMWhpX09LUlR6VFphd29ocmxhaW1ETSIsICJraWQiOiAiZGlkOmtleTp6Nk1rcE51c2J6dDdIU0J3ckJpUnBabWJ5TGlCRXNOR3MyZm90b1loeWtVOE11YXoifX0" + }, + // NOTE: includes b64 padding, but not recommended + "base64": "ZGlkOnBlZXI6NHpRbVhza2o1Sjc3NXRyWUpkaVVFZVlaUU5mYXZZQUREb25YMzJUOHF4VHJiU05oOno2MmY5VlFROER0N1VWRXJXcmp6YTd4MUVKOG50NWVxOWlaZk1BUGoyYnpyeGJycGY4VXdUTEpXVUJTV2U4dHNoRFl4ZDhlcmVSclRhOHRqVlhKNmNEOTV0Qml5dVdRVll6QzNtZWtUckJ4MzNjeXFCb2g0c3JGamdXZm1lcE5yOEZpRFI5aEoySExxMlM3VGZNWXIxNVN4UG52OExRR2lIV24zODhzVlF3ODRURVJFaTg4OXlUejZzeVVmRXhEaXdxWHZOTk05akt1eHc4NERvbmtVUDRHYkh0Q3B4R2hKYVBKWnlUWmJVaFF2SHBENGc2YzYyWTN5ZGQ0V1BQdXBYQVFISzJScFZod2hQWlVnQWQzN1lrcW1jb3FiWGFZTWFnekZZY3kxTEJ6NkdYekV5NjRrOGQ4WGhlem5vUkpIV3F4RTV1am5LYkpOM0pRR241UzREaEtRaXJTbUZINUJOYUNvRTZqaFlWc3gzWlpEM1ZWZVVxUW9ZMmVHMkNRVVRRak1zY0ozOEdqeDFiaVVlRkhZVVRrejRRVDJFWXpXRlVEbW1URHExVmVoZExtelJDWnNQUjJKR1VpVExUVkNzdUNzZ21jd1FqWHY4WmN6ejRaZUo0ODc4S3hBRm5mam1ibk1EejV5NVJOMnZtRGtkaE42dFFMZjJEWVJuSm1vSjJ5VTNheXczU2NjV0VMVzNpWEN6UFROV1F3WmFEb2d5UFVXZFBobkw0OEVpMjI2cnRBcWoySGQxcTRua1Fwb0ZWQ1B3aXJGUmtub05Zc2NGV1dxN1JEVGVMcmlKcENrUVVFblh4WVBpU1F5S0RxbVpFN0FRVjI=" + } + }); + let mut attach: Attachment = serde_json::from_value(json)?; + let signer = Key::from_fingerprint("z6MkpNusbzt7HSBwrBiRpZmbyLiBEsNGs2fotoYhykU8Muaz")?; + + // should verify with correct signer + assert!(jws_verify_attachment(&attach, &signer, wallet).await?); + + // should not verify with wrong signer + let wrong_signer = + Key::from_fingerprint("z6Mkva1JM9mM3SMuLCtVDAXzAQTwkdtfzHXSYMKtfXK2cPye")?; + assert!(!jws_verify_attachment(&attach, &wrong_signer, wallet).await?); + + // should not verify if wrong signature + attach.data.content = AttachmentType::Base64(String::from("d3JvbmcgZGF0YQ==")); + assert!(!jws_verify_attachment(&attach, &signer, wallet).await?); + + Ok(()) + } +}