From 43e3f2075cf82c26ebe1771b9ec651516ab67781 Mon Sep 17 00:00:00 2001 From: "artem.ivanov" Date: Wed, 17 Jun 2020 16:48:05 +0300 Subject: [PATCH] VCX: Strict Aries protocol Signed-off-by: artem.ivanov --- docs/configuration.md | 8 +- vcx/libvcx/src/credential.rs | 27 +++++- vcx/libvcx/src/disclosed_proof.rs | 15 +++ vcx/libvcx/src/issuer_credential.rs | 10 +- vcx/libvcx/src/messages/agent_utils.rs | 6 +- vcx/libvcx/src/messages/create_key.rs | 6 +- vcx/libvcx/src/messages/get_message.rs | 42 ++++++--- vcx/libvcx/src/messages/invite.rs | 21 +++-- vcx/libvcx/src/messages/message_type.rs | 3 +- vcx/libvcx/src/messages/mod.rs | 30 +++--- vcx/libvcx/src/messages/payload.rs | 6 +- vcx/libvcx/src/messages/send_message.rs | 6 +- vcx/libvcx/src/messages/update_connection.rs | 3 +- vcx/libvcx/src/messages/update_message.rs | 3 +- vcx/libvcx/src/messages/update_profile.rs | 3 +- vcx/libvcx/src/proof.rs | 12 +-- vcx/libvcx/src/settings.rs | 19 +++- .../proof_presentation/prover/prover.rs | 15 ++- .../proof_presentation/verifier/verifier.rs | 28 ++++-- vcx/wrappers/python3/demo/alice.py | 93 +++++++++---------- .../demo/alice_create_with_message_flow.py | 49 ++++++++++ .../demo/alice_create_with_message_id_flow.py | 49 ++++++++++ vcx/wrappers/python3/demo/demo_utils.py | 17 ++++ 23 files changed, 349 insertions(+), 122 deletions(-) create mode 100644 vcx/wrappers/python3/demo/alice_create_with_message_flow.py create mode 100644 vcx/wrappers/python3/demo/alice_create_with_message_id_flow.py diff --git a/docs/configuration.md b/docs/configuration.md index 8a4e0b66f6..ad883c6768 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -266,11 +266,15 @@ Almost all of them are optional and depend on the way you use Vcx (with agency o * `threadpool_size` - size of thread pool used for command execution (8 by default). -* `protocol_version` - message protocol to use for agent to agency and agent to agent communication. +* `protocol_type` - message protocol to use for agent to agency and agent to agent communication. Can be one of: * "1.0" - use bundled messages, auth/anon cryptography. * "2.0" - use aries cross domain message format, pack/unpack functions. - * "3.0" - use aries cross domain message format, pack/unpack functions and aries communication protocols (is alternative to the combination of settings "protocol_version":"2.0" and "communication_method":"aries"). + * "3.0" - use aries cross domain message format, pack/unpack functions and aries communication protocols + (is alternative to the combination of settings "protocol_version":"2.0" and "communication_method":"aries"). + Functions return messages in the `proprietary` format. + * "4.0" - use aries cross domain message format, pack/unpack functions and aries communication protocols. + Functions return messages in the `aries` format. * `author_agreement` - accept and use transaction author agreement data containing the following fields: * `acceptanceMechanismType` - (string) mechanism how user has accepted the TAA diff --git a/vcx/libvcx/src/credential.rs b/vcx/libvcx/src/credential.rs index e41c2c762d..d7ede3ba7a 100644 --- a/vcx/libvcx/src/credential.rs +++ b/vcx/libvcx/src/credential.rs @@ -1,4 +1,4 @@ -use serde_json; +use ::{serde_json, settings}; use serde_json::Value; use std::convert::TryInto; @@ -439,7 +439,7 @@ fn create_credential_v3(source_id: &str, offer: &str) -> VcxResult { // legacy offer format offer.pop() .ok_or(VcxError::from_msg(VcxErrorKind::InvalidJson, "Cannot get Credential Offer"))? - }, + } offer => offer //aries offer format }; @@ -455,6 +455,16 @@ fn create_credential_v3(source_id: &str, offer: &str) -> VcxResult VcxResult { trace!("credential_create_with_offer >>> source_id: {}, offer: {}", source_id, secret!(&offer)); + // strict aries protocol is set. Credential Offer must be in aries format + if settings::is_strict_aries_protocol_set() { + let cred_offer: CredentialOfferV3 = serde_json::from_str(offer) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, + format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Credential Offer: {}", err)))?; + + let holder = Holder::create(cred_offer, source_id)?; + return HANDLE_MAP.add(Credentials::V3(holder)); + } + let credential = match create_credential_v3(source_id, &offer)? { Some(credential) => credential, @@ -519,6 +529,12 @@ pub fn get_credential(handle: u32) -> VcxResult { } Credentials::V3(ref credential) => { let (cred_id, credential) = credential.get_credential()?; + + // strict aries protocol is set. Return aries formatted credential + if settings::is_strict_aries_protocol_set() { + return Ok(json!(credential).to_string()); + } + let credential: CredentialMessage = credential.try_into()?; let mut json = serde_json::Map::new(); @@ -676,6 +692,13 @@ pub fn get_credential_offer_messages(connection_handle: u32) -> VcxResult> = credential_offers .into_iter() .map(|credential_offer| credential_offer.try_into()) diff --git a/vcx/libvcx/src/disclosed_proof.rs b/vcx/libvcx/src/disclosed_proof.rs index 7130ebe0ed..a63ae9cd64 100644 --- a/vcx/libvcx/src/disclosed_proof.rs +++ b/vcx/libvcx/src/disclosed_proof.rs @@ -612,6 +612,16 @@ pub fn create_proof(source_id: &str, proof_req: &str) -> VcxResult { debug!("creating disclosed proof with id: {}", source_id); + // strict aries protocol is set. Presentation Request must be in aries format + if settings::is_strict_aries_protocol_set() { + let presentation_request: PresentationRequest = serde_json::from_str(proof_req) + .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, + format!("Strict `aries` protocol is enabled. Can not parse `aries` formatted Presentation Request: {}", err)))?; + + let proof = Prover::create(source_id, presentation_request)?; + return HANDLE_MAP.add(DisclosedProofs::V3(proof)); + } + let proof = match create_proof_v3(source_id, &proof_req)? { Some(proof) => proof, @@ -886,6 +896,11 @@ pub fn get_proof_request_messages(connection_handle: u32, match_name: Option<&st if connection::is_v3_connection(connection_handle)? { let presentation_requests = Prover::get_presentation_request_messages(connection_handle, match_name)?; + // strict aries protocol is set. return aries formatted Proof Request. + if settings::is_strict_aries_protocol_set() { + return Ok(json!(presentation_requests).to_string()); + } + let msgs: Vec = presentation_requests .into_iter() .map(|presentation_request| presentation_request.try_into()) diff --git a/vcx/libvcx/src/issuer_credential.rs b/vcx/libvcx/src/issuer_credential.rs index 747e04b8f4..c05737778e 100644 --- a/vcx/libvcx/src/issuer_credential.rs +++ b/vcx/libvcx/src/issuer_credential.rs @@ -661,11 +661,11 @@ pub fn issuer_credential_create(cred_def_handle: u32, trace!("issuer_credential_create >>> cred_def_handle: {}, source_id: {}, issuer_did: {}, credential_name: {}, credential_data: {}, price: {}", cred_def_handle, source_id, issuer_did, credential_name, secret!(&credential_data), price); -// // Initiate connection of new format -- redirect to v3 folder -// if settings::is_aries_protocol_set() { -// let issuer = v3::handlers::issuance::Issuer::create(cred_def_handle, &credential_data, &source_id)?; -// return ISSUER_CREDENTIAL_MAP.add(IssuerCredentials::V3(issuer)); -// } + // Initiate connection of new format -- redirect to v3 folder + if settings::is_strict_aries_protocol_set() { + let issuer = Issuer::create(cred_def_handle, &credential_data, &source_id)?; + return ISSUER_CREDENTIAL_MAP.add(IssuerCredentials::V3(issuer)); + } let issuer_credential = IssuerCredential::create(cred_def_handle, source_id, issuer_did, credential_name, credential_data, price)?; diff --git a/vcx/libvcx/src/messages/agent_utils.rs b/vcx/libvcx/src/messages/agent_utils.rs index d0e1d6d5ae..d08d405ba7 100644 --- a/vcx/libvcx/src/messages/agent_utils.rs +++ b/vcx/libvcx/src/messages/agent_utils.rs @@ -275,7 +275,8 @@ pub fn connect_register_provision(config: &str) -> VcxResult { let (agent_did, agent_vk) = match my_config.protocol_type { settings::ProtocolTypes::V1 => onboarding_v1(&my_did, &my_vk, &my_config.agency_did)?, settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3=> onboarding_v2(&my_did, &my_vk, &my_config.agency_did)?, + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => onboarding_v2(&my_did, &my_vk, &my_config.agency_did)?, }; let config = get_final_config(&my_did, &my_vk, &agent_did, &agent_vk, &wallet_name, &my_config)?; @@ -408,7 +409,8 @@ pub fn update_agent_info(id: &str, value: &str) -> VcxResult<()> { update_agent_info_v1(&to_did, com_method) } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { update_agent_info_v2(&to_did, com_method) } } diff --git a/vcx/libvcx/src/messages/create_key.rs b/vcx/libvcx/src/messages/create_key.rs index 27edb305ee..675da60a29 100644 --- a/vcx/libvcx/src/messages/create_key.rs +++ b/vcx/libvcx/src/messages/create_key.rs @@ -72,7 +72,8 @@ impl CreateKeyBuilder { match self.version { settings::ProtocolTypes::V1 => AgencyMock::set_next_response(constants::CREATE_KEYS_RESPONSE.to_vec()), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => AgencyMock::set_next_response(constants::CREATE_KEYS_V2_RESPONSE.to_vec()), + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => AgencyMock::set_next_response(constants::CREATE_KEYS_V2_RESPONSE.to_vec()), } } @@ -94,7 +95,8 @@ impl CreateKeyBuilder { }) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::CreateKey(CreateKey { msg_type: MessageTypes::MessageTypeV2(MessageTypes::build_v2(A2AMessageKinds::CreateKey)), diff --git a/vcx/libvcx/src/messages/get_message.rs b/vcx/libvcx/src/messages/get_message.rs index 669e861960..b05b1e204f 100644 --- a/vcx/libvcx/src/messages/get_message.rs +++ b/vcx/libvcx/src/messages/get_message.rs @@ -185,7 +185,8 @@ impl GetMessagesBuilder { self.pairwise_dids.clone())) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::GetMessages( GetMessages::build(A2AMessageKinds::GetMessagesByConnections, @@ -194,7 +195,6 @@ impl GetMessagesBuilder { self.status_codes.clone(), self.pairwise_dids.clone())) ), - }; let agency_did = settings::get_config_value(settings::CONFIG_REMOTE_TO_SDK_DID)?; @@ -247,7 +247,8 @@ impl GeneralMessage for GetMessagesBuilder { self.pairwise_dids.clone())) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::GetMessages( GetMessages::build(A2AMessageKinds::GetMessages, @@ -295,6 +296,18 @@ pub struct Message { pub decrypted_payload: Option, } +#[macro_export] +macro_rules! convert_aries_message { + ($message:ident, $target_type:ident, $kind:ident) => ( + if settings::is_strict_aries_protocol_set() { + (PayloadKinds::$kind, json!(&$message).to_string()) + } else { + let converted_message: $target_type = $message.try_into()?; + (PayloadKinds::$kind, json!(&converted_message).to_string()) + } + ) +} + impl Message { pub fn payload<'a>(&'a self) -> VcxResult> { match self.payload { @@ -331,6 +344,7 @@ impl Message { use v3::messages::a2a::A2AMessage; use v3::utils::encryption_envelope::EncryptionEnvelope; use ::issuer_credential::{CredentialOffer, CredentialMessage}; + use ::messages::proofs::proof_message::ProofMessage; use ::messages::payload::{PayloadTypes, PayloadV1, PayloadKinds}; use std::convert::TryInto; @@ -338,19 +352,21 @@ impl Message { let (kind, msg) = match a2a_message { A2AMessage::PresentationRequest(presentation_request) => { - let proof_req: ProofRequestMessage = presentation_request.try_into()?; - - (PayloadKinds::ProofRequest, json!(&proof_req).to_string()) + convert_aries_message!(presentation_request, ProofRequestMessage, ProofRequest) } A2AMessage::CredentialOffer(offer) => { - let cred_offer: CredentialOffer = offer.try_into()?; - - (PayloadKinds::CredOffer, json!(vec![cred_offer]).to_string()) + if settings::is_strict_aries_protocol_set() { + (PayloadKinds::CredOffer, json!(&offer).to_string()) + } else { + let cred_offer: CredentialOffer = offer.try_into()?; + (PayloadKinds::CredOffer, json!(vec![cred_offer]).to_string()) + } } A2AMessage::Credential(credential) => { - let credential: CredentialMessage = credential.try_into()?; - - (PayloadKinds::Cred, json!(&credential).to_string()) + convert_aries_message!(credential, CredentialMessage, Cred) + } + A2AMessage::Presentation(presentation) => { + convert_aries_message!(presentation, ProofMessage, Proof) } msg => { let msg = json!(&msg).to_string(); @@ -512,7 +528,7 @@ mod tests { assert_eq!(all_messages.len(), 1); let invalid_status_code = "abc".to_string(); - let bad_req = download_agent_messages(Some(vec![invalid_status_code]), None); + let bad_req = download_agent_messages(Some(vec![invalid_status_code]), None); assert!(bad_req.is_err()); } diff --git a/vcx/libvcx/src/messages/invite.rs b/vcx/libvcx/src/messages/invite.rs index 752fb284f2..1003346885 100644 --- a/vcx/libvcx/src/messages/invite.rs +++ b/vcx/libvcx/src/messages/invite.rs @@ -352,7 +352,8 @@ impl SendInviteBuilder { match self.version { settings::ProtocolTypes::V1 => AgencyMock::set_next_response(SEND_INVITE_RESPONSE.to_vec()), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => AgencyMock::set_next_response(SEND_INVITE_V2_RESPONSE.to_vec()), + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => AgencyMock::set_next_response(SEND_INVITE_V2_RESPONSE.to_vec()), } } @@ -372,7 +373,8 @@ impl SendInviteBuilder { // TODO: THINK better settings::ProtocolTypes::V1 => 1, settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => 0 + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => 0 }; match response.remove(index) { @@ -473,7 +475,8 @@ impl AcceptInviteBuilder { match self.version { settings::ProtocolTypes::V1 => AgencyMock::set_next_response(ACCEPT_INVITE_RESPONSE.to_vec()), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => AgencyMock::set_next_response(ACCEPT_INVITE_V2_RESPONSE.to_vec()), + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => AgencyMock::set_next_response(ACCEPT_INVITE_V2_RESPONSE.to_vec()), } } @@ -590,7 +593,8 @@ impl RedirectConnectionBuilder { match self.version { settings::ProtocolTypes::V1 => AgencyMock::set_next_response(ACCEPT_INVITE_RESPONSE.to_vec()), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => AgencyMock::set_next_response(ACCEPT_INVITE_V2_RESPONSE.to_vec()), + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => AgencyMock::set_next_response(ACCEPT_INVITE_V2_RESPONSE.to_vec()), } } @@ -651,7 +655,8 @@ impl GeneralMessage for SendInviteBuilder { A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::ConnectionRequest(details)))] } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { let msg = ConnectionRequest { msg_type: MessageTypes::build_v2(A2AMessageKinds::ConnectionRequest), send_msg: true, @@ -706,7 +711,8 @@ impl GeneralMessage for AcceptInviteBuilder { A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::ConnectionRequestAnswer(self.payload.clone())))] } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { let msg = ConnectionRequestAnswer { msg_type: MessageTypes::build_v2(A2AMessageKinds::ConnectionRequestAnswer), send_msg: true, @@ -761,7 +767,8 @@ impl GeneralMessage for RedirectConnectionBuilder { A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::ConnectionRequestRedirect(self.payload.clone())))] } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { let msg = ConnectionRequestRedirect { msg_type: MessageTypes::build_v2(A2AMessageKinds::ConnectionRequestRedirect), send_msg: true, diff --git a/vcx/libvcx/src/messages/message_type.rs b/vcx/libvcx/src/messages/message_type.rs index 5667d0bbed..6178107b10 100644 --- a/vcx/libvcx/src/messages/message_type.rs +++ b/vcx/libvcx/src/messages/message_type.rs @@ -37,7 +37,8 @@ impl MessageTypes { match settings::get_protocol_type() { settings::ProtocolTypes::V1 => MessageTypes::MessageTypeV1(MessageTypes::build_v1(kind)), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => MessageTypes::MessageTypeV2(MessageTypes::build_v2(kind)) + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => MessageTypes::MessageTypeV2(MessageTypes::build_v2(kind)) } } diff --git a/vcx/libvcx/src/messages/mod.rs b/vcx/libvcx/src/messages/mod.rs index d64045daac..a366e8b227 100644 --- a/vcx/libvcx/src/messages/mod.rs +++ b/vcx/libvcx/src/messages/mod.rs @@ -22,7 +22,7 @@ use self::update_profile::{UpdateProfileDataBuilder, UpdateConfigs, UpdateConfig use self::invite::{ SendInviteBuilder, ConnectionRequest, SendInviteMessageDetails, SendInviteMessageDetailsResponse, ConnectionRequestResponse, RedirectConnectionMessageDetails, ConnectionRequestRedirect, ConnectionRequestRedirectResponse, - AcceptInviteBuilder, RedirectConnectionBuilder, ConnectionRequestAnswer, AcceptInviteMessageDetails, ConnectionRequestAnswerResponse + AcceptInviteBuilder, RedirectConnectionBuilder, ConnectionRequestAnswer, AcceptInviteMessageDetails, ConnectionRequestAnswerResponse, }; use self::get_message::{GetMessagesBuilder, GetMessages, GetMessagesResponse, MessagesByConnections}; use self::send_message::SendMessageBuilder; @@ -451,7 +451,7 @@ impl<'de> Deserialize<'de> for A2AMessage { .map_err(de::Error::custom), MessageTypes::MessageTypeV2(_) => A2AMessageV2::deserialize(value) - .map(A2AMessage::Version2 ) + .map(A2AMessage::Version2) .map_err(de::Error::custom) } } @@ -490,7 +490,8 @@ impl Forward { ))) } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { let msg = serde_json::from_slice(msg.as_slice()) .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidState, err))?; @@ -537,7 +538,7 @@ pub struct GeneralMessageDetail { pub struct MessageCreated { #[serde(rename = "@type")] msg_type: MessageTypeV1, - pub uid: String + pub uid: String, } #[derive(Debug, Deserialize, Serialize)] @@ -627,7 +628,7 @@ impl<'de> Deserialize<'de> for RemoteMessageType { match value.as_str() { Some("connReq") => Ok(RemoteMessageType::ConnReq), Some("connReqAnswer") | Some("CONN_REQ_ACCEPTED") => Ok(RemoteMessageType::ConnReqAnswer), - Some("connReqRedirect") | Some("CONN_REQ_REDIRECTED") | Some("connReqRedirected") => Ok(RemoteMessageType::ConnReqRedirect), + Some("connReqRedirect") | Some("CONN_REQ_REDIRECTED") | Some("connReqRedirected") => Ok(RemoteMessageType::ConnReqRedirect), Some("credOffer") => Ok(RemoteMessageType::CredOffer), Some("credReq") => Ok(RemoteMessageType::CredReq), Some("cred") => Ok(RemoteMessageType::Cred), @@ -805,7 +806,8 @@ pub fn prepare_message_for_agency(message: &A2AMessage, agency_did: &str, versio match version { settings::ProtocolTypes::V1 => bundle_for_agency_v1(message, &agency_did), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => pack_for_agency_v2(message, agency_did) + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => pack_for_agency_v2(message, agency_did) } } @@ -842,7 +844,8 @@ fn parse_response_from_agency(response: &Vec, version: &ProtocolTypes) -> Vc match version { settings::ProtocolTypes::V1 => parse_response_from_agency_v1(response), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => parse_response_from_agency_v2(response) + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => parse_response_from_agency_v2(response) } } @@ -966,7 +969,8 @@ pub fn prepare_message_for_agent(messages: Vec, pw_vk: &str, agent_d match version { settings::ProtocolTypes::V1 => prepare_message_for_agent_v1(messages, pw_vk, agent_did, agent_vk), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => prepare_message_for_agent_v2(messages, pw_vk, agent_did, agent_vk) + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => prepare_message_for_agent_v2(messages, pw_vk, agent_did, agent_vk) } } @@ -1049,7 +1053,7 @@ pub trait GeneralMessage { #[derive(Debug, Serialize, Deserialize)] pub struct ObjectWithVersion<'a, T> { pub version: &'a str, - pub data: T + pub data: T, } impl<'a, 'de, T> ObjectWithVersion<'a, T> where T: ::serde::Serialize + ::serde::de::DeserializeOwned { @@ -1126,11 +1130,11 @@ pub mod tests { let details = GeneralMessageDetail { msg_type: MessageTypeV1 { name: "Name".to_string(), - ver: "1.0".to_string() + ver: "1.0".to_string(), }, msg: vec![1, 2, 3], title: None, - detail: None + detail: None, }; let string: String = serde_json::to_string(&details).unwrap(); @@ -1145,12 +1149,12 @@ pub mod tests { let details = CreateMessage { msg_type: MessageTypeV1 { name: "Name".to_string(), - ver: "1.0".to_string() + ver: "1.0".to_string(), }, mtype: RemoteMessageType::ProofReq, send_msg: true, uid: None, - reply_to_msg_id: None + reply_to_msg_id: None, }; let string: String = serde_json::to_string(&details).unwrap(); diff --git a/vcx/libvcx/src/messages/payload.rs b/vcx/libvcx/src/messages/payload.rs index 2869297769..05f2e931b1 100644 --- a/vcx/libvcx/src/messages/payload.rs +++ b/vcx/libvcx/src/messages/payload.rs @@ -65,7 +65,8 @@ impl Payloads { crypto::prep_msg(&my_vk, &their_vk, &bytes) } ProtocolTypes::V2 | - ProtocolTypes::V3 => { + ProtocolTypes::V3 | + ProtocolTypes::V4 => { let thread = thread.ok_or(VcxError::from_msg(VcxErrorKind::InvalidState, "Thread info not found"))?; let payload = PayloadV2 { @@ -210,7 +211,8 @@ impl PayloadKinds { } } ProtocolTypes::V2 | - ProtocolTypes::V3 => { + ProtocolTypes::V3 | + ProtocolTypes::V4 => { match self { PayloadKinds::CredOffer => "credential-offer", PayloadKinds::CredReq => "credential-request", diff --git a/vcx/libvcx/src/messages/send_message.rs b/vcx/libvcx/src/messages/send_message.rs index 53dd9d4b4d..e9d943b12b 100644 --- a/vcx/libvcx/src/messages/send_message.rs +++ b/vcx/libvcx/src/messages/send_message.rs @@ -121,7 +121,8 @@ impl SendMessageBuilder { 1 } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => 0 + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => 0 }; match response.remove(index) { @@ -164,7 +165,8 @@ impl GeneralMessage for SendMessageBuilder { A2AMessage::Version1(A2AMessageV1::MessageDetail(MessageDetail::General(detail)))] } settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => { + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => { let msg: ::serde_json::Value = ::serde_json::from_slice(self.payload.as_slice()) .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidState, err))?; diff --git a/vcx/libvcx/src/messages/update_connection.rs b/vcx/libvcx/src/messages/update_connection.rs index 9442539dca..2d87cab647 100644 --- a/vcx/libvcx/src/messages/update_connection.rs +++ b/vcx/libvcx/src/messages/update_connection.rs @@ -147,7 +147,8 @@ impl GeneralMessage for DeleteConnectionBuilder { ) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::UpdateConnection( UpdateConnection { diff --git a/vcx/libvcx/src/messages/update_message.rs b/vcx/libvcx/src/messages/update_message.rs index 3016baec3e..e0806f6276 100644 --- a/vcx/libvcx/src/messages/update_message.rs +++ b/vcx/libvcx/src/messages/update_message.rs @@ -94,7 +94,8 @@ impl UpdateMessageStatusByConnectionsBuilder { ) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::UpdateMessageStatusByConnections( UpdateMessageStatusByConnections { diff --git a/vcx/libvcx/src/messages/update_profile.rs b/vcx/libvcx/src/messages/update_profile.rs index fe70bbe09d..d0c9dfc13d 100644 --- a/vcx/libvcx/src/messages/update_profile.rs +++ b/vcx/libvcx/src/messages/update_profile.rs @@ -114,7 +114,8 @@ impl UpdateProfileDataBuilder { ) ), settings::ProtocolTypes::V2 | - settings::ProtocolTypes::V3 => + settings::ProtocolTypes::V3 | + settings::ProtocolTypes::V4 => A2AMessage::Version2( A2AMessageV2::UpdateConfigs( UpdateConfigs { diff --git a/vcx/libvcx/src/proof.rs b/vcx/libvcx/src/proof.rs index 783801498b..07cefc9eb3 100644 --- a/vcx/libvcx/src/proof.rs +++ b/vcx/libvcx/src/proof.rs @@ -474,12 +474,12 @@ pub fn create_proof(source_id: String, requested_predicates: String, revocation_details: String, name: String) -> VcxResult { -// // Initiate proof of new format -- redirect to v3 folder -// if settings::is_aries_protocol_set() { -// let verifier = Verifier::create(source_id, requested_attrs, requested_predicates, revocation_details, name)?; -// return PROOF_MAP.add(Proofs::V3(verifier)) -// .or(Err(VcxError::from(VcxErrorKind::CreateProof))); -// } + + // strict aries protocol is set. Initiate proof of new format -- redirect to v3 folder + if settings::is_strict_aries_protocol_set() { + let verifier = Verifier::create(source_id, requested_attrs, requested_predicates, revocation_details, name)?; + return PROOF_MAP.add(Proofs::V3(verifier)) + } trace!("create_proof >>> source_id: {}, requested_attrs: {}, requested_predicates: {}, name: {}", source_id, requested_attrs, requested_predicates, name); diff --git a/vcx/libvcx/src/settings.rs b/vcx/libvcx/src/settings.rs index b3e687e37b..4cab041f85 100644 --- a/vcx/libvcx/src/settings.rs +++ b/vcx/libvcx/src/settings.rs @@ -266,7 +266,7 @@ pub fn set_config_value(key: &str, value: &str) { pub fn get_wallet_name() -> VcxResult { get_config_value(CONFIG_WALLET_NAME) - .map_err(|_|VcxError::from(VcxErrorKind::MissingWalletKey)) + .map_err(|_| VcxError::from(VcxErrorKind::MissingWalletKey)) } pub fn get_threadpool_size() -> usize { @@ -314,7 +314,7 @@ pub fn get_opt_config_value(key: &str) -> Option { pub fn set_opt_config_value(key: &str, value: &Option) { if let Some(v) = value { - set_config_value(key, v.as_str()) + set_config_value(key, v.as_str()) } } @@ -361,8 +361,15 @@ pub fn get_communication_method() -> VcxResult { } pub fn is_aries_protocol_set() -> bool { - get_protocol_type() == ProtocolTypes::V2 && ARIES_COMMUNICATION_METHOD == get_communication_method().unwrap_or_default() || - get_protocol_type() == ProtocolTypes::V3 + let protocol_type = get_protocol_type(); + + protocol_type == ProtocolTypes::V2 && ARIES_COMMUNICATION_METHOD == get_communication_method().unwrap_or_default() || + protocol_type == ProtocolTypes::V3 || + protocol_type == ProtocolTypes::V4 +} + +pub fn is_strict_aries_protocol_set() -> bool { + get_protocol_type() == ProtocolTypes::V4 } pub fn get_actors() -> Vec { @@ -397,6 +404,8 @@ pub enum ProtocolTypes { V2, #[serde(rename = "3.0")] V3, + #[serde(rename = "4.0")] + V4, } impl Default for ProtocolTypes { @@ -411,6 +420,7 @@ impl From for ProtocolTypes { "1.0" => ProtocolTypes::V1, "2.0" => ProtocolTypes::V2, "3.0" => ProtocolTypes::V3, + "4.0" => ProtocolTypes::V4, type_ @ _ => { error!("Unknown protocol type: {:?}. Use default", type_); ProtocolTypes::default() @@ -425,6 +435,7 @@ impl ::std::string::ToString for ProtocolTypes { ProtocolTypes::V1 => "1.0".to_string(), ProtocolTypes::V2 => "2.0".to_string(), ProtocolTypes::V3 => "3.0".to_string(), + ProtocolTypes::V4 => "4.0".to_string(), } } } diff --git a/vcx/libvcx/src/v3/handlers/proof_presentation/prover/prover.rs b/vcx/libvcx/src/v3/handlers/proof_presentation/prover/prover.rs index ab83ffc179..3aeddb46d4 100644 --- a/vcx/libvcx/src/v3/handlers/proof_presentation/prover/prover.rs +++ b/vcx/libvcx/src/v3/handlers/proof_presentation/prover/prover.rs @@ -9,7 +9,7 @@ use v3::handlers::proof_presentation::prover::messages::ProverMessages; use v3::messages::a2a::{A2AMessage, MessageId}; use v3::messages::proof_presentation::presentation_proposal::PresentationPreview; use v3::messages::proof_presentation::presentation_request::PresentationRequest; -use connection; +use ::{connection, settings}; use messages::proofs::proof_message::ProofMessage; @@ -54,10 +54,17 @@ impl Prover { pub fn generate_presentation_msg(&self) -> VcxResult { trace!("Prover::generate_presentation_msg >>>"); - let proof: ProofMessage = self.prover_sm.presentation()?.clone().try_into()?; + let proof = self.prover_sm.presentation()?.to_owned(); - ::serde_json::to_string(&proof) - .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize ProofMessage: {:?}", err))) + // strict aries protocol is set. return aries formatted Proof + if settings::is_strict_aries_protocol_set() { + return Ok(json!(proof).to_string()) + } + + // convert Proof into proprietary format + let proof: ProofMessage = proof.try_into()?; + + return Ok(json!(proof).to_string()) } pub fn set_presentation(&mut self, presentation: Presentation) -> VcxResult<()> { diff --git a/vcx/libvcx/src/v3/handlers/proof_presentation/verifier/verifier.rs b/vcx/libvcx/src/v3/handlers/proof_presentation/verifier/verifier.rs index 8d731ebbcb..16eef8549b 100644 --- a/vcx/libvcx/src/v3/handlers/proof_presentation/verifier/verifier.rs +++ b/vcx/libvcx/src/v3/handlers/proof_presentation/verifier/verifier.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use messages::get_message::Message; -use connection; +use ::{connection, settings}; use v3::messages::proof_presentation::presentation_request::*; use v3::messages::proof_presentation::presentation::Presentation; use v3::handlers::proof_presentation::verifier::states::VerifierSM; @@ -106,19 +106,33 @@ impl Verifier { pub fn generate_presentation_request_msg(&self) -> VcxResult { trace!("Verifier::generate_presentation_request_msg >>>"); - let proof_request: ProofRequestMessage = self.verifier_sm.presentation_request()?.try_into()?; + let proof_request = self.verifier_sm.presentation_request()?; - ::serde_json::to_string(&proof_request) - .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize ProofMessage: {:?}", err))) + // strict aries protocol is set. return aries formatted Proof Request + if settings::is_strict_aries_protocol_set() { + return Ok(json!(proof_request).to_string()) + } + + // convert Proof Request into proprietary format + let proof_request: ProofRequestMessage = proof_request.try_into()?; + + return Ok(json!(proof_request).to_string()) } pub fn get_presentation(&self) -> VcxResult { trace!("Verifier::get_presentation >>>"); - let proof: ProofMessage = self.verifier_sm.presentation()?.try_into()?; + let proof = self.verifier_sm.presentation()?; + + // strict aries protocol is set. return aries formatted Proof + if settings::is_strict_aries_protocol_set() { + return Ok(json!(proof).to_string()) + } + + // convert Proof into proprietary format + let proof: ProofMessage = proof.try_into()?; - ::serde_json::to_string(&proof) - .map_err(|err| VcxError::from_msg(VcxErrorKind::InvalidJson, format!("Cannot serialize ProofMessage: {:?}", err))) + return Ok(json!(proof).to_string()) } pub fn step(&mut self, message: VerifierMessages) -> VcxResult<()> { diff --git a/vcx/wrappers/python3/demo/alice.py b/vcx/wrappers/python3/demo/alice.py index b7921ca34b..f9f3dc649a 100644 --- a/vcx/wrappers/python3/demo/alice.py +++ b/vcx/wrappers/python3/demo/alice.py @@ -1,9 +1,7 @@ import asyncio import json -from ctypes import cdll from time import sleep -from demo_utils import file_ext from vcx.api.connection import Connection from vcx.api.credential import Credential from vcx.api.disclosed_proof import DisclosedProof @@ -23,32 +21,13 @@ 'wallet_key': '123', 'payment_method': 'null', 'enterprise_seed': '000000000000000000000000Trustee1', - 'protocol_type': '3.0', + 'protocol_type': '4.0', } async def main(): - payment_plugin = cdll.LoadLibrary('libnullpay' + file_ext()) - payment_plugin.nullpay_init() - - print("#7 Provision an agent and wallet, get back configuration details") - config = await vcx_agent_provision(json.dumps(provisionConfig)) - config = json.loads(config) - # Set some additional configuration options specific to alice - config['institution_name'] = 'alice' - config['institution_logo_url'] = 'http://robohash.org/456' - config['genesis_path'] = 'docker.txn' - config['payment_method'] = 'null' - - config = json.dumps(config) - - print('Alice config:\n ' + config) - - print("#8 Initialize libvcx with new configuration") - await vcx_init_with_config(config) - + await init() connection_to_faber = None - while True: answer = input( "Would you like to do? \n " @@ -59,41 +38,64 @@ async def main(): "else finish \n") \ .lower().strip() if answer == '0': - print("#9 Input faber.py invitation details") - details = input('invite details: ') - - print("#10 Convert to valid json and string and create a connection to faber") - jdetails = json.loads(details) - connection_to_faber = await Connection.create_with_details('faber', json.dumps(jdetails)) - await connection_to_faber.connect('{"use_public_did": true}') - connection_state = await connection_to_faber.update_state() - while connection_state != State.Accepted: - sleep(2) - await connection_to_faber.update_state() - connection_state = await connection_to_faber.get_state() - - print("Connection is established") + connection_to_faber = await connect() elif answer == '1': print("Check agency for a credential offer") offers = await Credential.get_offers(connection_to_faber) - await accept_offer(connection_to_faber, offers) + credential = await Credential.create('credential', offers[0]) + await accept_offer(connection_to_faber, credential) elif answer == '2': print("Check agency for a proof request") requests = await DisclosedProof.get_requests(connection_to_faber) - await create_proof(connection_to_faber, requests[0]) + print("#23 Create a Disclosed proof object from proof request") + proof = await DisclosedProof.create('proof', requests[0]) + await create_proof(connection_to_faber, proof) elif answer == '3': request = await handle_challenge() - await create_proof(None, request) + print("#23 Create a Disclosed proof object from proof request") + proof = await DisclosedProof.create('proof', request) + await create_proof(None, proof) else: break print("Finished") -async def accept_offer(connection_to_faber, offers): - # Create a credential object from the credential offer - credential = await Credential.create('credential', offers[0]) +async def init(): + print("#7 Provision an agent and wallet, get back configuration details") + config = await vcx_agent_provision(json.dumps(provisionConfig)) + config = json.loads(config) + # Set some additional configuration options specific to alice + config['institution_name'] = 'alice' + config['institution_logo_url'] = 'http://robohash.org/456' + config['genesis_path'] = 'docker.txn' + config['payment_method'] = 'null' + + config = json.dumps(config) + + print("#8 Initialize libvcx with new configuration") + await vcx_init_with_config(config) + +async def connect(): + print("#9 Input faber.py invitation details") + details = input('invite details: ') + + print("#10 Convert to valid json and string and create a connection to faber") + jdetails = json.loads(details) + connection_to_faber = await Connection.create_with_details('faber', json.dumps(jdetails)) + await connection_to_faber.connect('{"use_public_did": true}') + connection_state = await connection_to_faber.update_state() + while connection_state != State.Accepted: + sleep(2) + await connection_to_faber.update_state() + connection_state = await connection_to_faber.get_state() + + print("Connection is established") + return connection_to_faber + + +async def accept_offer(connection_to_faber, credential): print("#15 After receiving credential offer, send credential request") await credential.send_request(connection_to_faber, 0) @@ -105,10 +107,7 @@ async def accept_offer(connection_to_faber, offers): credential_state = await credential.get_state() -async def create_proof(connection_to_faber, request): - print("#23 Create a Disclosed proof object from proof request") - proof = await DisclosedProof.create('proof', request) - +async def create_proof(connection_to_faber, proof): print("#24 Query for credentials in the wallet that satisfy the proof request") credentials = await proof.get_creds() diff --git a/vcx/wrappers/python3/demo/alice_create_with_message_flow.py b/vcx/wrappers/python3/demo/alice_create_with_message_flow.py new file mode 100644 index 0000000000..3c15617e6b --- /dev/null +++ b/vcx/wrappers/python3/demo/alice_create_with_message_flow.py @@ -0,0 +1,49 @@ +import asyncio +import json + +from alice import init, connect, accept_offer, create_proof +from demo_utils import download_message, update_message_as_read + +from vcx import logging +from vcx.api.credential import Credential +from vcx.api.disclosed_proof import DisclosedProof + + + +async def main(): + await init() + connection_to_faber = None + while True: + answer = input( + "Would you like to do? \n " + "0 - establish connection \n " + "1 - check for credential offer \n " + "2 - check for proof request \n " + "else finish \n") \ + .lower().strip() + if answer == '0': + connection_to_faber = await connect() + elif answer == '1': + print("Check agency for a credential offer") + pw_did = await connection_to_faber.get_my_pw_did() + uid, offer, _ = await download_message(pw_did) + credential = await Credential.create('credential', json.loads(offer)) + await accept_offer(connection_to_faber, credential) + await update_message_as_read(pw_did, uid) + elif answer == '2': + print("Check agency for a proof request") + pw_did = await connection_to_faber.get_my_pw_did() + uid, request, _ = await download_message(pw_did) + print("#23 Create a Disclosed proof object from proof request") + proof = await DisclosedProof.create('proof', json.loads(request)) + await create_proof(connection_to_faber, proof) + await update_message_as_read(pw_did, uid) + else: + pass + # break + print("Finished") + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/vcx/wrappers/python3/demo/alice_create_with_message_id_flow.py b/vcx/wrappers/python3/demo/alice_create_with_message_id_flow.py new file mode 100644 index 0000000000..78af255dbf --- /dev/null +++ b/vcx/wrappers/python3/demo/alice_create_with_message_id_flow.py @@ -0,0 +1,49 @@ +import asyncio + +from alice import connect, accept_offer, create_proof, init +from demo_utils import download_message + +from vcx.api.credential import Credential +from vcx.api.disclosed_proof import DisclosedProof + + +# logging.basicConfig(level=0) + +async def main(): + await init() + connection_to_faber = None + while True: + answer = input( + "Would you like to do? \n " + "0 - establish connection \n " + "1 - check for credential offer \n " + "2 - check for proof request \n " + "else finish \n") \ + .lower().strip() + if answer == '0': + connection_to_faber = await connect() + elif answer == '1': + print("Check agency for a credential offer") + pw_did = await connection_to_faber.get_my_pw_did() + uid, offer, _ = await download_message(pw_did) + credential = await Credential.create_with_msgid('credential', connection_to_faber, uid) + print("Offer") + print(credential.cred_offer) + await accept_offer(connection_to_faber, credential) + elif answer == '2': + print("Check agency for a proof request") + pw_did = await connection_to_faber.get_my_pw_did() + uid, request, _ = await download_message(pw_did) + print("#23 Create a Disclosed proof object from proof request") + proof = await DisclosedProof.create_with_msgid('proof', connection_to_faber, uid) + await create_proof(connection_to_faber, proof) + else: + pass + # break + print(answer) + print("Finished") + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.run_until_complete(main()) diff --git a/vcx/wrappers/python3/demo/demo_utils.py b/vcx/wrappers/python3/demo/demo_utils.py index 25894d414c..448723c0a5 100644 --- a/vcx/wrappers/python3/demo/demo_utils.py +++ b/vcx/wrappers/python3/demo/demo_utils.py @@ -14,6 +14,7 @@ from vcx.api.proof import Proof from vcx.api.disclosed_proof import DisclosedProof from vcx.api.schema import Schema +from vcx.api.utils import vcx_messages_download, vcx_messages_update_status from vcx.state import State, ProofState @@ -268,6 +269,22 @@ async def create_postgres_wallet(provisionConfig): print("Postgres wallet provisioned") +async def download_message(pw_did: str): + messages = await vcx_messages_download("MS-103", None, pw_did) + message = json.loads(messages.decode())[0]['msgs'][0] + decryptedPayload = message["decryptedPayload"] + print(decryptedPayload) + return message["uid"], json.loads(decryptedPayload)["@msg"], json.dumps(message) + + +async def update_message_as_read(pw_did: str, uid: str): + messages_to_update = [{ + "pairwiseDID": pw_did, + "uids": [uid] + }] + await vcx_messages_update_status(json.dumps(messages_to_update)) + + def load_payment_library(): payment_plugin = cdll.LoadLibrary('libnullpay' + file_ext()) payment_plugin.nullpay_init()