diff --git a/agents/rust/aries-vcx-agent/src/services/holder.rs b/agents/rust/aries-vcx-agent/src/services/holder.rs index 157d361203..85f7e9eb7d 100644 --- a/agents/rust/aries-vcx-agent/src/services/holder.rs +++ b/agents/rust/aries-vcx-agent/src/services/holder.rs @@ -4,9 +4,9 @@ use aries_vcx::{ core::profile::profile::Profile, handlers::issuance::holder::Holder, messages::{ - msg_fields::protocols::cred_issuance::{ - issue_credential::IssueCredential, offer_credential::OfferCredential, - propose_credential::ProposeCredential, + msg_fields::protocols::cred_issuance::v1::{ + issue_credential::IssueCredentialV1, offer_credential::OfferCredentialV1, + propose_credential::ProposeCredentialV1, }, AriesMessage, }, @@ -63,7 +63,7 @@ impl ServiceCredentialsHolder { pub async fn send_credential_proposal( &self, connection_id: &str, - propose_credential: ProposeCredential, + propose_credential: ProposeCredentialV1, ) -> AgentResult { let connection = self.service_connections.get_by_id(connection_id)?; let wallet = self.profile.inject_wallet(); @@ -83,7 +83,7 @@ impl ServiceCredentialsHolder { pub fn create_from_offer( &self, connection_id: &str, - offer: OfferCredential, + offer: OfferCredentialV1, ) -> AgentResult { self.service_connections.get_by_id(connection_id)?; let holder = Holder::create_from_offer("", offer)?; @@ -128,7 +128,7 @@ impl ServiceCredentialsHolder { pub async fn process_credential( &self, thread_id: &str, - msg_issue_credential: IssueCredential, + msg_issue_credential: IssueCredentialV1, ) -> AgentResult { let mut holder = self.get_holder(thread_id)?; let connection_id = self.get_connection_id(thread_id)?; diff --git a/agents/rust/aries-vcx-agent/src/services/issuer.rs b/agents/rust/aries-vcx-agent/src/services/issuer.rs index dd94371e83..0449917cf1 100644 --- a/agents/rust/aries-vcx-agent/src/services/issuer.rs +++ b/agents/rust/aries-vcx-agent/src/services/issuer.rs @@ -4,9 +4,9 @@ use aries_vcx::{ core::profile::profile::Profile, handlers::{issuance::issuer::Issuer, util::OfferInfo}, messages::{ - msg_fields::protocols::cred_issuance::{ - ack::AckCredential, propose_credential::ProposeCredential, - request_credential::RequestCredential, + msg_fields::protocols::cred_issuance::v1::{ + ack::AckCredentialV1, propose_credential::ProposeCredentialV1, + request_credential::RequestCredentialV1, }, AriesMessage, }, @@ -63,7 +63,7 @@ impl ServiceCredentialsIssuer { pub async fn accept_proposal( &self, connection_id: &str, - proposal: &ProposeCredential, + proposal: &ProposeCredentialV1, ) -> AgentResult { let issuer = Issuer::create_from_proposal("", proposal)?; self.creds_issuer.insert( @@ -106,7 +106,7 @@ impl ServiceCredentialsIssuer { pub fn process_credential_request( &self, thread_id: &str, - request: RequestCredential, + request: RequestCredentialV1, ) -> AgentResult<()> { let IssuerWrapper { mut issuer, @@ -120,7 +120,7 @@ impl ServiceCredentialsIssuer { Ok(()) } - pub fn process_credential_ack(&self, thread_id: &str, ack: AckCredential) -> AgentResult<()> { + pub fn process_credential_ack(&self, thread_id: &str, ack: AckCredentialV1) -> AgentResult<()> { let IssuerWrapper { mut issuer, connection_id, @@ -180,7 +180,7 @@ impl ServiceCredentialsIssuer { issuer.get_rev_id().map_err(|err| err.into()) } - pub fn get_proposal(&self, thread_id: &str) -> AgentResult { + pub fn get_proposal(&self, thread_id: &str) -> AgentResult { let issuer = self.get_issuer(thread_id)?; issuer.get_proposal().map_err(|err| err.into()) } diff --git a/aries_vcx/src/handlers/issuance/holder.rs b/aries_vcx/src/handlers/issuance/holder.rs index 5e0b3f045d..8d9ff70b0a 100644 --- a/aries_vcx/src/handlers/issuance/holder.rs +++ b/aries_vcx/src/handlers/issuance/holder.rs @@ -9,11 +9,14 @@ use messages::{ decorators::{thread::Thread, timing::Timing}, msg_fields::protocols::{ cred_issuance::{ - ack::{AckCredential, AckCredentialContent}, - issue_credential::IssueCredential, - offer_credential::OfferCredential, - propose_credential::ProposeCredential, - request_credential::RequestCredential, + v1::{ + ack::{AckCredentialV1, AckCredentialV1Content}, + issue_credential::IssueCredentialV1, + offer_credential::OfferCredentialV1, + propose_credential::ProposeCredentialV1, + request_credential::RequestCredentialV1, + CredentialIssuanceV1, + }, CredentialIssuance, }, notification::ack::{AckContent, AckDecorators, AckStatus}, @@ -34,8 +37,8 @@ use crate::{ protocols::issuance::holder::state_machine::{HolderFullState, HolderSM, HolderState}, }; -fn build_credential_ack(thread_id: &str) -> AckCredential { - let content = AckCredentialContent::builder() +fn build_credential_ack(thread_id: &str) -> AckCredentialV1 { + let content = AckCredentialV1Content::builder() .inner(AckContent::builder().status(AckStatus::Ok).build()) .build(); let decorators = AckDecorators::builder() @@ -43,7 +46,7 @@ fn build_credential_ack(thread_id: &str) -> AckCredential { .timing(Timing::builder().out_time(Utc::now()).build()) .build(); - AckCredential::builder() + AckCredentialV1::builder() .id(Uuid::new_v4().to_string()) .content(content) .decorators(decorators) @@ -64,7 +67,7 @@ impl Holder { pub fn create_with_proposal( source_id: &str, - propose_credential: ProposeCredential, + propose_credential: ProposeCredentialV1, ) -> VcxResult { trace!( "Holder::create_with_proposal >>> source_id: {:?}, propose_credential: {:?}", @@ -77,7 +80,7 @@ impl Holder { pub fn create_from_offer( source_id: &str, - credential_offer: OfferCredential, + credential_offer: OfferCredentialV1, ) -> VcxResult { trace!( "Holder::create_from_offer >>> source_id: {:?}, credential_offer: {:?}", @@ -88,7 +91,7 @@ impl Holder { Ok(Holder { holder_sm }) } - pub fn set_proposal(&mut self, credential_proposal: ProposeCredential) -> VcxResult<()> { + pub fn set_proposal(&mut self, credential_proposal: ProposeCredentialV1) -> VcxResult<()> { self.holder_sm = self.holder_sm.clone().set_proposal(credential_proposal)?; Ok(()) } @@ -115,10 +118,10 @@ impl Holder { } } - pub fn get_msg_credential_request(&self) -> VcxResult { + pub fn get_msg_credential_request(&self) -> VcxResult { match self.holder_sm.state { HolderFullState::RequestSet(ref state) => { - let mut msg: RequestCredential = state.msg_credential_request.clone(); + let mut msg: RequestCredentialV1 = state.msg_credential_request.clone(); let timing = Timing::builder().out_time(Utc::now()).build(); msg.decorators.timing = Some(timing); Ok(msg) @@ -142,7 +145,7 @@ impl Holder { &mut self, ledger: &Arc, anoncreds: &Arc, - credential: IssueCredential, + credential: IssueCredentialV1, ) -> VcxResult<()> { self.holder_sm = self .holder_sm @@ -176,7 +179,7 @@ impl Holder { self.holder_sm.get_attachment() } - pub fn get_offer(&self) -> VcxResult { + pub fn get_offer(&self) -> VcxResult { self.holder_sm.get_offer() } @@ -261,10 +264,12 @@ impl Holder { message: AriesMessage, ) -> VcxResult<()> { let holder_sm = match message { - AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(offer)) => { - self.holder_sm.clone().receive_offer(offer)? - } - AriesMessage::CredentialIssuance(CredentialIssuance::IssueCredential(credential)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(offer), + )) => self.holder_sm.clone().receive_offer(offer)?, + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::IssueCredential(credential), + )) => { self.holder_sm .clone() .receive_credential(ledger, anoncreds, credential) diff --git a/aries_vcx/src/handlers/issuance/issuer.rs b/aries_vcx/src/handlers/issuance/issuer.rs index 3b7eb78208..fa73b0a9c2 100644 --- a/aries_vcx/src/handlers/issuance/issuer.rs +++ b/aries_vcx/src/handlers/issuance/issuer.rs @@ -7,10 +7,13 @@ use messages::{ misc::MimeType, msg_fields::protocols::{ cred_issuance::{ - ack::AckCredential, issue_credential::IssueCredential, - offer_credential::OfferCredential, propose_credential::ProposeCredential, - request_credential::RequestCredential, CredentialAttr, CredentialIssuance, - CredentialPreview, + common::CredentialAttr, + v1::{ + ack::AckCredentialV1, issue_credential::IssueCredentialV1, + offer_credential::OfferCredentialV1, propose_credential::ProposeCredentialV1, + request_credential::RequestCredentialV1, CredentialIssuanceV1, CredentialPreviewV1, + }, + CredentialIssuance, }, notification::Notification, report_problem::ProblemReport, @@ -36,7 +39,7 @@ pub struct IssuerConfig { pub tails_file: Option, } -fn _build_credential_preview(credential_json: &str) -> VcxResult { +fn _build_credential_preview(credential_json: &str) -> VcxResult { trace!( "Issuer::_build_credential_preview >>> credential_json: {:?}", secret!(credential_json) @@ -115,7 +118,7 @@ fn _build_credential_preview(credential_json: &str) -> VcxResult {} }; - Ok(CredentialPreview::new(attributes)) + Ok(CredentialPreviewV1::new(attributes)) } impl Issuer { @@ -127,7 +130,7 @@ impl Issuer { pub fn create_from_proposal( source_id: &str, - credential_proposal: &ProposeCredential, + credential_proposal: &ProposeCredentialV1, ) -> VcxResult { trace!( "Issuer::create_from_proposal >>> source_id: {:?}, credential_proposal: {:?}", @@ -159,7 +162,7 @@ impl Issuer { Ok(()) } - pub fn get_credential_offer(&self) -> VcxResult { + pub fn get_credential_offer(&self) -> VcxResult { self.issuer_sm.get_credential_offer_msg() } @@ -168,12 +171,12 @@ impl Issuer { Ok(offer.into()) } - pub fn process_credential_request(&mut self, request: RequestCredential) -> VcxResult<()> { + pub fn process_credential_request(&mut self, request: RequestCredentialV1) -> VcxResult<()> { self.issuer_sm = self.issuer_sm.clone().receive_request(request)?; Ok(()) } - pub fn process_credential_ack(&mut self, ack: AckCredential) -> VcxResult<()> { + pub fn process_credential_ack(&mut self, ack: AckCredentialV1) -> VcxResult<()> { self.issuer_sm = self.issuer_sm.clone().receive_ack(ack)?; Ok(()) } @@ -183,7 +186,7 @@ impl Issuer { Ok(()) } - pub fn get_msg_issue_credential(&mut self) -> VcxResult { + pub fn get_msg_issue_credential(&mut self) -> VcxResult { self.issuer_sm.clone().get_msg_issue_credential() } @@ -253,7 +256,7 @@ impl Issuer { self.issuer_sm.thread_id() } - pub fn get_proposal(&self) -> VcxResult { + pub fn get_proposal(&self) -> VcxResult { self.issuer_sm.get_proposal() } @@ -269,17 +272,17 @@ impl Issuer { self.issuer_sm.is_revoked(ledger).await } - pub async fn receive_proposal(&mut self, proposal: ProposeCredential) -> VcxResult<()> { + pub async fn receive_proposal(&mut self, proposal: ProposeCredentialV1) -> VcxResult<()> { self.issuer_sm = self.issuer_sm.clone().receive_proposal(proposal)?; Ok(()) } - pub async fn receive_request(&mut self, request: RequestCredential) -> VcxResult<()> { + pub async fn receive_request(&mut self, request: RequestCredentialV1) -> VcxResult<()> { self.issuer_sm = self.issuer_sm.clone().receive_request(request)?; Ok(()) } - pub async fn receive_ack(&mut self, ack: AckCredential) -> VcxResult<()> { + pub async fn receive_ack(&mut self, ack: AckCredentialV1) -> VcxResult<()> { self.issuer_sm = self.issuer_sm.clone().receive_ack(ack)?; Ok(()) } @@ -299,15 +302,15 @@ impl Issuer { // todo: will ultimately end up in generic SM layer pub async fn process_aries_msg(&mut self, msg: AriesMessage) -> VcxResult<()> { let issuer_sm = match msg { - AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential(proposal)) => { - self.issuer_sm.clone().receive_proposal(proposal)? - } - AriesMessage::CredentialIssuance(CredentialIssuance::RequestCredential(request)) => { - self.issuer_sm.clone().receive_request(request)? - } - AriesMessage::CredentialIssuance(CredentialIssuance::Ack(ack)) => { - self.issuer_sm.clone().receive_ack(ack)? - } + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(proposal), + )) => self.issuer_sm.clone().receive_proposal(proposal)?, + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::RequestCredential(request), + )) => self.issuer_sm.clone().receive_request(request)?, + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::Ack(ack), + )) => self.issuer_sm.clone().receive_ack(ack)?, AriesMessage::ReportProblem(report) => { self.issuer_sm.clone().receive_problem_report(report)? } @@ -315,7 +318,9 @@ impl Issuer { .issuer_sm .clone() .receive_problem_report(report.into())?, - AriesMessage::CredentialIssuance(CredentialIssuance::ProblemReport(report)) => self + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProblemReport(report), + )) => self .issuer_sm .clone() .receive_problem_report(report.into())?, diff --git a/aries_vcx/src/handlers/issuance/mediated_holder.rs b/aries_vcx/src/handlers/issuance/mediated_holder.rs index c1cc8cd025..0b27b296b7 100644 --- a/aries_vcx/src/handlers/issuance/mediated_holder.rs +++ b/aries_vcx/src/handlers/issuance/mediated_holder.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; use messages::{ - msg_fields::protocols::{cred_issuance::CredentialIssuance, notification::Notification}, + msg_fields::protocols::{ + cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, + notification::Notification, + }, AriesMessage, }; @@ -22,8 +25,8 @@ pub fn holder_find_message_to_handle( for (uid, message) in messages { match sm.get_state() { HolderState::ProposalSet => { - if let AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential( - offer, + if let AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(offer), )) = &message { if matches_opt_thread_id!(offer, sm.get_thread_id().unwrap().as_str()) { @@ -32,15 +35,15 @@ pub fn holder_find_message_to_handle( } } HolderState::RequestSet => match &message { - AriesMessage::CredentialIssuance(CredentialIssuance::IssueCredential( - credential, + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::IssueCredential(credential), )) => { if matches_thread_id!(credential, sm.get_thread_id().unwrap().as_str()) { return Some((uid, message)); } } - AriesMessage::CredentialIssuance(CredentialIssuance::ProblemReport( - problem_report, + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProblemReport(problem_report), )) => { if matches_opt_thread_id!(problem_report, sm.get_thread_id().unwrap().as_str()) { diff --git a/aries_vcx/src/handlers/issuance/mediated_issuer.rs b/aries_vcx/src/handlers/issuance/mediated_issuer.rs index 29c66c8ad0..1b47fa3f59 100644 --- a/aries_vcx/src/handlers/issuance/mediated_issuer.rs +++ b/aries_vcx/src/handlers/issuance/mediated_issuer.rs @@ -1,7 +1,10 @@ use std::collections::HashMap; use messages::{ - msg_fields::protocols::{cred_issuance::CredentialIssuance, notification::Notification}, + msg_fields::protocols::{ + cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, + notification::Notification, + }, AriesMessage, }; @@ -27,8 +30,9 @@ pub fn issuer_find_message_to_handle( for (uid, message) in messages { match sm.get_state() { IssuerState::Initial => { - if let AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential(_)) = - &message + if let AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(_), + )) = &message { info!( "In state IssuerState::OfferSet, found matching message ProposeCredential" @@ -37,7 +41,9 @@ pub fn issuer_find_message_to_handle( } } IssuerState::OfferSet => match &message { - AriesMessage::CredentialIssuance(CredentialIssuance::RequestCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::RequestCredential(msg), + )) => { info!( "In state IssuerState::OfferSet, found potentially matching message \ RequestCredential" @@ -48,7 +54,9 @@ pub fn issuer_find_message_to_handle( return Some((uid, message)); } } - AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(msg), + )) => { info!( "In state IssuerState::OfferSet, found potentially matching message \ ProposeCredential" @@ -66,7 +74,9 @@ pub fn issuer_find_message_to_handle( _ => {} }, IssuerState::CredentialSet => match &message { - AriesMessage::CredentialIssuance(CredentialIssuance::Ack(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::Ack(msg), + )) => { info!( "In state IssuerState::CredentialSet, found matching message \ CredentialIssuance::Ack" diff --git a/aries_vcx/src/handlers/out_of_band/receiver.rs b/aries_vcx/src/handlers/out_of_band/receiver.rs index e8205a1c26..2593cec6c5 100644 --- a/aries_vcx/src/handlers/out_of_band/receiver.rs +++ b/aries_vcx/src/handlers/out_of_band/receiver.rs @@ -7,8 +7,11 @@ use messages::{ decorators::{attachment::AttachmentType, thread::Thread}, msg_fields::protocols::{ cred_issuance::{ - issue_credential::IssueCredential, offer_credential::OfferCredential, - request_credential::RequestCredential, CredentialIssuance, + v1::{ + issue_credential::IssueCredentialV1, offer_credential::OfferCredentialV1, + request_credential::RequestCredentialV1, CredentialIssuanceV1, + }, + CredentialIssuance, }, out_of_band::{ invitation::{Invitation, OobService}, @@ -194,7 +197,7 @@ impl OutOfBandReceiver { Some(id) => match id { AttachmentId::CredentialOffer => { let mut offer = - OfferCredential::deserialize(&attach_json).map_err(|_| { + OfferCredentialV1::deserialize(&attach_json).map_err(|_| { AriesVcxError::from_msg( AriesVcxErrorKind::SerializationError, format!("Failed to deserialize attachment: {attach_json:?}"), @@ -212,12 +215,12 @@ impl OutOfBandReceiver { } return Ok(Some(AriesMessage::CredentialIssuance( - CredentialIssuance::OfferCredential(offer), + CredentialIssuance::V1(CredentialIssuanceV1::OfferCredential(offer)), ))); } AttachmentId::CredentialRequest => { let mut request = - RequestCredential::deserialize(&attach_json).map_err(|_| { + RequestCredentialV1::deserialize(&attach_json).map_err(|_| { AriesVcxError::from_msg( AriesVcxErrorKind::SerializationError, format!("Failed to deserialize attachment: {attach_json:?}"), @@ -235,12 +238,14 @@ impl OutOfBandReceiver { } return Ok(Some(AriesMessage::CredentialIssuance( - CredentialIssuance::RequestCredential(request), + CredentialIssuance::V1(CredentialIssuanceV1::RequestCredential( + request, + )), ))); } AttachmentId::Credential => { let mut credential = - IssueCredential::deserialize(&attach_json).map_err(|_| { + IssueCredentialV1::deserialize(&attach_json).map_err(|_| { AriesVcxError::from_msg( AriesVcxErrorKind::SerializationError, format!("Failed to deserialize attachment: {attach_json:?}"), @@ -250,7 +255,9 @@ impl OutOfBandReceiver { credential.decorators.thread.pthid = Some(self.oob.id.clone()); return Ok(Some(AriesMessage::CredentialIssuance( - CredentialIssuance::IssueCredential(credential), + CredentialIssuance::V1(CredentialIssuanceV1::IssueCredential( + credential, + )), ))); } AttachmentId::PresentationRequest => { diff --git a/aries_vcx/src/handlers/out_of_band/sender.rs b/aries_vcx/src/handlers/out_of_band/sender.rs index c48e3fb519..d49fbf0ce3 100644 --- a/aries_vcx/src/handlers/out_of_band/sender.rs +++ b/aries_vcx/src/handlers/out_of_band/sender.rs @@ -1,6 +1,6 @@ use messages::{ msg_fields::protocols::{ - cred_issuance::CredentialIssuance, + cred_issuance::{v1::CredentialIssuanceV1, CredentialIssuance}, out_of_band::{ invitation::{Invitation, InvitationContent, InvitationDecorators, OobService}, OobGoalCode, @@ -94,9 +94,9 @@ impl OutOfBandSender { AttachmentId::PresentationRequest, json!(&a2a_msg).to_string(), ), - a2a_msg @ AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(_)) => { - (AttachmentId::CredentialOffer, json!(&a2a_msg).to_string()) - } + a2a_msg @ AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(_), + )) => (AttachmentId::CredentialOffer, json!(&a2a_msg).to_string()), _ => { error!("Appended message type {:?} is not allowed.", msg); return Err(AriesVcxError::from_msg( diff --git a/aries_vcx/src/handlers/util.rs b/aries_vcx/src/handlers/util.rs index e6009e4605..56d0d5b621 100644 --- a/aries_vcx/src/handlers/util.rs +++ b/aries_vcx/src/handlers/util.rs @@ -1,7 +1,7 @@ use messages::{ msg_fields::protocols::{ connection::{invitation::Invitation, Connection}, - cred_issuance::CredentialIssuance, + cred_issuance::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance}, discover_features::DiscoverFeatures, notification::Notification, out_of_band::{invitation::Invitation as OobInvitation, OutOfBand}, @@ -92,22 +92,64 @@ pub fn verify_thread_id(thread_id: &str, message: &AriesMessage) -> VcxResult<() matches_opt_thread_id!(msg, thread_id) } AriesMessage::Connection(Connection::Response(msg)) => matches_thread_id!(msg, thread_id), - AriesMessage::CredentialIssuance(CredentialIssuance::Ack(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1(CredentialIssuanceV1::Ack( + msg, + ))) => { matches_thread_id!(msg, thread_id) } - AriesMessage::CredentialIssuance(CredentialIssuance::IssueCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::IssueCredential(msg), + )) => { matches_thread_id!(msg, thread_id) } - AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(msg), + )) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(msg), + )) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::CredentialIssuance(CredentialIssuance::RequestCredential(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::RequestCredential(msg), + )) => { matches_opt_thread_id!(msg, thread_id) } - AriesMessage::CredentialIssuance(CredentialIssuance::ProblemReport(msg)) => { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProblemReport(msg), + )) => { + matches_opt_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2(CredentialIssuanceV2::Ack( + msg, + ))) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2( + CredentialIssuanceV2::IssueCredential(msg), + )) => { + matches_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2( + CredentialIssuanceV2::OfferCredential(msg), + )) => { + matches_opt_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2( + CredentialIssuanceV2::ProposeCredential(msg), + )) => { + matches_opt_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2( + CredentialIssuanceV2::RequestCredential(msg), + )) => { + matches_opt_thread_id!(msg, thread_id) + } + AriesMessage::CredentialIssuance(CredentialIssuance::V2( + CredentialIssuanceV2::ProblemReport(msg), + )) => { matches_opt_thread_id!(msg, thread_id) } AriesMessage::DiscoverFeatures(DiscoverFeatures::Query(msg)) => msg.id == thread_id, diff --git a/aries_vcx/src/protocols/issuance/holder/state_machine.rs b/aries_vcx/src/protocols/issuance/holder/state_machine.rs index 5f665e29e1..ca43201503 100644 --- a/aries_vcx/src/protocols/issuance/holder/state_machine.rs +++ b/aries_vcx/src/protocols/issuance/holder/state_machine.rs @@ -8,11 +8,14 @@ use messages::{ decorators::{thread::Thread, timing::Timing}, msg_fields::protocols::{ cred_issuance::{ - issue_credential::IssueCredential, - offer_credential::OfferCredential, - propose_credential::ProposeCredential, - request_credential::{ - RequestCredential, RequestCredentialContent, RequestCredentialDecorators, + v1::{ + issue_credential::IssueCredentialV1, + offer_credential::OfferCredentialV1, + propose_credential::ProposeCredentialV1, + request_credential::{ + RequestCredentialV1, RequestCredentialV1Content, RequestCredentialV1Decorators, + }, + CredentialIssuanceV1, }, CredentialIssuance, }, @@ -80,20 +83,20 @@ impl fmt::Display for HolderFullState { fn _build_credential_request_msg( credential_request_attach: String, thread_id: &str, -) -> RequestCredential { - let content = RequestCredentialContent::builder() +) -> RequestCredentialV1 { + let content = RequestCredentialV1Content::builder() .requests_attach(vec![make_attach_from_str!( &credential_request_attach, AttachmentId::CredentialRequest.as_ref().to_string() )]) .build(); - let decorators = RequestCredentialDecorators::builder() + let decorators = RequestCredentialV1Decorators::builder() .thread(Thread::builder().thid(thread_id.to_owned()).build()) .timing(Timing::builder().out_time(Utc::now()).build()) .build(); - RequestCredential::builder() + RequestCredentialV1::builder() .id(Uuid::new_v4().to_string()) .content(content) .decorators(decorators) @@ -109,7 +112,7 @@ impl HolderSM { } } - pub fn from_offer(offer: OfferCredential, source_id: String) -> Self { + pub fn from_offer(offer: OfferCredentialV1, source_id: String) -> Self { HolderSM { thread_id: offer.id.clone(), state: HolderFullState::OfferReceived(OfferReceivedState::new(offer)), @@ -117,7 +120,7 @@ impl HolderSM { } } - pub fn with_proposal(propose_credential: ProposeCredential, source_id: String) -> Self { + pub fn with_proposal(propose_credential: ProposeCredentialV1, source_id: String) -> Self { HolderSM { thread_id: propose_credential.id.clone(), state: HolderFullState::ProposalSet(ProposalSetState::new(propose_credential)), @@ -143,7 +146,7 @@ impl HolderSM { } #[allow(dead_code)] - pub fn get_proposal(&self) -> VcxResult { + pub fn get_proposal(&self) -> VcxResult { match &self.state { HolderFullState::ProposalSet(state) => Ok(state.credential_proposal.clone()), _ => Err(AriesVcxError::from_msg( @@ -153,12 +156,12 @@ impl HolderSM { } } - pub fn set_proposal(self, proposal: ProposeCredential) -> VcxResult { + pub fn set_proposal(self, proposal: ProposeCredentialV1) -> VcxResult { trace!("HolderSM::set_proposal >>"); verify_thread_id( &self.thread_id, - &AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential( - proposal.clone(), + &AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(proposal.clone()), )), )?; let state = match self.state { @@ -180,11 +183,13 @@ impl HolderSM { Ok(Self { state, ..self }) } - pub fn receive_offer(self, offer: OfferCredential) -> VcxResult { + pub fn receive_offer(self, offer: OfferCredentialV1) -> VcxResult { trace!("HolderSM::receive_offer >>"); verify_thread_id( &self.thread_id, - &AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(offer.clone())), + &AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(offer.clone()), + )), )?; let state = match self.state { HolderFullState::ProposalSet(_) => { @@ -261,7 +266,7 @@ impl HolderSM { self, ledger: &'a Arc, anoncreds: &'a Arc, - credential: IssueCredential, + credential: IssueCredentialV1, ) -> VcxResult { trace!("HolderSM::receive_credential >>"); let state = match self.state { @@ -403,7 +408,7 @@ impl HolderSM { } } - pub fn get_offer(&self) -> VcxResult { + pub fn get_offer(&self) -> VcxResult { match self.state { HolderFullState::OfferReceived(ref state) => Ok(state.offer.clone()), _ => Err(AriesVcxError::from_msg( @@ -529,7 +534,7 @@ fn _parse_rev_reg_id_from_credential(credential: &str) -> VcxResult, anoncreds: &Arc, - credential: &IssueCredential, + credential: &IssueCredentialV1, req_meta: &str, cred_def_json: &str, ) -> VcxResult<(String, Option)> { @@ -585,8 +590,8 @@ async fn build_credential_request_msg( anoncreds: &Arc, thread_id: String, my_pw_did: String, - offer: &OfferCredential, -) -> VcxResult<(RequestCredential, String, String)> { + offer: &OfferCredentialV1, +) -> VcxResult<(RequestCredentialV1, String, String)> { trace!( "Holder::_make_credential_request >>> my_pw_did: {:?}, offer: {:?}", my_pw_did, diff --git a/aries_vcx/src/protocols/issuance/holder/states/finished.rs b/aries_vcx/src/protocols/issuance/holder/states/finished.rs index f93e3e6dfc..55145a94c1 100644 --- a/aries_vcx/src/protocols/issuance/holder/states/finished.rs +++ b/aries_vcx/src/protocols/issuance/holder/states/finished.rs @@ -1,5 +1,5 @@ use messages::msg_fields::protocols::{ - cred_issuance::issue_credential::IssueCredential, report_problem::ProblemReport, + cred_issuance::v1::issue_credential::IssueCredentialV1, report_problem::ProblemReport, }; use crate::{ @@ -10,7 +10,7 @@ use crate::{ #[derive(Serialize, Deserialize, Debug, Clone)] pub struct FinishedHolderState { pub cred_id: Option, - pub credential: Option, + pub credential: Option, pub status: Status, pub rev_reg_def_json: Option, pub ack_requested: Option, diff --git a/aries_vcx/src/protocols/issuance/holder/states/offer_received.rs b/aries_vcx/src/protocols/issuance/holder/states/offer_received.rs index 27a5f9b2de..3adf7af235 100644 --- a/aries_vcx/src/protocols/issuance/holder/states/offer_received.rs +++ b/aries_vcx/src/protocols/issuance/holder/states/offer_received.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use aries_vcx_core::ledger::base_ledger::AnoncredsLedgerRead; -use messages::msg_fields::protocols::cred_issuance::offer_credential::OfferCredential; +use messages::msg_fields::protocols::cred_issuance::v1::offer_credential::OfferCredentialV1; use crate::{ errors::error::prelude::*, @@ -13,11 +13,11 @@ use crate::{ #[derive(Serialize, Deserialize, Debug, Clone)] pub struct OfferReceivedState { - pub offer: OfferCredential, + pub offer: OfferCredentialV1, } impl OfferReceivedState { - pub fn new(offer: OfferCredential) -> Self { + pub fn new(offer: OfferCredentialV1) -> Self { OfferReceivedState { offer } } diff --git a/aries_vcx/src/protocols/issuance/holder/states/proposal_set.rs b/aries_vcx/src/protocols/issuance/holder/states/proposal_set.rs index 7f9ac0489a..f5352bad3b 100644 --- a/aries_vcx/src/protocols/issuance/holder/states/proposal_set.rs +++ b/aries_vcx/src/protocols/issuance/holder/states/proposal_set.rs @@ -1,17 +1,17 @@ use std::sync::Arc; use aries_vcx_core::ledger::base_ledger::AnoncredsLedgerRead; -use messages::msg_fields::protocols::cred_issuance::propose_credential::ProposeCredential; +use messages::msg_fields::protocols::cred_issuance::v1::propose_credential::ProposeCredentialV1; use crate::{errors::error::prelude::*, protocols::issuance::is_cred_def_revokable}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ProposalSetState { - pub credential_proposal: ProposeCredential, + pub credential_proposal: ProposeCredentialV1, } impl ProposalSetState { - pub fn new(credential_proposal: ProposeCredential) -> Self { + pub fn new(credential_proposal: ProposeCredentialV1) -> Self { Self { credential_proposal, } diff --git a/aries_vcx/src/protocols/issuance/holder/states/request_set.rs b/aries_vcx/src/protocols/issuance/holder/states/request_set.rs index 40b6c92cf6..e348378872 100644 --- a/aries_vcx/src/protocols/issuance/holder/states/request_set.rs +++ b/aries_vcx/src/protocols/issuance/holder/states/request_set.rs @@ -1,5 +1,5 @@ -use messages::msg_fields::protocols::cred_issuance::{ - issue_credential::IssueCredential, request_credential::RequestCredential, +use messages::msg_fields::protocols::cred_issuance::v1::{ + issue_credential::IssueCredentialV1, request_credential::RequestCredentialV1, }; use crate::{ @@ -11,15 +11,15 @@ use crate::{ pub struct RequestSetState { pub req_meta: String, pub cred_def_json: String, - pub msg_credential_request: RequestCredential, + pub msg_credential_request: RequestCredentialV1, } -impl From<(RequestSetState, String, IssueCredential, Option)> for FinishedHolderState { +impl From<(RequestSetState, String, IssueCredentialV1, Option)> for FinishedHolderState { fn from( (_, cred_id, credential, rev_reg_def_json): ( RequestSetState, String, - IssueCredential, + IssueCredentialV1, Option, ), ) -> Self { diff --git a/aries_vcx/src/protocols/issuance/issuer/state_machine.rs b/aries_vcx/src/protocols/issuance/issuer/state_machine.rs index 4f984f9024..a2b897203f 100644 --- a/aries_vcx/src/protocols/issuance/issuer/state_machine.rs +++ b/aries_vcx/src/protocols/issuance/issuer/state_machine.rs @@ -8,16 +8,19 @@ use messages::{ decorators::{please_ack::PleaseAck, thread::Thread, timing::Timing}, msg_fields::protocols::{ cred_issuance::{ - ack::AckCredential, - issue_credential::{ - IssueCredential, IssueCredentialContent, IssueCredentialDecorators, + v1::{ + ack::AckCredentialV1, + issue_credential::{ + IssueCredentialV1, IssueCredentialV1Content, IssueCredentialV1Decorators, + }, + offer_credential::{ + OfferCredentialV1, OfferCredentialV1Content, OfferCredentialV1Decorators, + }, + propose_credential::ProposeCredentialV1, + request_credential::RequestCredentialV1, + CredentialIssuanceV1, CredentialPreviewV1, }, - offer_credential::{ - OfferCredential, OfferCredentialContent, OfferCredentialDecorators, - }, - propose_credential::ProposeCredential, - request_credential::RequestCredential, - CredentialIssuance, CredentialPreview, + CredentialIssuance, }, report_problem::ProblemReport, }, @@ -97,22 +100,22 @@ pub struct IssuerSM { pub(crate) state: IssuerFullState, } -fn build_credential_message(libindy_credential: String, thread_id: String) -> IssueCredential { +fn build_credential_message(libindy_credential: String, thread_id: String) -> IssueCredentialV1 { let id = Uuid::new_v4().to_string(); - let content = IssueCredentialContent::builder() + let content = IssueCredentialV1Content::builder() .credentials_attach(vec![make_attach_from_str!( &libindy_credential, AttachmentId::Credential.as_ref().to_string() )]) .build(); - let decorators = IssueCredentialDecorators::builder() + let decorators = IssueCredentialV1Decorators::builder() .thread(Thread::builder().thid(thread_id).build()) .please_ack(PleaseAck::builder().on(vec![]).build()) .build(); - IssueCredential::builder() + IssueCredentialV1::builder() .id(id) .content(content) .decorators(decorators) @@ -122,12 +125,12 @@ fn build_credential_message(libindy_credential: String, thread_id: String) -> Is fn build_credential_offer( thread_id: &str, credential_offer: &str, - credential_preview: CredentialPreview, + credential_preview: CredentialPreviewV1, comment: Option, -) -> VcxResult { +) -> VcxResult { let id = thread_id.to_owned(); - let content = OfferCredentialContent::builder() + let content = OfferCredentialV1Content::builder() .credential_preview(credential_preview) .offers_attach(vec![make_attach_from_str!( &credential_offer, @@ -140,11 +143,11 @@ fn build_credential_offer( content.build() }; - let decorators = OfferCredentialDecorators::builder() + let decorators = OfferCredentialV1Decorators::builder() .timing(Timing::builder().out_time(Utc::now()).build()) .build(); - Ok(OfferCredential::builder() + Ok(OfferCredentialV1::builder() .id(id) .content(content) .decorators(decorators) @@ -160,7 +163,7 @@ impl IssuerSM { } } - pub fn from_proposal(source_id: &str, credential_proposal: &ProposeCredential) -> Self { + pub fn from_proposal(source_id: &str, credential_proposal: &ProposeCredentialV1) -> Self { Self { thread_id: credential_proposal.id.clone(), source_id: source_id.to_string(), @@ -299,7 +302,7 @@ impl IssuerSM { } } - pub fn get_proposal(&self) -> VcxResult { + pub fn get_proposal(&self) -> VcxResult { match &self.state { IssuerFullState::ProposalReceived(state) => Ok(state.credential_proposal.clone()), _ => Err(AriesVcxError::from_msg( @@ -312,7 +315,7 @@ impl IssuerSM { pub fn build_credential_offer_msg( self, credential_offer: &str, - credential_preview: CredentialPreview, + credential_preview: CredentialPreviewV1, comment: Option, offer_info: &OfferInfo, ) -> VcxResult { @@ -350,7 +353,7 @@ impl IssuerSM { Ok(Self::step(source_id, thread_id, state)) } - pub fn get_credential_offer_msg(&self) -> VcxResult { + pub fn get_credential_offer_msg(&self) -> VcxResult { match &self.state { IssuerFullState::OfferSet(state) => Ok(state.offer.clone()), _ => Err(AriesVcxError::from_msg( @@ -363,11 +366,11 @@ impl IssuerSM { } } - pub fn receive_proposal(self, proposal: ProposeCredential) -> VcxResult { + pub fn receive_proposal(self, proposal: ProposeCredentialV1) -> VcxResult { verify_thread_id( &self.thread_id, - &AriesMessage::CredentialIssuance(CredentialIssuance::ProposeCredential( - proposal.clone(), + &AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::ProposeCredential(proposal.clone()), )), )?; let (state, thread_id) = match self.state { @@ -394,11 +397,11 @@ impl IssuerSM { }) } - pub fn receive_request(self, request: RequestCredential) -> VcxResult { + pub fn receive_request(self, request: RequestCredentialV1) -> VcxResult { verify_thread_id( &self.thread_id, - &AriesMessage::CredentialIssuance(CredentialIssuance::RequestCredential( - request.clone(), + &AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::RequestCredential(request.clone()), )), )?; let state = match self.state { @@ -465,10 +468,10 @@ impl IssuerSM { Ok(Self { state, ..self }) } - pub fn get_msg_issue_credential(self) -> VcxResult { + pub fn get_msg_issue_credential(self) -> VcxResult { match self.state { IssuerFullState::CredentialSet(ref state_data) => { - let mut msg_issue_credential: IssueCredential = + let mut msg_issue_credential: IssueCredentialV1 = state_data.msg_issue_credential.clone(); let timing = Timing::builder().out_time(Utc::now()).build(); @@ -482,10 +485,12 @@ impl IssuerSM { } } - pub fn receive_ack(self, ack: AckCredential) -> VcxResult { + pub fn receive_ack(self, ack: AckCredentialV1) -> VcxResult { verify_thread_id( &self.thread_id, - &AriesMessage::CredentialIssuance(CredentialIssuance::Ack(ack.clone())), + &AriesMessage::CredentialIssuance(CredentialIssuance::V1(CredentialIssuanceV1::Ack( + ack.clone(), + ))), )?; let state = match self.state { IssuerFullState::CredentialSet(state_data) => { @@ -556,13 +561,13 @@ impl IssuerSM { async fn create_credential( anoncreds: &Arc, - request: &RequestCredential, + request: &RequestCredentialV1, rev_reg_id: &Option, tails_file: &Option, - offer: &OfferCredential, + offer: &OfferCredentialV1, cred_data: &str, thread_id: String, -) -> VcxResult<(IssueCredential, Option)> { +) -> VcxResult<(IssueCredentialV1, Option)> { let offer = get_attach_as_string!(&offer.content.offers_attach); trace!( diff --git a/aries_vcx/src/protocols/issuance/issuer/states/credential_set.rs b/aries_vcx/src/protocols/issuance/issuer/states/credential_set.rs index c927935090..343d6dea82 100644 --- a/aries_vcx/src/protocols/issuance/issuer/states/credential_set.rs +++ b/aries_vcx/src/protocols/issuance/issuer/states/credential_set.rs @@ -1,4 +1,4 @@ -use messages::msg_fields::protocols::cred_issuance::issue_credential::IssueCredential; +use messages::msg_fields::protocols::cred_issuance::v1::issue_credential::IssueCredentialV1; use crate::{ handlers::util::Status, @@ -10,7 +10,7 @@ use crate::{ #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CredentialSetState { pub revocation_info_v1: Option, - pub msg_issue_credential: IssueCredential, + pub msg_issue_credential: IssueCredentialV1, } impl FinishedState { diff --git a/aries_vcx/src/protocols/issuance/issuer/states/offer_set.rs b/aries_vcx/src/protocols/issuance/issuer/states/offer_set.rs index cc3179638e..7339d1771e 100644 --- a/aries_vcx/src/protocols/issuance/issuer/states/offer_set.rs +++ b/aries_vcx/src/protocols/issuance/issuer/states/offer_set.rs @@ -1,5 +1,7 @@ use messages::msg_fields::protocols::{ - cred_issuance::{offer_credential::OfferCredential, request_credential::RequestCredential}, + cred_issuance::v1::{ + offer_credential::OfferCredentialV1, request_credential::RequestCredentialV1, + }, report_problem::ProblemReport, }; @@ -13,7 +15,7 @@ use crate::{ #[derive(Serialize, Deserialize, Debug, Clone)] pub struct OfferSetState { - pub offer: OfferCredential, + pub offer: OfferCredentialV1, pub credential_json: String, pub cred_def_id: String, pub rev_reg_id: Option, @@ -22,7 +24,7 @@ pub struct OfferSetState { impl OfferSetState { pub fn new( - cred_offer_msg: OfferCredential, + cred_offer_msg: OfferCredentialV1, credential_json: &str, cred_def_id: &str, rev_reg_id: Option, @@ -39,7 +41,7 @@ impl OfferSetState { } impl RequestReceivedState { - pub fn from_offer_set_and_request(state: OfferSetState, request: RequestCredential) -> Self { + pub fn from_offer_set_and_request(state: OfferSetState, request: RequestCredentialV1) -> Self { trace!("SM is now in Request Received state"); RequestReceivedState { offer: state.offer, diff --git a/aries_vcx/src/protocols/issuance/issuer/states/proposal_received.rs b/aries_vcx/src/protocols/issuance/issuer/states/proposal_received.rs index 2ab4ca834b..7e13f75881 100644 --- a/aries_vcx/src/protocols/issuance/issuer/states/proposal_received.rs +++ b/aries_vcx/src/protocols/issuance/issuer/states/proposal_received.rs @@ -1,15 +1,15 @@ -use messages::msg_fields::protocols::cred_issuance::propose_credential::ProposeCredential; +use messages::msg_fields::protocols::cred_issuance::v1::propose_credential::ProposeCredentialV1; use crate::handlers::util::OfferInfo; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct ProposalReceivedState { - pub credential_proposal: ProposeCredential, + pub credential_proposal: ProposeCredentialV1, pub offer_info: Option, } impl ProposalReceivedState { - pub fn new(credential_proposal: ProposeCredential, offer_info: Option) -> Self { + pub fn new(credential_proposal: ProposeCredentialV1, offer_info: Option) -> Self { Self { credential_proposal, offer_info, diff --git a/aries_vcx/src/protocols/issuance/issuer/states/requested_received.rs b/aries_vcx/src/protocols/issuance/issuer/states/requested_received.rs index 1925f4bac5..2c0718fb53 100644 --- a/aries_vcx/src/protocols/issuance/issuer/states/requested_received.rs +++ b/aries_vcx/src/protocols/issuance/issuer/states/requested_received.rs @@ -1,5 +1,7 @@ use messages::msg_fields::protocols::{ - cred_issuance::{offer_credential::OfferCredential, request_credential::RequestCredential}, + cred_issuance::v1::{ + offer_credential::OfferCredentialV1, request_credential::RequestCredentialV1, + }, report_problem::ProblemReport, }; @@ -13,11 +15,11 @@ use crate::{ // TODO: Use OfferInfo instead of ind. fields #[derive(Serialize, Deserialize, Debug, Clone)] pub struct RequestReceivedState { - pub offer: OfferCredential, + pub offer: OfferCredentialV1, pub cred_data: String, pub rev_reg_id: Option, pub tails_file: Option, - pub request: RequestCredential, + pub request: RequestCredentialV1, } impl FinishedState { diff --git a/aries_vcx/src/utils/filters.rs b/aries_vcx/src/utils/filters.rs index 6015b6119f..293ce6f7d1 100644 --- a/aries_vcx/src/utils/filters.rs +++ b/aries_vcx/src/utils/filters.rs @@ -1,7 +1,7 @@ use messages::{ decorators::attachment::Attachment, msg_fields::protocols::{ - cred_issuance::offer_credential::OfferCredential, + cred_issuance::v1::offer_credential::OfferCredentialV1, present_proof::request::RequestPresentation, }, }; @@ -52,16 +52,20 @@ fn _filter_proof_requests_by_name( Ok(filtered) } -fn _filter_offers_by_comment(offers: &str, match_comment: &str) -> VcxResult> { - let credential_offers: Vec = serde_json::from_str(offers).map_err(|err| { - AriesVcxError::from_msg( - AriesVcxErrorKind::InvalidJson, - format!( - "Failed to deserialize Vec: {}\nObtained error: {:?}", - offers, err - ), - ) - })?; +fn _filter_offers_by_comment( + offers: &str, + match_comment: &str, +) -> VcxResult> { + let credential_offers: Vec = + serde_json::from_str(offers).map_err(|err| { + AriesVcxError::from_msg( + AriesVcxErrorKind::InvalidJson, + format!( + "Failed to deserialize Vec: {}\nObtained error: {:?}", + offers, err + ), + ) + })?; let filtered = credential_offers .into_iter() .filter_map(|credential_offer| match &credential_offer.content.comment { @@ -90,7 +94,7 @@ pub fn filter_proof_requests_by_name(requests: &str, name: &str) -> VcxResult VcxResult { - let credential_offers: Vec = _filter_offers_by_comment(offers, comment)?; + let credential_offers: Vec = _filter_offers_by_comment(offers, comment)?; let filtered: String = serde_json::to_string(&credential_offers).map_err(|err| { AriesVcxError::from_msg( AriesVcxErrorKind::InvalidJson, diff --git a/aries_vcx/tests/utils/scenarios/credential_issuance.rs b/aries_vcx/tests/utils/scenarios/credential_issuance.rs index 06f6a8c031..403ea141a0 100644 --- a/aries_vcx/tests/utils/scenarios/credential_issuance.rs +++ b/aries_vcx/tests/utils/scenarios/credential_issuance.rs @@ -23,9 +23,9 @@ use aries_vcx::{ utils::constants::TEST_TAILS_URL, }; use messages::msg_fields::protocols::{ - cred_issuance::{ - offer_credential::OfferCredential, propose_credential::ProposeCredential, - request_credential::RequestCredential, + cred_issuance::v1::{ + offer_credential::OfferCredentialV1, propose_credential::ProposeCredentialV1, + request_credential::RequestCredentialV1, }, report_problem::ProblemReport, }; @@ -70,13 +70,13 @@ pub async fn create_address_schema_creddef_revreg( (schema, cred_def, rev_reg) } -pub fn create_holder_from_proposal(proposal: ProposeCredential) -> Holder { +pub fn create_holder_from_proposal(proposal: ProposeCredentialV1) -> Holder { let holder = Holder::create_with_proposal("TEST_CREDENTIAL", proposal).unwrap(); assert_eq!(HolderState::ProposalSet, holder.get_state()); holder } -pub fn create_issuer_from_proposal(proposal: ProposeCredential) -> Issuer { +pub fn create_issuer_from_proposal(proposal: ProposeCredentialV1) -> Issuer { let issuer = Issuer::create_from_proposal("TEST_CREDENTIAL", &proposal).unwrap(); assert_eq!(IssuerState::ProposalReceived, issuer.get_state()); assert_eq!(proposal.clone(), issuer.get_proposal().unwrap()); @@ -86,10 +86,10 @@ pub fn create_issuer_from_proposal(proposal: ProposeCredential) -> Issuer { pub async fn accept_credential_proposal( faber: &mut TestAgent, issuer: &mut Issuer, - cred_proposal: ProposeCredential, + cred_proposal: ProposeCredentialV1, rev_reg_id: Option, tails_dir: Option, -) -> OfferCredential { +) -> OfferCredentialV1 { let offer_info = OfferInfo { credential_json: json!(cred_proposal.content.credential_proposal.attributes).to_string(), cred_def_id: cred_proposal.content.cred_def_id.clone(), @@ -109,9 +109,9 @@ pub async fn accept_credential_proposal( pub async fn accept_offer( alice: &mut TestAgent, - cred_offer: OfferCredential, + cred_offer: OfferCredentialV1, holder: &mut Holder, -) -> RequestCredential { +) -> RequestCredentialV1 { // TODO: Replace with message-specific handler holder .process_aries_msg( @@ -140,7 +140,7 @@ pub async fn accept_offer( pub async fn decline_offer( alice: &mut TestAgent, - cred_offer: OfferCredential, + cred_offer: OfferCredentialV1, holder: &mut Holder, ) -> ProblemReport { // TODO: Replace with message-specific handler @@ -163,7 +163,7 @@ pub async fn send_credential( faber: &mut TestAgent, issuer_credential: &mut Issuer, holder_credential: &mut Holder, - cred_request: RequestCredential, + cred_request: RequestCredentialV1, revokable: bool, ) { let thread_id = issuer_credential.get_thread_id().unwrap(); @@ -329,7 +329,7 @@ async fn create_credential_offer( issuer } -async fn create_credential_request(alice: &mut TestAgent, cred_offer: OfferCredential) -> Holder { +async fn create_credential_request(alice: &mut TestAgent, cred_offer: OfferCredentialV1) -> Holder { let mut holder = Holder::create_from_offer("TEST_CREDENTIAL", cred_offer).unwrap(); assert_eq!(HolderState::OfferReceived, holder.get_state()); holder diff --git a/aries_vcx/tests/utils/scenarios/data.rs b/aries_vcx/tests/utils/scenarios/data.rs index f3740bddf1..4dbd7a049c 100644 --- a/aries_vcx/tests/utils/scenarios/data.rs +++ b/aries_vcx/tests/utils/scenarios/data.rs @@ -2,8 +2,11 @@ use messages::{ misc::MimeType, msg_fields::protocols::{ cred_issuance::{ - propose_credential::{ProposeCredential, ProposeCredentialContent}, - CredentialAttr, CredentialPreview, + common::CredentialAttr, + v1::{ + propose_credential::{ProposeCredentialV1, ProposeCredentialV1Content}, + CredentialPreviewV1, + }, }, present_proof::propose::PresentationAttr, }, @@ -66,7 +69,7 @@ pub fn create_credential_proposal( schema_id: &str, cred_def_id: &str, comment: &str, -) -> ProposeCredential { +) -> ProposeCredentialV1 { let attrs = credential_data_address_1() .as_object() .unwrap() @@ -79,13 +82,13 @@ pub fn create_credential_proposal( .build() }) .collect(); - let content = ProposeCredentialContent::builder() - .credential_proposal(CredentialPreview::new(attrs)) + let content = ProposeCredentialV1Content::builder() + .credential_proposal(CredentialPreviewV1::new(attrs)) .schema_id(schema_id.to_owned()) .cred_def_id(cred_def_id.to_owned()) .comment(comment.to_owned()) .build(); - ProposeCredential::builder() + ProposeCredentialV1::builder() .id("test".to_owned()) .content(content) .build() diff --git a/libvcx_core/src/api_vcx/api_handle/credential.rs b/libvcx_core/src/api_vcx/api_handle/credential.rs index d4530a098c..fca70c9cb8 100644 --- a/libvcx_core/src/api_vcx/api_handle/credential.rs +++ b/libvcx_core/src/api_vcx/api_handle/credential.rs @@ -4,7 +4,8 @@ use aries_vcx::{ handlers::issuance::{holder::Holder, mediated_holder::holder_find_message_to_handle}, messages::{ msg_fields::protocols::cred_issuance::{ - offer_credential::OfferCredential, CredentialIssuance, + v1::{offer_credential::OfferCredentialV1, CredentialIssuanceV1}, + CredentialIssuance, }, AriesMessage, }, @@ -62,7 +63,7 @@ fn create_credential(source_id: &str, offer: &str) -> LibvcxResult offer, }; - if let Ok(cred_offer) = serde_json::from_value::(offer_message) { + if let Ok(cred_offer) = serde_json::from_value::(offer_message) { return Ok(Some(Holder::create_from_offer(source_id, cred_offer)?)); } @@ -77,7 +78,7 @@ pub fn credential_create_with_offer(source_id: &str, offer: &str) -> LibvcxResul secret!(&offer) ); - let cred_offer: OfferCredential = serde_json::from_str(offer).map_err(|err| { + let cred_offer: OfferCredentialV1 = serde_json::from_str(offer).map_err(|err| { LibvcxError::from_msg( LibvcxErrorKind::InvalidJson, format!( @@ -285,20 +286,21 @@ async fn get_credential_offer_msg(connection_handle: u32, msg_id: &str) -> Libvc AgencyMockDecrypted::set_next_decrypted_response(GET_MESSAGES_DECRYPTED_RESPONSE); AgencyMockDecrypted::set_next_decrypted_message(ARIES_CREDENTIAL_OFFER); } - let credential_offer = match mediated_connection::get_message_by_id(connection_handle, msg_id) - .await - { - Ok(message) => match message { - AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(_)) => Ok(message), - msg => { - return Err(LibvcxError::from_msg( - LibvcxErrorKind::InvalidMessages, - format!("Message of different type was received: {:?}", msg), - )); - } - }, - Err(err) => Err(err), - }?; + let credential_offer = + match mediated_connection::get_message_by_id(connection_handle, msg_id).await { + Ok(message) => match message { + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(_), + )) => Ok(message), + msg => { + return Err(LibvcxError::from_msg( + LibvcxErrorKind::InvalidMessages, + format!("Message of different type was received: {:?}", msg), + )); + } + }, + Err(err) => Err(err), + }?; serde_json::to_string(&credential_offer).map_err(|err| { LibvcxError::from_msg( @@ -323,9 +325,9 @@ pub async fn get_credential_offer_messages_with_conn_handle( .await? .into_iter() .filter_map(|(_, a2a_message)| match a2a_message { - AriesMessage::CredentialIssuance(CredentialIssuance::OfferCredential(_)) => { - Some(a2a_message) - } + AriesMessage::CredentialIssuance(CredentialIssuance::V1( + CredentialIssuanceV1::OfferCredential(_), + )) => Some(a2a_message), _ => None, }) .collect(); @@ -413,7 +415,7 @@ pub mod tests_utils { #[allow(clippy::unwrap_used)] pub mod tests { use aries_vcx::{ - messages::msg_fields::protocols::cred_issuance::issue_credential::IssueCredential, + messages::msg_fields::protocols::cred_issuance::v1::issue_credential::IssueCredentialV1, protocols::issuance::holder::state_machine::HolderState, utils::{ devsetup::{SetupDefaults, SetupMocks}, @@ -574,7 +576,7 @@ pub mod tests { "full_credential_test:: going to deserialize credential: {:?}", msg_value ); - let _credential_struct: IssueCredential = + let _credential_struct: IssueCredentialV1 = serde_json::from_str(msg_value.to_string().as_str()).unwrap(); info!("full_credential_test:: going get offered attributes from final state"); @@ -619,7 +621,7 @@ pub mod tests { .unwrap(); let o: serde_json::Value = serde_json::from_str(&offer).unwrap(); debug!("Serialized credential offer: {:?}", &o[0]); - let _credential_offer: OfferCredential = serde_json::from_str(&o[0].to_string()).unwrap(); + let _credential_offer: OfferCredentialV1 = serde_json::from_str(&o[0].to_string()).unwrap(); } #[tokio::test] @@ -629,7 +631,7 @@ pub mod tests { let handle = from_string(CREDENTIAL_SM_FINISHED).unwrap(); let cred_string: String = get_credential(handle).unwrap(); let cred_value: serde_json::Value = serde_json::from_str(&cred_string).unwrap(); - let _credential_struct: IssueCredential = + let _credential_struct: IssueCredentialV1 = serde_json::from_str(cred_value.to_string().as_str()).unwrap(); } } diff --git a/messages/src/lib.rs b/messages/src/lib.rs index 828cafa2de..6ac2d5d9f9 100644 --- a/messages/src/lib.rs +++ b/messages/src/lib.rs @@ -15,13 +15,19 @@ pub mod msg_types; use derive_more::From; use misc::utils; -use msg_types::{report_problem::ReportProblemTypeV1_0, routing::RoutingTypeV1_0, MsgWithType}; +use msg_fields::protocols::cred_issuance::{ + v1::CredentialIssuanceV1, v2::CredentialIssuanceV2, CredentialIssuance, +}; +use msg_types::{ + cred_issuance::CredentialIssuanceType, report_problem::ReportProblemTypeV1_0, + routing::RoutingTypeV1_0, MsgWithType, +}; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use crate::{ msg_fields::{ protocols::{ - basic_message::BasicMessage, connection::Connection, cred_issuance::CredentialIssuance, + basic_message::BasicMessage, connection::Connection, discover_features::DiscoverFeatures, notification::Notification, out_of_band::OutOfBand, present_proof::PresentProof, report_problem::ProblemReport, revocation::Revocation, routing::Forward, trust_ping::TrustPing, @@ -100,9 +106,19 @@ impl DelayedSerde for AriesMessage { Protocol::RevocationType(msg_type) => { Revocation::delayed_deserialize((msg_type, kind_str), deserializer).map(From::from) } - Protocol::CredentialIssuanceType(msg_type) => { - CredentialIssuance::delayed_deserialize((msg_type, kind_str), deserializer) - .map(From::from) + Protocol::CredentialIssuanceType(CredentialIssuanceType::V1(msg_type)) => { + CredentialIssuanceV1::delayed_deserialize( + (CredentialIssuanceType::V1(msg_type), kind_str), + deserializer, + ) + .map(|x| AriesMessage::from(CredentialIssuance::V1(x))) + } + Protocol::CredentialIssuanceType(CredentialIssuanceType::V2(msg_type)) => { + CredentialIssuanceV2::delayed_deserialize( + (CredentialIssuanceType::V2(msg_type), kind_str), + deserializer, + ) + .map(|x| AriesMessage::from(CredentialIssuance::V2(x))) } Protocol::ReportProblemType(msg_type) => { let kind = match msg_type { @@ -159,7 +175,8 @@ impl DelayedSerde for AriesMessage { Self::Routing(v) => MsgWithType::from(v).serialize(serializer), Self::Connection(v) => v.delayed_serialize(serializer), Self::Revocation(v) => v.delayed_serialize(serializer), - Self::CredentialIssuance(v) => v.delayed_serialize(serializer), + Self::CredentialIssuance(CredentialIssuance::V1(v)) => v.delayed_serialize(serializer), + Self::CredentialIssuance(CredentialIssuance::V2(v)) => v.delayed_serialize(serializer), Self::ReportProblem(v) => MsgWithType::from(v).serialize(serializer), Self::PresentProof(v) => v.delayed_serialize(serializer), Self::TrustPing(v) => v.delayed_serialize(serializer), diff --git a/messages/src/msg_fields/protocols/cred_issuance/common/mod.rs b/messages/src/msg_fields/protocols/cred_issuance/common/mod.rs new file mode 100644 index 0000000000..d2feabd431 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/common/mod.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::misc::MimeType; + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, TypedBuilder)] +#[serde(rename_all = "kebab-case")] +pub struct CredentialAttr { + pub name: String, + pub value: String, + #[builder(default, setter(strip_option))] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "mime-type")] + pub mime_type: Option, +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/mod.rs b/messages/src/msg_fields/protocols/cred_issuance/mod.rs index 9e1bf997c6..1ff283a530 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/mod.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/mod.rs @@ -1,218 +1,13 @@ -//! Module containing the `issue credential` protocol messages, as defined in the [RFC](). - -pub mod ack; -pub mod issue_credential; -pub mod offer_credential; -pub mod problem_report; -pub mod propose_credential; -pub mod request_credential; - -use std::str::FromStr; - use derive_more::From; -use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; -use shared_vcx::misc::utils::CowStr; -use typed_builder::TypedBuilder; -use self::{ - ack::{AckCredential, AckCredentialContent}, - issue_credential::{IssueCredential, IssueCredentialContent, IssueCredentialDecorators}, - offer_credential::{OfferCredential, OfferCredentialContent, OfferCredentialDecorators}, - problem_report::{CredIssuanceProblemReport, CredIssuanceProblemReportContent}, - propose_credential::{ - ProposeCredential, ProposeCredentialContent, ProposeCredentialDecorators, - }, - request_credential::{ - RequestCredential, RequestCredentialContent, RequestCredentialDecorators, - }, -}; -use super::{notification::ack::AckDecorators, report_problem::ProblemReportDecorators}; -use crate::{ - misc::{ - utils::{self, into_msg_with_type, transit_to_aries_msg}, - MimeType, - }, - msg_fields::traits::DelayedSerde, - msg_types::{ - protocols::cred_issuance::{ - CredentialIssuanceType as CredentialIssuanceKind, CredentialIssuanceTypeV1, - CredentialIssuanceTypeV1_0, - }, - traits::MessageKind, - MessageType, MsgWithType, Protocol, - }, -}; +use self::{v1::CredentialIssuanceV1, v2::CredentialIssuanceV2}; + +pub mod common; +pub mod v1; +pub mod v2; #[derive(Clone, Debug, From, PartialEq)] pub enum CredentialIssuance { - OfferCredential(OfferCredential), - ProposeCredential(ProposeCredential), - RequestCredential(RequestCredential), - IssueCredential(IssueCredential), - Ack(AckCredential), - ProblemReport(CredIssuanceProblemReport), -} - -impl DelayedSerde for CredentialIssuance { - type MsgType<'a> = (CredentialIssuanceKind, &'a str); - - fn delayed_deserialize<'de, D>( - msg_type: Self::MsgType<'de>, - deserializer: D, - ) -> Result - where - D: Deserializer<'de>, - { - let (protocol, kind_str) = msg_type; - let kind = match protocol { - CredentialIssuanceKind::V1(CredentialIssuanceTypeV1::V1_0(kind)) => { - kind.kind_from_str(kind_str) - } - }; - - match kind.map_err(D::Error::custom)? { - CredentialIssuanceTypeV1_0::OfferCredential => { - OfferCredential::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::ProposeCredential => { - ProposeCredential::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::RequestCredential => { - RequestCredential::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::IssueCredential => { - IssueCredential::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::Ack => { - AckCredential::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::ProblemReport => { - CredIssuanceProblemReport::deserialize(deserializer).map(From::from) - } - CredentialIssuanceTypeV1_0::CredentialPreview => { - Err(utils::not_standalone_msg::(kind_str)) - } - } - } - - fn delayed_serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Self::OfferCredential(v) => MsgWithType::from(v).serialize(serializer), - Self::ProposeCredential(v) => MsgWithType::from(v).serialize(serializer), - Self::RequestCredential(v) => MsgWithType::from(v).serialize(serializer), - Self::IssueCredential(v) => MsgWithType::from(v).serialize(serializer), - Self::Ack(v) => MsgWithType::from(v).serialize(serializer), - Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), - } - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub struct CredentialPreview { - #[serde(rename = "@type")] - msg_type: CredentialPreviewMsgType, - pub attributes: Vec, + V1(CredentialIssuanceV1), + V2(CredentialIssuanceV2), } - -impl CredentialPreview { - pub fn new(attributes: Vec) -> Self { - Self { - msg_type: CredentialPreviewMsgType, - attributes, - } - } -} - -/// Non-standalone message type. -/// This is only encountered as part of an existent message. -/// It is not a message on it's own. -#[derive(Copy, Clone, Debug, Default, Deserialize, PartialEq)] -#[serde(try_from = "CowStr")] -struct CredentialPreviewMsgType; - -impl<'a> From<&'a CredentialPreviewMsgType> for CredentialIssuanceTypeV1_0 { - fn from(_value: &'a CredentialPreviewMsgType) -> Self { - CredentialIssuanceTypeV1_0::CredentialPreview - } -} - -impl<'a> TryFrom> for CredentialPreviewMsgType { - type Error = String; - - fn try_from(value: CowStr) -> Result { - let value = MessageType::try_from(value.0.as_ref())?; - - if let Protocol::CredentialIssuanceType(CredentialIssuanceKind::V1( - CredentialIssuanceTypeV1::V1_0(_), - )) = value.protocol - { - if let Ok(CredentialIssuanceTypeV1_0::CredentialPreview) = - CredentialIssuanceTypeV1_0::from_str(value.kind) - { - return Ok(CredentialPreviewMsgType); - } - } - - Err(format!("message kind is not {}", value.kind)) - } -} - -impl Serialize for CredentialPreviewMsgType { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - let protocol = Protocol::from(CredentialIssuanceTypeV1_0::parent()); - let kind = CredentialIssuanceTypeV1_0::from(self); - format_args!("{protocol}/{}", kind.as_ref()).serialize(serializer) - } -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, TypedBuilder)] -#[serde(rename_all = "kebab-case")] -pub struct CredentialAttr { - pub name: String, - pub value: String, - #[builder(default, setter(strip_option))] - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(rename = "mime-type")] - pub mime_type: Option, -} - -transit_to_aries_msg!(OfferCredentialContent: OfferCredentialDecorators, CredentialIssuance); -transit_to_aries_msg!( - ProposeCredentialContent: ProposeCredentialDecorators, - CredentialIssuance -); -transit_to_aries_msg!( - RequestCredentialContent: RequestCredentialDecorators, - CredentialIssuance -); -transit_to_aries_msg!(IssueCredentialContent: IssueCredentialDecorators, CredentialIssuance); -transit_to_aries_msg!(AckCredentialContent: AckDecorators, CredentialIssuance); -transit_to_aries_msg!( - CredIssuanceProblemReportContent: ProblemReportDecorators, - CredentialIssuance -); - -into_msg_with_type!(OfferCredential, CredentialIssuanceTypeV1_0, OfferCredential); -into_msg_with_type!( - ProposeCredential, - CredentialIssuanceTypeV1_0, - ProposeCredential -); -into_msg_with_type!( - RequestCredential, - CredentialIssuanceTypeV1_0, - RequestCredential -); -into_msg_with_type!(IssueCredential, CredentialIssuanceTypeV1_0, IssueCredential); -into_msg_with_type!(AckCredential, CredentialIssuanceTypeV1_0, Ack); -into_msg_with_type!( - CredIssuanceProblemReport, - CredentialIssuanceTypeV1_0, - ProblemReport -); diff --git a/messages/src/msg_fields/protocols/cred_issuance/ack.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/ack.rs similarity index 81% rename from messages/src/msg_fields/protocols/cred_issuance/ack.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/ack.rs index b824f8eaf6..cfd04c1698 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/ack.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/ack.rs @@ -6,22 +6,22 @@ use crate::{ msg_parts::MsgParts, }; -pub type AckCredential = MsgParts; +pub type AckCredentialV1 = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] #[serde(transparent)] -pub struct AckCredentialContent { +pub struct AckCredentialV1Content { pub inner: AckContent, } -impl From for AckCredentialContent { +impl From for AckCredentialV1Content { fn from(value: AckContent) -> Self { Self { inner: value } } } -impl From for Ack { - fn from(value: AckCredential) -> Self { +impl From for Ack { + fn from(value: AckCredentialV1) -> Self { Self::builder() .id(value.id) .content(value.content.inner) @@ -46,7 +46,7 @@ mod tests { #[test] fn test_minimal_ack_cred() { - let content: AckCredentialContent = AckContent::builder().status(AckStatus::Ok).build(); + let content: AckCredentialV1Content = AckContent::builder().status(AckStatus::Ok).build(); let decorators = AckDecorators::builder() .thread(make_extended_thread()) @@ -67,7 +67,7 @@ mod tests { #[test] fn test_extended_ack_cred() { - let content: AckCredentialContent = AckContent::builder().status(AckStatus::Ok).build(); + let content: AckCredentialV1Content = AckContent::builder().status(AckStatus::Ok).build(); let decorators = AckDecorators::builder() .thread(make_extended_thread()) diff --git a/messages/src/msg_fields/protocols/cred_issuance/issue_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/issue_credential.rs similarity index 87% rename from messages/src/msg_fields/protocols/cred_issuance/issue_credential.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/issue_credential.rs index 3179f1bcf5..161af7d698 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/issue_credential.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/issue_credential.rs @@ -6,10 +6,10 @@ use crate::{ msg_parts::MsgParts, }; -pub type IssueCredential = MsgParts; +pub type IssueCredentialV1 = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct IssueCredentialContent { +pub struct IssueCredentialV1Content { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub comment: Option, @@ -18,7 +18,7 @@ pub struct IssueCredentialContent { } #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct IssueCredentialDecorators { +pub struct IssueCredentialV1Decorators { #[serde(rename = "~thread")] pub thread: Thread, #[builder(default, setter(strip_option))] @@ -50,11 +50,11 @@ mod tests { #[test] fn test_minimal_issue_cred() { - let content = IssueCredentialContent::builder() + let content = IssueCredentialV1Content::builder() .credentials_attach(vec![make_extended_attachment()]) .build(); - let decorators = IssueCredentialDecorators::builder() + let decorators = IssueCredentialV1Decorators::builder() .thread(make_extended_thread()) .build(); @@ -73,12 +73,12 @@ mod tests { #[test] fn test_extended_issue_cred() { - let content = IssueCredentialContent::builder() + let content = IssueCredentialV1Content::builder() .credentials_attach(vec![make_extended_attachment()]) .comment("test_comment".to_owned()) .build(); - let decorators = IssueCredentialDecorators::builder() + let decorators = IssueCredentialV1Decorators::builder() .thread(make_extended_thread()) .timing(make_extended_timing()) .please_ack(make_minimal_please_ack()) diff --git a/messages/src/msg_fields/protocols/cred_issuance/v1/mod.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/mod.rs new file mode 100644 index 0000000000..a85709a63d --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/mod.rs @@ -0,0 +1,225 @@ +//! Module containing the `issue credential` protocol messages, as defined in the [RFC](). + +pub mod ack; +pub mod issue_credential; +pub mod offer_credential; +pub mod problem_report; +pub mod propose_credential; +pub mod request_credential; + +use std::str::FromStr; + +use derive_more::From; +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; +use shared_vcx::misc::utils::CowStr; + +use self::{ + ack::{AckCredentialV1, AckCredentialV1Content}, + issue_credential::{IssueCredentialV1, IssueCredentialV1Content, IssueCredentialV1Decorators}, + offer_credential::{OfferCredentialV1, OfferCredentialV1Content, OfferCredentialV1Decorators}, + problem_report::{CredIssuanceV1ProblemReport, CredIssuanceV1ProblemReportContent}, + propose_credential::{ + ProposeCredentialV1, ProposeCredentialV1Content, ProposeCredentialV1Decorators, + }, + request_credential::{ + RequestCredentialV1, RequestCredentialV1Content, RequestCredentialV1Decorators, + }, +}; +use super::{common::CredentialAttr, CredentialIssuance}; +use crate::{ + misc::utils::{self, into_msg_with_type, transit_to_aries_msg}, + msg_fields::{ + protocols::{notification::ack::AckDecorators, report_problem::ProblemReportDecorators}, + traits::DelayedSerde, + }, + msg_types::{ + protocols::cred_issuance::{ + CredentialIssuanceType as CredentialIssuanceKind, CredentialIssuanceTypeV1, + CredentialIssuanceTypeV1_0, + }, + traits::MessageKind, + MessageType, MsgWithType, Protocol, + }, +}; + +#[derive(Clone, Debug, From, PartialEq)] +pub enum CredentialIssuanceV1 { + OfferCredential(OfferCredentialV1), + ProposeCredential(ProposeCredentialV1), + RequestCredential(RequestCredentialV1), + IssueCredential(IssueCredentialV1), + Ack(AckCredentialV1), + ProblemReport(CredIssuanceV1ProblemReport), +} + +impl DelayedSerde for CredentialIssuanceV1 { + type MsgType<'a> = (CredentialIssuanceKind, &'a str); + + fn delayed_deserialize<'de, D>( + msg_type: Self::MsgType<'de>, + deserializer: D, + ) -> Result + where + D: Deserializer<'de>, + { + let (protocol, kind_str) = msg_type; + let kind = match protocol { + CredentialIssuanceKind::V1(CredentialIssuanceTypeV1::V1_0(kind)) => { + kind.kind_from_str(kind_str) + } + CredentialIssuanceKind::V2(_) => { + return Err(D::Error::custom( + "Cannot deserialize issue-credential-v2 message type into issue-credential-v1", + )) + } + }; + + match kind.map_err(D::Error::custom)? { + CredentialIssuanceTypeV1_0::OfferCredential => { + OfferCredentialV1::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::ProposeCredential => { + ProposeCredentialV1::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::RequestCredential => { + RequestCredentialV1::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::IssueCredential => { + IssueCredentialV1::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::Ack => { + AckCredentialV1::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::ProblemReport => { + CredIssuanceV1ProblemReport::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV1_0::CredentialPreview => { + Err(utils::not_standalone_msg::(kind_str)) + } + } + } + + fn delayed_serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::OfferCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::ProposeCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::RequestCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::IssueCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::Ack(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct CredentialPreviewV1 { + #[serde(rename = "@type")] + msg_type: CredentialPreviewV1MsgType, + pub attributes: Vec, +} + +impl CredentialPreviewV1 { + pub fn new(attributes: Vec) -> Self { + Self { + msg_type: CredentialPreviewV1MsgType, + attributes, + } + } +} + +/// Non-standalone message type. +/// This is only encountered as part of an existent message. +/// It is not a message on it's own. +#[derive(Copy, Clone, Debug, Default, Deserialize, PartialEq)] +#[serde(try_from = "CowStr")] +struct CredentialPreviewV1MsgType; + +impl<'a> From<&'a CredentialPreviewV1MsgType> for CredentialIssuanceTypeV1_0 { + fn from(_value: &'a CredentialPreviewV1MsgType) -> Self { + CredentialIssuanceTypeV1_0::CredentialPreview + } +} + +impl<'a> TryFrom> for CredentialPreviewV1MsgType { + type Error = String; + + fn try_from(value: CowStr) -> Result { + let value = MessageType::try_from(value.0.as_ref())?; + + if let Protocol::CredentialIssuanceType(CredentialIssuanceKind::V1( + CredentialIssuanceTypeV1::V1_0(_), + )) = value.protocol + { + if let Ok(CredentialIssuanceTypeV1_0::CredentialPreview) = + CredentialIssuanceTypeV1_0::from_str(value.kind) + { + return Ok(CredentialPreviewV1MsgType); + } + } + + Err(format!("message kind is not {}", value.kind)) + } +} + +impl Serialize for CredentialPreviewV1MsgType { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let protocol = Protocol::from(CredentialIssuanceTypeV1_0::parent()); + let kind = CredentialIssuanceTypeV1_0::from(self); + format_args!("{protocol}/{}", kind.as_ref()).serialize(serializer) + } +} + +transit_to_aries_msg!( + OfferCredentialV1Content: OfferCredentialV1Decorators, + CredentialIssuanceV1, CredentialIssuance +); +transit_to_aries_msg!( + ProposeCredentialV1Content: ProposeCredentialV1Decorators, + CredentialIssuanceV1, CredentialIssuance +); +transit_to_aries_msg!( + RequestCredentialV1Content: RequestCredentialV1Decorators, + CredentialIssuanceV1, CredentialIssuance +); +transit_to_aries_msg!( + IssueCredentialV1Content: IssueCredentialV1Decorators, + CredentialIssuanceV1, CredentialIssuance +); +transit_to_aries_msg!(AckCredentialV1Content: AckDecorators, CredentialIssuanceV1, CredentialIssuance); +transit_to_aries_msg!( + CredIssuanceV1ProblemReportContent: ProblemReportDecorators, + CredentialIssuanceV1, CredentialIssuance +); + +into_msg_with_type!( + OfferCredentialV1, + CredentialIssuanceTypeV1_0, + OfferCredential +); +into_msg_with_type!( + ProposeCredentialV1, + CredentialIssuanceTypeV1_0, + ProposeCredential +); +into_msg_with_type!( + RequestCredentialV1, + CredentialIssuanceTypeV1_0, + RequestCredential +); +into_msg_with_type!( + IssueCredentialV1, + CredentialIssuanceTypeV1_0, + IssueCredential +); +into_msg_with_type!(AckCredentialV1, CredentialIssuanceTypeV1_0, Ack); +into_msg_with_type!( + CredIssuanceV1ProblemReport, + CredentialIssuanceTypeV1_0, + ProblemReport +); diff --git a/messages/src/msg_fields/protocols/cred_issuance/offer_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/offer_credential.rs similarity index 81% rename from messages/src/msg_fields/protocols/cred_issuance/offer_credential.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/offer_credential.rs index b596a0fd25..bdc790efee 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/offer_credential.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/offer_credential.rs @@ -1,26 +1,26 @@ use serde::{Deserialize, Serialize}; use typed_builder::TypedBuilder; -use super::CredentialPreview; +use super::CredentialPreviewV1; use crate::{ decorators::{attachment::Attachment, thread::Thread, timing::Timing}, msg_parts::MsgParts, }; -pub type OfferCredential = MsgParts; +pub type OfferCredentialV1 = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct OfferCredentialContent { +pub struct OfferCredentialV1Content { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub comment: Option, - pub credential_preview: CredentialPreview, + pub credential_preview: CredentialPreviewV1, #[serde(rename = "offers~attach")] pub offers_attach: Vec, } #[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct OfferCredentialDecorators { +pub struct OfferCredentialV1Decorators { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "~thread")] @@ -44,7 +44,7 @@ mod tests { timing::tests::make_extended_timing, }, misc::test_utils, - msg_fields::protocols::cred_issuance::CredentialAttr, + msg_fields::protocols::cred_issuance::v1::CredentialAttr, msg_types::cred_issuance::CredentialIssuanceTypeV1_0, }; @@ -55,13 +55,13 @@ mod tests { .value("test_attribute_value".to_owned()) .build(); - let preview = CredentialPreview::new(vec![attribute]); - let content = OfferCredentialContent::builder() + let preview = CredentialPreviewV1::new(vec![attribute]); + let content = OfferCredentialV1Content::builder() .credential_preview(preview) .offers_attach(vec![make_extended_attachment()]) .build(); - let decorators = OfferCredentialDecorators::default(); + let decorators = OfferCredentialV1Decorators::default(); let expected = json!({ "offers~attach": content.offers_attach, @@ -83,14 +83,14 @@ mod tests { .value("test_attribute_value".to_owned()) .build(); - let preview = CredentialPreview::new(vec![attribute]); - let content = OfferCredentialContent::builder() + let preview = CredentialPreviewV1::new(vec![attribute]); + let content = OfferCredentialV1Content::builder() .credential_preview(preview) .offers_attach(vec![make_extended_attachment()]) .comment("test_comment".to_owned()) .build(); - let decorators = OfferCredentialDecorators::builder() + let decorators = OfferCredentialV1Decorators::builder() .thread(make_extended_thread()) .timing(make_extended_timing()) .build(); diff --git a/messages/src/msg_fields/protocols/cred_issuance/problem_report.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/problem_report.rs similarity index 88% rename from messages/src/msg_fields/protocols/cred_issuance/problem_report.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/problem_report.rs index 69324f4c7a..f79f09d161 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/problem_report.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/problem_report.rs @@ -8,23 +8,23 @@ use crate::{ msg_parts::MsgParts, }; -pub type CredIssuanceProblemReport = - MsgParts; +pub type CredIssuanceV1ProblemReport = + MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] #[serde(transparent)] -pub struct CredIssuanceProblemReportContent { +pub struct CredIssuanceV1ProblemReportContent { pub inner: ProblemReportContent, } -impl From for CredIssuanceProblemReportContent { +impl From for CredIssuanceV1ProblemReportContent { fn from(value: ProblemReportContent) -> Self { Self { inner: value } } } -impl From for ProblemReport { - fn from(value: CredIssuanceProblemReport) -> Self { +impl From for ProblemReport { + fn from(value: CredIssuanceV1ProblemReport) -> Self { Self::builder() .id(value.id) .content(value.content.inner) @@ -60,7 +60,7 @@ mod tests { .code("test_problem_report_code".to_owned()) .build(); - let content: CredIssuanceProblemReportContent = ProblemReportContent::builder() + let content: CredIssuanceV1ProblemReportContent = ProblemReportContent::builder() .description(description) .build(); let decorators = ProblemReportDecorators::default(); @@ -121,7 +121,7 @@ mod tests { "fix-hint~l10n": decorators.fix_hint_locale }); - let content = CredIssuanceProblemReportContent::builder() + let content = CredIssuanceV1ProblemReportContent::builder() .inner(content) .build(); diff --git a/messages/src/msg_fields/protocols/cred_issuance/propose_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/propose_credential.rs similarity index 80% rename from messages/src/msg_fields/protocols/cred_issuance/propose_credential.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/propose_credential.rs index 40a4d1fe68..8a16ba20a5 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/propose_credential.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/propose_credential.rs @@ -1,26 +1,26 @@ use serde::{Deserialize, Serialize}; use typed_builder::TypedBuilder; -use super::CredentialPreview; +use super::CredentialPreviewV1; use crate::{ decorators::{thread::Thread, timing::Timing}, msg_parts::MsgParts, }; -pub type ProposeCredential = MsgParts; +pub type ProposeCredentialV1 = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct ProposeCredentialContent { +pub struct ProposeCredentialV1Content { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub comment: Option, - pub credential_proposal: CredentialPreview, + pub credential_proposal: CredentialPreviewV1, pub schema_id: String, pub cred_def_id: String, } #[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct ProposeCredentialDecorators { +pub struct ProposeCredentialV1Decorators { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "~thread")] @@ -41,7 +41,7 @@ mod tests { use crate::{ decorators::{thread::tests::make_extended_thread, timing::tests::make_extended_timing}, misc::test_utils, - msg_fields::protocols::cred_issuance::CredentialAttr, + msg_fields::protocols::cred_issuance::v1::CredentialAttr, msg_types::cred_issuance::CredentialIssuanceTypeV1_0, }; @@ -51,14 +51,14 @@ mod tests { .name("test_attribute_name".to_owned()) .value("test_attribute_value".to_owned()) .build(); - let preview = CredentialPreview::new(vec![attribute]); - let content = ProposeCredentialContent::builder() + let preview = CredentialPreviewV1::new(vec![attribute]); + let content = ProposeCredentialV1Content::builder() .credential_proposal(preview) .schema_id("test_schema_id".to_owned()) .cred_def_id("test_cred_def_id".to_owned()) .build(); - let decorators = ProposeCredentialDecorators::default(); + let decorators = ProposeCredentialV1Decorators::default(); let expected = json!({ "credential_proposal": content.credential_proposal, @@ -80,15 +80,15 @@ mod tests { .name("test_attribute_name".to_owned()) .value("test_attribute_value".to_owned()) .build(); - let preview = CredentialPreview::new(vec![attribute]); - let content = ProposeCredentialContent::builder() + let preview = CredentialPreviewV1::new(vec![attribute]); + let content = ProposeCredentialV1Content::builder() .credential_proposal(preview) .schema_id("test_schema_id".to_owned()) .cred_def_id("test_cred_def_id".to_owned()) .comment("test_comment".to_owned()) .build(); - let decorators = ProposeCredentialDecorators::builder() + let decorators = ProposeCredentialV1Decorators::builder() .thread(make_extended_thread()) .timing(make_extended_timing()) .build(); diff --git a/messages/src/msg_fields/protocols/cred_issuance/request_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v1/request_credential.rs similarity index 84% rename from messages/src/msg_fields/protocols/cred_issuance/request_credential.rs rename to messages/src/msg_fields/protocols/cred_issuance/v1/request_credential.rs index ea4b63907a..d285ebd6f2 100644 --- a/messages/src/msg_fields/protocols/cred_issuance/request_credential.rs +++ b/messages/src/msg_fields/protocols/cred_issuance/v1/request_credential.rs @@ -6,10 +6,10 @@ use crate::{ msg_parts::MsgParts, }; -pub type RequestCredential = MsgParts; +pub type RequestCredentialV1 = MsgParts; #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] -pub struct RequestCredentialContent { +pub struct RequestCredentialV1Content { #[builder(default, setter(strip_option))] #[serde(skip_serializing_if = "Option::is_none")] pub comment: Option, @@ -18,7 +18,7 @@ pub struct RequestCredentialContent { } #[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] -pub struct RequestCredentialDecorators { +pub struct RequestCredentialV1Decorators { #[builder(default, setter(strip_option))] #[serde(rename = "~thread")] #[serde(skip_serializing_if = "Option::is_none")] @@ -46,11 +46,11 @@ mod tests { #[test] fn test_minimal_request_cred() { - let content = RequestCredentialContent::builder() + let content = RequestCredentialV1Content::builder() .requests_attach(vec![make_extended_attachment()]) .build(); - let decorators = RequestCredentialDecorators::default(); + let decorators = RequestCredentialV1Decorators::default(); let expected = json!({ "requests~attach": content.requests_attach, @@ -66,12 +66,12 @@ mod tests { #[test] fn test_extended_request_cred() { - let content = RequestCredentialContent::builder() + let content = RequestCredentialV1Content::builder() .requests_attach(vec![make_extended_attachment()]) .comment("test_comment".to_owned()) .build(); - let decorators = RequestCredentialDecorators::builder() + let decorators = RequestCredentialV1Decorators::builder() .thread(make_extended_thread()) .build(); diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/ack.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/ack.rs new file mode 100644 index 0000000000..39a0ea1d1e --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/ack.rs @@ -0,0 +1,90 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + msg_fields::protocols::notification::ack::{Ack, AckContent, AckDecorators}, + msg_parts::MsgParts, +}; + +pub type AckCredentialV2 = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +#[serde(transparent)] +pub struct AckCredentialV2Content { + pub inner: AckContent, +} + +impl From for AckCredentialV2Content { + fn from(value: AckContent) -> Self { + Self { inner: value } + } +} + +impl From for Ack { + fn from(value: AckCredentialV2) -> Self { + Self::builder() + .id(value.id) + .content(value.content.inner) + .decorators(value.decorators) + .build() + } +} + +#[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, timing::tests::make_extended_timing}, + misc::test_utils, + msg_fields::protocols::notification::ack::AckStatus, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_ack_cred() { + let content: AckCredentialV2Content = AckContent::builder().status(AckStatus::Ok).build(); + + let decorators = AckDecorators::builder() + .thread(make_extended_thread()) + .build(); + + let expected = json!({ + "status": content.inner.status, + "~thread": decorators.thread + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::Ack, + expected, + ); + } + + #[test] + fn test_extended_ack_cred() { + let content: AckCredentialV2Content = AckContent::builder().status(AckStatus::Ok).build(); + + let decorators = AckDecorators::builder() + .thread(make_extended_thread()) + .timing(make_extended_timing()) + .build(); + + let expected = json!({ + "status": content.inner.status, + "~thread": decorators.thread, + "~timing": decorators.timing + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::Ack, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/issue_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/issue_credential.rs new file mode 100644 index 0000000000..19adc8b769 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/issue_credential.rs @@ -0,0 +1,137 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use super::AttachmentFormatSpecifier; +use crate::{ + decorators::{attachment::Attachment, please_ack::PleaseAck, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type IssueCredentialV2 = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct IssueCredentialV2Content { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub goal_code: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub replacement_id: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, + pub formats: Vec>, + #[serde(rename = "credentials~attach")] + pub credentials_attach: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct IssueCredentialV2Decorators { + #[serde(rename = "~thread")] + pub thread: Thread, + #[builder(default)] + #[serde(rename = "~please_ack")] + #[serde(skip_serializing_if = "Option::is_none")] + pub please_ack: Option, + #[builder(default)] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub enum IssueCredentialAttachmentFormatType { + #[serde(rename = "aries/ld-proof-vc@v1.0")] + AriesLdProofVc1_0, + #[serde(rename = "hlindy/cred@v2.0")] + HyperledgerIndyCredential2_0, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + use shared_vcx::maybe_known::MaybeKnown; + + use super::*; + use crate::{ + decorators::{ + attachment::tests::make_extended_attachment, + please_ack::tests::make_minimal_please_ack, thread::tests::make_extended_thread, + timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_issue_cred() { + let content = IssueCredentialV2Content::builder() + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: MaybeKnown::Known( + IssueCredentialAttachmentFormatType::HyperledgerIndyCredential2_0, + ), + }]) + .credentials_attach(vec![make_extended_attachment()]) + .build(); + + let decorators = IssueCredentialV2Decorators::builder() + .thread(make_extended_thread()) + .build(); + + let expected = json!({ + "formats": content.formats, + "credentials~attach": content.credentials_attach, + "~thread": decorators.thread + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::IssueCredential, + expected, + ); + } + + #[test] + fn test_extended_issue_cred() { + let content = IssueCredentialV2Content::builder() + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: shared_vcx::maybe_known::MaybeKnown::Known( + IssueCredentialAttachmentFormatType::HyperledgerIndyCredential2_0, + ), + }]) + .credentials_attach(vec![make_extended_attachment()]) + .goal_code(Some("goal.goal".to_owned())) + .replacement_id(Some("replacement-123".to_owned())) + .comment(Some("test_comment".to_owned())) + .build(); + + let decorators = IssueCredentialV2Decorators::builder() + .thread(make_extended_thread()) + .timing(Some(make_extended_timing())) + .please_ack(Some(make_minimal_please_ack())) + .build(); + + let expected = json!({ + "formats": content.formats, + "credentials~attach": content.credentials_attach, + "goal_code": content.goal_code, + "replacement_id": content.replacement_id, + "comment": content.comment, + "~thread": decorators.thread, + "~timing": decorators.timing, + "~please_ack": decorators.please_ack + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::IssueCredential, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/mod.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/mod.rs new file mode 100644 index 0000000000..8f9d100c62 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/mod.rs @@ -0,0 +1,232 @@ +//! Module containing the `issue credential` protocol messages, as defined in the [RFC](). + +pub mod ack; +pub mod issue_credential; +pub mod offer_credential; +pub mod problem_report; +pub mod propose_credential; +pub mod request_credential; + +use std::str::FromStr; + +use derive_more::From; +use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; +use shared_vcx::{maybe_known::MaybeKnown, misc::utils::CowStr}; +use typed_builder::TypedBuilder; + +use self::{ + ack::{AckCredentialV2, AckCredentialV2Content}, + issue_credential::{IssueCredentialV2, IssueCredentialV2Content, IssueCredentialV2Decorators}, + offer_credential::{OfferCredentialV2, OfferCredentialV2Content, OfferCredentialV2Decorators}, + problem_report::{CredIssuanceProblemReportV2, CredIssuanceV2ProblemReportContent}, + propose_credential::{ + ProposeCredentialV2, ProposeCredentialV2Content, ProposeCredentialV2Decorators, + }, + request_credential::{ + RequestCredentialV2, RequestCredentialV2Content, RequestCredentialV2Decorators, + }, +}; +use super::{ + super::{notification::ack::AckDecorators, report_problem::ProblemReportDecorators}, + common::CredentialAttr, + CredentialIssuance, +}; +use crate::{ + misc::utils::{self, into_msg_with_type, transit_to_aries_msg}, + msg_fields::traits::DelayedSerde, + msg_types::{ + cred_issuance::{CredentialIssuanceTypeV2, CredentialIssuanceTypeV2_0}, + protocols::cred_issuance::CredentialIssuanceType as CredentialIssuanceKind, + traits::MessageKind, + MessageType, MsgWithType, Protocol, + }, +}; + +#[derive(Clone, Debug, From, PartialEq)] +pub enum CredentialIssuanceV2 { + OfferCredential(OfferCredentialV2), + ProposeCredential(ProposeCredentialV2), + RequestCredential(RequestCredentialV2), + IssueCredential(IssueCredentialV2), + Ack(AckCredentialV2), + ProblemReport(CredIssuanceProblemReportV2), +} + +impl DelayedSerde for CredentialIssuanceV2 { + type MsgType<'a> = (CredentialIssuanceKind, &'a str); + + fn delayed_deserialize<'de, D>( + msg_type: Self::MsgType<'de>, + deserializer: D, + ) -> Result + where + D: Deserializer<'de>, + { + let (protocol, kind_str) = msg_type; + let kind = match protocol { + CredentialIssuanceKind::V2(CredentialIssuanceTypeV2::V2_0(kind)) => { + kind.kind_from_str(kind_str) + } + CredentialIssuanceKind::V1(_) => { + return Err(D::Error::custom( + "Cannot deserialize issue-credential-v1 message type into issue-credential-v2", + )) + } + }; + + match kind.map_err(D::Error::custom)? { + CredentialIssuanceTypeV2_0::OfferCredential => { + OfferCredentialV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::ProposeCredential => { + ProposeCredentialV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::RequestCredential => { + RequestCredentialV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::IssueCredential => { + IssueCredentialV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::Ack => { + AckCredentialV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::ProblemReport => { + CredIssuanceProblemReportV2::deserialize(deserializer).map(From::from) + } + CredentialIssuanceTypeV2_0::CredentialPreview => { + Err(utils::not_standalone_msg::(kind_str)) + } + } + } + + fn delayed_serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Self::OfferCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::ProposeCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::RequestCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::IssueCredential(v) => MsgWithType::from(v).serialize(serializer), + Self::Ack(v) => MsgWithType::from(v).serialize(serializer), + Self::ProblemReport(v) => MsgWithType::from(v).serialize(serializer), + } + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +pub struct CredentialPreviewV2 { + #[serde(rename = "@type")] + msg_type: CredentialPreviewV2MsgType, + pub attributes: Vec, +} + +impl CredentialPreviewV2 { + pub fn new(attributes: Vec) -> Self { + Self { + msg_type: CredentialPreviewV2MsgType, + attributes, + } + } +} + +/// Non-standalone message type. +/// This is only encountered as part of an existent message. +/// It is not a message on it's own. +#[derive(Copy, Clone, Debug, Default, Deserialize, PartialEq)] +#[serde(try_from = "CowStr")] +struct CredentialPreviewV2MsgType; + +impl<'a> From<&'a CredentialPreviewV2MsgType> for CredentialIssuanceTypeV2_0 { + fn from(_value: &'a CredentialPreviewV2MsgType) -> Self { + CredentialIssuanceTypeV2_0::CredentialPreview + } +} + +impl<'a> TryFrom> for CredentialPreviewV2MsgType { + type Error = String; + + fn try_from(value: CowStr) -> Result { + let value = MessageType::try_from(value.0.as_ref())?; + + if let Protocol::CredentialIssuanceType(CredentialIssuanceKind::V2( + CredentialIssuanceTypeV2::V2_0(_), + )) = value.protocol + { + if let Ok(CredentialIssuanceTypeV2_0::CredentialPreview) = + CredentialIssuanceTypeV2_0::from_str(value.kind) + { + return Ok(CredentialPreviewV2MsgType); + } + } + + Err(format!("message kind is not {}", value.kind)) + } +} + +impl Serialize for CredentialPreviewV2MsgType { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let protocol = Protocol::from(CredentialIssuanceTypeV2_0::parent()); + let kind = CredentialIssuanceTypeV2_0::from(self); + format_args!("{protocol}/{}", kind.as_ref()).serialize(serializer) + } +} + +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, TypedBuilder)] +#[serde(rename_all = "snake_case")] +pub struct AttachmentFormatSpecifier { + attach_id: String, + format: MaybeKnown, +} + +transit_to_aries_msg!( + OfferCredentialV2Content: OfferCredentialV2Decorators, + CredentialIssuanceV2, CredentialIssuance +); +transit_to_aries_msg!( + ProposeCredentialV2Content: ProposeCredentialV2Decorators, + CredentialIssuanceV2, CredentialIssuance +); +transit_to_aries_msg!( + RequestCredentialV2Content: RequestCredentialV2Decorators, + CredentialIssuanceV2, CredentialIssuance +); +transit_to_aries_msg!( + IssueCredentialV2Content: IssueCredentialV2Decorators, + CredentialIssuanceV2, CredentialIssuance +); +transit_to_aries_msg!(AckCredentialV2Content: AckDecorators, CredentialIssuanceV2, CredentialIssuance); +transit_to_aries_msg!( + CredIssuanceV2ProblemReportContent: ProblemReportDecorators, + CredentialIssuanceV2, CredentialIssuance +); + +into_msg_with_type!( + OfferCredentialV2, + CredentialIssuanceTypeV2_0, + OfferCredential +); +into_msg_with_type!( + ProposeCredentialV2, + CredentialIssuanceTypeV2_0, + ProposeCredential +); +into_msg_with_type!( + RequestCredentialV2, + CredentialIssuanceTypeV2_0, + RequestCredential +); +into_msg_with_type!( + IssueCredentialV2, + CredentialIssuanceTypeV2_0, + IssueCredential +); +into_msg_with_type!(AckCredentialV2, CredentialIssuanceTypeV2_0, Ack); +into_msg_with_type!( + CredIssuanceProblemReportV2, + CredentialIssuanceTypeV2_0, + ProblemReport +); diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/offer_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/offer_credential.rs new file mode 100644 index 0000000000..495ff6f1e4 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/offer_credential.rs @@ -0,0 +1,149 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use super::{AttachmentFormatSpecifier, CredentialPreviewV2}; +use crate::{ + decorators::{attachment::Attachment, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type OfferCredentialV2 = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct OfferCredentialV2Content { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub goal_code: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub replacement_id: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, + pub credential_preview: CredentialPreviewV2, + pub formats: Vec>, + #[serde(rename = "offers~attach")] + pub offers_attach: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct OfferCredentialV2Decorators { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "~thread")] + pub thread: Option, + #[builder(default)] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub enum OfferCredentialAttachmentFormatType { + #[serde(rename = "dif/credential-manifest@v1.0")] + DifCredentialManifest1_0, + #[serde(rename = "hlindy/cred-abstract@v2.0")] + HyperledgerIndyCredentialAbstract2_0, + #[serde(rename = "aries/ld-proof-vc-detail@v1.0")] + AriesLdProofVcDetail1_0, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + use shared_vcx::maybe_known::MaybeKnown; + + use super::*; + use crate::{ + decorators::{ + attachment::tests::make_extended_attachment, thread::tests::make_extended_thread, + timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_fields::protocols::cred_issuance::common::CredentialAttr, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_offer_cred() { + let attribute = CredentialAttr::builder() + .name("test_attribute_name".to_owned()) + .value("test_attribute_value".to_owned()) + .build(); + + let preview = CredentialPreviewV2::new(vec![attribute]); + let content = OfferCredentialV2Content::builder() + .credential_preview(preview) + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: MaybeKnown::Known( + OfferCredentialAttachmentFormatType::HyperledgerIndyCredentialAbstract2_0, + ), + }]) + .offers_attach(vec![make_extended_attachment()]) + .build(); + + let decorators = OfferCredentialV2Decorators::default(); + + let expected = json!({ + "formats": content.formats, + "offers~attach": content.offers_attach, + "credential_preview": content.credential_preview, + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::OfferCredential, + expected, + ); + } + + #[test] + fn test_extended_offer_cred() { + let attribute = CredentialAttr::builder() + .name("test_attribute_name".to_owned()) + .value("test_attribute_value".to_owned()) + .build(); + + let preview = CredentialPreviewV2::new(vec![attribute]); + let content = OfferCredentialV2Content::builder() + .credential_preview(preview) + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: MaybeKnown::Known( + OfferCredentialAttachmentFormatType::HyperledgerIndyCredentialAbstract2_0, + ), + }]) + .offers_attach(vec![make_extended_attachment()]) + .comment(Some("test_comment".to_owned())) + .replacement_id(Some("replacement_id".to_owned())) + .goal_code(Some("goal.goal".to_owned())) + .build(); + + let decorators = OfferCredentialV2Decorators::builder() + .thread(Some(make_extended_thread())) + .timing(Some(make_extended_timing())) + .build(); + + let expected = json!({ + "formats": content.formats, + "offers~attach": content.offers_attach, + "credential_preview": content.credential_preview, + "comment": content.comment, + "goal_code": content.goal_code, + "replacement_id": content.replacement_id, + "~thread": decorators.thread, + "~timing": decorators.timing + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::OfferCredential, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/problem_report.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/problem_report.rs new file mode 100644 index 0000000000..542142b0bd --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/problem_report.rs @@ -0,0 +1,135 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use crate::{ + msg_fields::protocols::report_problem::{ + ProblemReport, ProblemReportContent, ProblemReportDecorators, + }, + msg_parts::MsgParts, +}; + +pub type CredIssuanceProblemReportV2 = + MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +#[serde(transparent)] +pub struct CredIssuanceV2ProblemReportContent { + pub inner: ProblemReportContent, +} + +impl From for CredIssuanceV2ProblemReportContent { + fn from(value: ProblemReportContent) -> Self { + Self { inner: value } + } +} + +impl From for ProblemReport { + fn from(value: CredIssuanceProblemReportV2) -> Self { + Self::builder() + .id(value.id) + .content(value.content.inner) + .decorators(value.decorators) + .build() + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use std::collections::HashMap; + + use serde_json::json; + + use super::*; + use crate::{ + decorators::{ + localization::tests::make_extended_field_localization, + thread::tests::make_extended_thread, timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_fields::protocols::report_problem::{ + Description, Impact, Where, WhereParty, WhoRetries, + }, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_problem_report() { + let description = Description::builder() + .code("test_problem_report_code".to_owned()) + .build(); + + let content: CredIssuanceV2ProblemReportContent = ProblemReportContent::builder() + .description(description) + .build(); + let decorators = ProblemReportDecorators::default(); + + let expected = json!({ + "description": content.inner.description + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::ProblemReport, + expected, + ); + } + + #[test] + fn test_extended_problem_report() { + let description = Description::builder() + .code("test_problem_report_code".to_owned()) + .build(); + + let content: ProblemReportContent = ProblemReportContent::builder() + .description(description) + .who_retries(WhoRetries::Me) + .fix_hint("test_fix_hint".to_owned()) + .impact(Impact::Connection) + .location(Where::new(WhereParty::Me, "test_location".to_owned())) + .noticed_time("test_noticed_time".to_owned()) + .tracking_uri("https://dummy.dummy/dummy".parse().unwrap()) + .escalation_uri("https://dummy.dummy/dummy".parse().unwrap()) + .problem_items(vec![HashMap::from([( + "test_prob_item_key".to_owned(), + "test_prob_item_value".to_owned(), + )])]) + .build(); + + let decorators = ProblemReportDecorators::builder() + .thread(make_extended_thread()) + .timing(make_extended_timing()) + .description_locale(make_extended_field_localization()) + .fix_hint_locale(make_extended_field_localization()) + .build(); + + let expected = json!({ + "description": content.description, + "who_retries": content.who_retries, + "fix-hint": content.fix_hint, + "impact": content.impact, + "where": content.location, + "noticed_time": content.noticed_time, + "tracking-uri": content.tracking_uri, + "escalation-uri": content.escalation_uri, + "problem_items": content.problem_items, + "~thread": decorators.thread, + "~timing": decorators.timing, + "description~l10n": decorators.description_locale, + "fix-hint~l10n": decorators.fix_hint_locale + }); + + let content = CredIssuanceV2ProblemReportContent::builder() + .inner(content) + .build(); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::ProblemReport, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/propose_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/propose_credential.rs new file mode 100644 index 0000000000..1350cea084 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/propose_credential.rs @@ -0,0 +1,137 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use super::{AttachmentFormatSpecifier, CredentialPreviewV2}; +use crate::{ + decorators::{attachment::Attachment, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type ProposeCredentialV2 = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct ProposeCredentialV2Content { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub goal_code: Option, // TODO - spec does not specify what goal codes to use.. + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub credential_preview: Option, + pub formats: Vec>, + #[serde(rename = "filters~attach")] + pub filters_attach: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct ProposeCredentialV2Decorators { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "~thread")] + pub thread: Option, + #[builder(default)] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub enum ProposeCredentialAttachmentFormatType { + #[serde(rename = "dif/credential-manifest@v1.0")] + DifCredentialManifest1_0, + #[serde(rename = "aries/ld-proof-vc-detail@v1.0")] + AriesLdProofVcDetail1_0, + #[serde(rename = "hlindy/cred-filter@v2.0")] + HyperledgerIndyCredentialFilter2_0, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + use shared_vcx::maybe_known::MaybeKnown; + + use super::*; + use crate::{ + decorators::{ + attachment::tests::make_extended_attachment, thread::tests::make_extended_thread, + timing::tests::make_extended_timing, + }, + misc::test_utils, + msg_fields::protocols::cred_issuance::common::CredentialAttr, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_propose_cred() { + let content = ProposeCredentialV2Content::builder() + .formats(vec![AttachmentFormatSpecifier { + attach_id: String::from("1"), + format: MaybeKnown::Known( + ProposeCredentialAttachmentFormatType::HyperledgerIndyCredentialFilter2_0, + ), + }]) + .filters_attach(vec![make_extended_attachment()]) + .build(); + + let decorators = ProposeCredentialV2Decorators::default(); + + let expected = json!({ + "formats": content.formats, + "filters~attach": content.filters_attach, + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::ProposeCredential, + expected, + ); + } + + #[test] + fn test_extended_propose_cred() { + let attribute = CredentialAttr::builder() + .name("test_attribute_name".to_owned()) + .value("test_attribute_value".to_owned()) + .build(); + let preview = CredentialPreviewV2::new(vec![attribute]); + let content = ProposeCredentialV2Content::builder() + .credential_preview(Some(preview)) + .formats(vec![AttachmentFormatSpecifier { + attach_id: String::from("1"), + format: MaybeKnown::Known( + ProposeCredentialAttachmentFormatType::HyperledgerIndyCredentialFilter2_0, + ), + }]) + .filters_attach(vec![make_extended_attachment()]) + .comment(Some("test_comment".to_owned())) + .goal_code(Some("goal.goal".to_owned())) + .build(); + + let decorators = ProposeCredentialV2Decorators::builder() + .thread(Some(make_extended_thread())) + .timing(Some(make_extended_timing())) + .build(); + + let expected = json!({ + "credential_preview": content.credential_preview, + "formats": content.formats, + "filters~attach": content.filters_attach, + "comment": content.comment, + "goal_code": content.goal_code, + "~thread": decorators.thread, + "~timing": decorators.timing + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::ProposeCredential, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/cred_issuance/v2/request_credential.rs b/messages/src/msg_fields/protocols/cred_issuance/v2/request_credential.rs new file mode 100644 index 0000000000..e916f3be67 --- /dev/null +++ b/messages/src/msg_fields/protocols/cred_issuance/v2/request_credential.rs @@ -0,0 +1,123 @@ +use serde::{Deserialize, Serialize}; +use typed_builder::TypedBuilder; + +use super::AttachmentFormatSpecifier; +use crate::{ + decorators::{attachment::Attachment, thread::Thread, timing::Timing}, + msg_parts::MsgParts, +}; + +pub type RequestCredentialV2 = MsgParts; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, TypedBuilder)] +pub struct RequestCredentialV2Content { + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub goal_code: Option, + #[builder(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub comment: Option, + pub formats: Vec>, + #[serde(rename = "requests~attach")] + pub requests_attach: Vec, +} + +#[derive(Clone, Debug, Deserialize, Serialize, Default, PartialEq, TypedBuilder)] +pub struct RequestCredentialV2Decorators { + #[builder(default)] + #[serde(rename = "~thread")] + #[serde(skip_serializing_if = "Option::is_none")] + pub thread: Option, + #[builder(default)] + #[serde(rename = "~timing")] + #[serde(skip_serializing_if = "Option::is_none")] + pub timing: Option, +} + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)] +pub enum RequestCredentialAttachmentFormatType { + #[serde(rename = "dif/credential-manifest@v1.0")] + DifCredentialManifest1_0, + #[serde(rename = "hlindy/cred-req@v2.0")] + HyperledgerIndyCredentialRequest2_0, + #[serde(rename = "aries/ld-proof-vc-detail@v1.0")] + AriesLdProofVcDetail1_0, +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +#[allow(clippy::field_reassign_with_default)] +mod tests { + use serde_json::json; + use shared_vcx::maybe_known::MaybeKnown; + + use super::*; + use crate::{ + decorators::{ + attachment::tests::make_extended_attachment, thread::tests::make_extended_thread, + }, + misc::test_utils, + msg_types::cred_issuance::CredentialIssuanceTypeV2_0, + }; + + #[test] + fn test_minimal_request_cred() { + let content = RequestCredentialV2Content::builder() + .requests_attach(vec![make_extended_attachment()]) + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: MaybeKnown::Known( + RequestCredentialAttachmentFormatType::HyperledgerIndyCredentialRequest2_0, + ), + }]) + .build(); + + let decorators = RequestCredentialV2Decorators::default(); + + let expected = json!({ + "requests~attach": content.requests_attach, + "formats": content.formats + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::RequestCredential, + expected, + ); + } + + #[test] + fn test_extended_request_cred() { + let content = RequestCredentialV2Content::builder() + .requests_attach(vec![make_extended_attachment()]) + .formats(vec![AttachmentFormatSpecifier { + attach_id: "1".to_owned(), + format: MaybeKnown::Known( + RequestCredentialAttachmentFormatType::HyperledgerIndyCredentialRequest2_0, + ), + }]) + .comment(Some("test_comment".to_owned())) + .goal_code(Some("goal.goal".to_owned())) + .build(); + + let decorators = RequestCredentialV2Decorators::builder() + .thread(Some(make_extended_thread())) + .build(); + + let expected = json!({ + "requests~attach": content.requests_attach, + "formats": content.formats, + "comment": content.comment, + "goal_code": content.goal_code, + "~thread": decorators.thread + }); + + test_utils::test_msg( + content, + decorators, + CredentialIssuanceTypeV2_0::RequestCredential, + expected, + ); + } +} diff --git a/messages/src/msg_fields/protocols/notification/mod.rs b/messages/src/msg_fields/protocols/notification/mod.rs index d609c59e01..92d10b6159 100644 --- a/messages/src/msg_fields/protocols/notification/mod.rs +++ b/messages/src/msg_fields/protocols/notification/mod.rs @@ -62,7 +62,10 @@ impl DelayedSerde for Notification { } transit_to_aries_msg!(AckContent: AckDecorators, Notification); -transit_to_aries_msg!(NotificationProblemReportContent: ProblemReportDecorators, Notification); +transit_to_aries_msg!( + NotificationProblemReportContent: ProblemReportDecorators, + Notification +); into_msg_with_type!(Ack, NotificationTypeV1_0, Ack); into_msg_with_type!( diff --git a/messages/src/msg_fields/protocols/present_proof/mod.rs b/messages/src/msg_fields/protocols/present_proof/mod.rs index 73e40c5204..e03dc143e7 100644 --- a/messages/src/msg_fields/protocols/present_proof/mod.rs +++ b/messages/src/msg_fields/protocols/present_proof/mod.rs @@ -85,11 +85,20 @@ impl DelayedSerde for PresentProof { } } -transit_to_aries_msg!(ProposePresentationContent: ProposePresentationDecorators, PresentProof); -transit_to_aries_msg!(RequestPresentationContent: RequestPresentationDecorators, PresentProof); +transit_to_aries_msg!( + ProposePresentationContent: ProposePresentationDecorators, + PresentProof +); +transit_to_aries_msg!( + RequestPresentationContent: RequestPresentationDecorators, + PresentProof +); transit_to_aries_msg!(PresentationContent: PresentationDecorators, PresentProof); transit_to_aries_msg!(AckPresentationContent: AckDecorators, PresentProof); -transit_to_aries_msg!(PresentProofProblemReportContent: ProblemReportDecorators, PresentProof); +transit_to_aries_msg!( + PresentProofProblemReportContent: ProblemReportDecorators, + PresentProof +); into_msg_with_type!( ProposePresentation, diff --git a/messages/src/msg_types/protocols/cred_issuance.rs b/messages/src/msg_types/protocols/cred_issuance.rs index e3c5499915..45b4578581 100644 --- a/messages/src/msg_types/protocols/cred_issuance.rs +++ b/messages/src/msg_types/protocols/cred_issuance.rs @@ -10,6 +10,7 @@ use crate::msg_types::{role::Role, MsgKindType}; #[msg_type(protocol = "issue-credential")] pub enum CredentialIssuanceType { V1(CredentialIssuanceTypeV1), + V2(CredentialIssuanceTypeV2), } #[derive(Copy, Clone, Debug, From, TryInto, PartialEq, Transitive, MessageType)] @@ -20,6 +21,14 @@ pub enum CredentialIssuanceTypeV1 { V1_0(MsgKindType), } +#[derive(Copy, Clone, Debug, From, TryInto, PartialEq, Transitive, MessageType)] +#[transitive(into(CredentialIssuanceType, Protocol))] +#[msg_type(major = 2)] +pub enum CredentialIssuanceTypeV2 { + #[msg_type(minor = 0, roles = "Role::Holder, Role::Issuer")] + V2_0(MsgKindType), +} + #[derive(Copy, Clone, Debug, AsRefStr, EnumString, PartialEq)] #[strum(serialize_all = "kebab-case")] pub enum CredentialIssuanceTypeV1_0 { @@ -32,6 +41,18 @@ pub enum CredentialIssuanceTypeV1_0 { ProblemReport, } +#[derive(Copy, Clone, Debug, AsRefStr, EnumString, PartialEq)] +#[strum(serialize_all = "kebab-case")] +pub enum CredentialIssuanceTypeV2_0 { + OfferCredential, + ProposeCredential, + RequestCredential, + IssueCredential, + CredentialPreview, + Ack, + ProblemReport, +} + #[cfg(test)] mod tests { use serde_json::json; @@ -40,7 +61,7 @@ mod tests { use crate::misc::test_utils; #[test] - fn test_protocol_issue_credential() { + fn test_protocol_issue_credential_v1() { test_utils::test_serde( Protocol::from(CredentialIssuanceTypeV1::new_v1_0()), json!("https://didcomm.org/issue-credential/1.0"), @@ -48,7 +69,7 @@ mod tests { } #[test] - fn test_version_resolution_issue_credential() { + fn test_version_resolution_issue_credential_v1() { test_utils::test_msg_type_resolution( "https://didcomm.org/issue-credential/1.255", CredentialIssuanceTypeV1::new_v1_0(), @@ -57,7 +78,7 @@ mod tests { #[test] #[should_panic] - fn test_unsupported_version_issue_credential() { + fn test_unsupported_version_issue_credential_v1() { test_utils::test_serde( Protocol::from(CredentialIssuanceTypeV1::new_v1_0()), json!("https://didcomm.org/issue-credential/2.0"), @@ -65,7 +86,7 @@ mod tests { } #[test] - fn test_msg_type_offer() { + fn test_msg_type_offer_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "offer-credential", @@ -74,7 +95,7 @@ mod tests { } #[test] - fn test_msg_type_propose() { + fn test_msg_type_propose_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "propose-credential", @@ -83,7 +104,7 @@ mod tests { } #[test] - fn test_msg_type_request() { + fn test_msg_type_request_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "request-credential", @@ -92,7 +113,7 @@ mod tests { } #[test] - fn test_msg_type_issue() { + fn test_msg_type_issue_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "issue-credential", @@ -101,7 +122,7 @@ mod tests { } #[test] - fn test_msg_type_preview() { + fn test_msg_type_preview_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "credential-preview", @@ -110,11 +131,90 @@ mod tests { } #[test] - fn test_msg_type_ack() { + fn test_msg_type_ack_v1() { test_utils::test_msg_type( "https://didcomm.org/issue-credential/1.0", "ack", CredentialIssuanceTypeV1::new_v1_0(), ) } + + #[test] + fn test_protocol_issue_credential_v2() { + test_utils::test_serde( + Protocol::from(CredentialIssuanceTypeV2::new_v2_0()), + json!("https://didcomm.org/issue-credential/2.0"), + ) + } + + #[test] + fn test_version_resolution_issue_credential_v2() { + test_utils::test_msg_type_resolution( + "https://didcomm.org/issue-credential/2.255", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + #[should_panic] + fn test_unsupported_version_issue_credential_v2() { + test_utils::test_serde( + Protocol::from(CredentialIssuanceTypeV2::new_v2_0()), + json!("https://didcomm.org/issue-credential/1.0"), + ) + } + + #[test] + fn test_msg_type_offer_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "offer-credential", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + fn test_msg_type_propose_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "propose-credential", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + fn test_msg_type_request_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "request-credential", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + fn test_msg_type_issue_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "issue-credential", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + fn test_msg_type_preview_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "credential-preview", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } + + #[test] + fn test_msg_type_ack_v2() { + test_utils::test_msg_type( + "https://didcomm.org/issue-credential/2.0", + "ack", + CredentialIssuanceTypeV2::new_v2_0(), + ) + } } diff --git a/messages/src/msg_types/registry.rs b/messages/src/msg_types/registry.rs index 4895969676..bdec49cfcc 100644 --- a/messages/src/msg_types/registry.rs +++ b/messages/src/msg_types/registry.rs @@ -5,11 +5,17 @@ use shared_vcx::maybe_known::MaybeKnown; use super::{role::Role, Protocol}; use crate::msg_types::protocols::{ - basic_message::BasicMessageTypeV1, connection::ConnectionTypeV1, - cred_issuance::CredentialIssuanceTypeV1, discover_features::DiscoverFeaturesTypeV1, - notification::NotificationTypeV1, out_of_band::OutOfBandTypeV1, - present_proof::PresentProofTypeV1, report_problem::ReportProblemTypeV1, - revocation::RevocationTypeV2, routing::RoutingTypeV1, signature::SignatureTypeV1, + basic_message::BasicMessageTypeV1, + connection::ConnectionTypeV1, + cred_issuance::{CredentialIssuanceTypeV1, CredentialIssuanceTypeV2}, + discover_features::DiscoverFeaturesTypeV1, + notification::NotificationTypeV1, + out_of_band::OutOfBandTypeV1, + present_proof::PresentProofTypeV1, + report_problem::ReportProblemTypeV1, + revocation::RevocationTypeV2, + routing::RoutingTypeV1, + signature::SignatureTypeV1, trust_ping::TrustPingTypeV1, }; type RegistryMap = HashMap<(&'static str, u8), Vec>; @@ -75,6 +81,7 @@ lazy_static! { map_insert(&mut m, extract_parts!(ConnectionTypeV1::new_v1_0())); map_insert(&mut m, extract_parts!(SignatureTypeV1::new_v1_0())); map_insert(&mut m, extract_parts!(CredentialIssuanceTypeV1::new_v1_0())); + map_insert(&mut m, extract_parts!(CredentialIssuanceTypeV2::new_v2_0())); map_insert(&mut m, extract_parts!(DiscoverFeaturesTypeV1::new_v1_0())); map_insert(&mut m, extract_parts!(NotificationTypeV1::new_v1_0())); map_insert(&mut m, extract_parts!(OutOfBandTypeV1::new_v1_1()));