Skip to content

Commit

Permalink
WIP: Acapy interop in progress
Browse files Browse the repository at this point in the history
Signed-off-by: Miroslav Kovar <miroslav.kovar@absa.africa>
  • Loading branch information
mirgee committed Aug 22, 2023
1 parent 7dd93cc commit cee9b94
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 65 deletions.
54 changes: 46 additions & 8 deletions agents/rust/aries-vcx-agent/src/services/did_exchange.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use std::sync::Arc;

use aries_vcx::{
core::profile::profile::Profile,
did_doc_sov::extra_fields::KeyKind,
messages::msg_fields::protocols::{
did_exchange::{complete::Complete, request::Request, response::Response},
out_of_band::invitation::Invitation as OobInvitation,
out_of_band::invitation::{Invitation as OobInvitation, OobService},
},
protocols::{
connection::wrap_and_send_msg,
did_exchange::service::{
did_exchange::state_machine::{
generic::{GenericDidExchange, ThinState},
requester::{ConstructRequestConfig, PairwiseConstructRequestConfig, PublicConstructRequestConfig},
responder::ReceiveRequestConfig,
Expand Down Expand Up @@ -61,7 +62,13 @@ impl ServiceDidExchange {
wrap_and_send_msg(
&self.profile.inject_wallet(),
&request.clone().into(),
&requester.our_verkey().base58(),
&requester
.our_did_document()
.resolved_key_agreement()
.next()
.unwrap()
.public_key()?
.base58(),
&from_did_doc_sov_to_legacy(requester.their_did_doc().clone())?,
&HttpClient,
)
Expand All @@ -75,14 +82,21 @@ impl ServiceDidExchange {
ledger: self.profile.inject_indy_ledger_read(),
wallet: self.profile.inject_wallet(),
invitation: invitation.clone(),
resolver_registry: self.resolver_registry.clone(),
service_endpoint: self.service_endpoint.clone(),
routing_keys: vec![],
});
let (requester, request) = GenericDidExchange::construct_request(config).await?;
wrap_and_send_msg(
&self.profile.inject_wallet(),
&request.clone().into(),
&requester.our_verkey().base58(),
&requester
.our_did_document()
.resolved_key_agreement()
.next()
.unwrap()
.public_key()?
.base58(),
&from_did_doc_sov_to_legacy(requester.their_did_doc().clone())?,
&HttpClient,
)
Expand All @@ -91,24 +105,42 @@ impl ServiceDidExchange {
self.did_exchange.insert(&request_id, requester.clone().into())
}

pub async fn send_response(&self, request: Request, invitation_id: String) -> AgentResult<String> {
pub async fn send_response(&self, request: Request, invitation: OobInvitation) -> AgentResult<String> {
// TODO: We should fetch the out of band invite associated with the request.
// We don't want to be sending response if we don't know if there is any invitation
// associated with the request.
let request_id = request.clone().decorators.thread.unwrap().thid;
let invitation_key = match invitation.content.services.get(0).unwrap() {
OobService::SovService(service) => match service.extra().first_recipient_key()? {
KeyKind::DidKey(did_key) => did_key.key().to_owned(),
KeyKind::Value(key_value) => todo!("Legacy - parse key value {key_value} as base58 encoded key"),
KeyKind::Reference(reference) => unimplemented!("Can't resolve reference without a DDO: {reference}"),
},
OobService::Did(did) => {
todo!("Resolve the thing and extract key from DDO");
}
OobService::AriesService(_) => todo!(),
};
let (responder, response) = GenericDidExchange::handle_request(ReceiveRequestConfig {
wallet: self.profile.inject_wallet(),
resolver_registry: self.resolver_registry.clone(),
request,
service_endpoint: self.service_endpoint.clone(),
routing_keys: vec![],
invitation_id,
invitation_id: invitation.id.clone(),
invitation_key,
})
.await?;
wrap_and_send_msg(
&self.profile.inject_wallet(),
&response.clone().into(),
&responder.our_verkey().base58(),
&responder
.our_did_document()
.resolved_key_agreement()
.next()
.unwrap()
.public_key()?
.base58(),
&from_did_doc_sov_to_legacy(responder.their_did_doc().clone())?,
&HttpClient,
)
Expand All @@ -121,7 +153,13 @@ impl ServiceDidExchange {
wrap_and_send_msg(
&self.profile.inject_wallet(),
&complete.clone().into(),
&requester.our_verkey().base58(),
&requester
.our_did_document()
.resolved_key_agreement()
.next()
.unwrap()
.public_key()?
.base58(),
&from_did_doc_sov_to_legacy(requester.their_did_doc().clone())?,
&HttpClient,
)
Expand Down
66 changes: 36 additions & 30 deletions aries_vcx/src/protocols/did_exchange/state_machine/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use std::{collections::HashMap, sync::Arc};

use aries_vcx_core::wallet::base_wallet::BaseWallet;
use did_doc::schema::verification_method::{VerificationMethod, VerificationMethodKind, VerificationMethodType};
use did_doc::schema::{
types::uri::Uri,
verification_method::{VerificationMethod, VerificationMethodKind, VerificationMethodType},
};
use did_doc_sov::{
extra_fields::{didcommv1::ExtraFieldsDidCommV1, KeyKind},
service::{didcommv1::ServiceDidCommV1, ServiceSov},
DidDocumentSov,
};
use did_key::DidKey;
use did_parser::Did;
use did_parser::{Did, DidUrl};
use did_peer::peer_did::generate::generate_numalgo2;
use diddoc_legacy::aries::diddoc::AriesDidDoc;
use messages::decorators::attachment::{Attachment, AttachmentData, AttachmentType};
Expand Down Expand Up @@ -36,11 +39,7 @@ pub fn construct_service(
.set_routing_keys(routing_keys)
.set_recipient_keys(recipient_keys)
.build();
let service = ServiceSov::DIDCommV1(ServiceDidCommV1::new(
Default::default(),
service_endpoint.into(),
extra,
)?);
let service = ServiceSov::DIDCommV1(ServiceDidCommV1::new(Uri::new("#0")?, service_endpoint.into(), extra)?);
Ok(service)
}

Expand All @@ -58,35 +57,40 @@ pub async fn create_our_did_document(
)?;

// TODO: Make it easier to generate peer did from keys and service, and generate DDO from it
let did_document_temp = did_doc_from_keys(Default::default(), key_ver.clone(), key_enc.clone(), service.clone());
let did_document_temp = did_doc_from_keys(Default::default(), key_ver.clone(), key_enc.clone(), service.clone())?;
let peer_did = generate_numalgo2(did_document_temp.into())?;
let vm_id = peer_did.to_numalgo3();

Ok((
did_doc_from_keys(peer_did.clone().into(), key_ver, key_enc.clone(), service),
did_doc_from_keys(peer_did.clone().into(), key_ver, key_enc.clone(), service)?,
key_enc,
))
}

pub fn did_doc_from_keys(did: Did, key_ver: Key, key_enc: Key, service: ServiceSov) -> DidDocumentSov {
fn did_doc_from_keys(
did: Did,
key_ver: Key,
key_enc: Key,
service: ServiceSov,
) -> Result<DidDocumentSov, AriesVcxError> {
let vm_ver_id = DidUrl::from_fragment(key_ver.short_prefixless_fingerprint())?;
let vm_ka_id = DidUrl::from_fragment(key_enc.short_prefixless_fingerprint())?;
let vm_ver = VerificationMethod::builder(
did.clone().into(),
vm_ver_id,
did.clone(),
VerificationMethodType::Ed25519VerificationKey2020,
)
.add_public_key_base58(key_ver.base58())
.build();
let vm_ka = VerificationMethod::builder(
did.clone().into(),
did.clone(),
VerificationMethodType::X25519KeyAgreementKey2020,
)
.add_public_key_base58(key_enc.base58())
.build();
DidDocumentSov::builder(did)
let vm_ka = VerificationMethod::builder(vm_ka_id, did.clone(), VerificationMethodType::X25519KeyAgreementKey2020)
.add_public_key_base58(key_enc.base58())
.build();
Ok(DidDocumentSov::builder(did)
.add_service(service)
.add_verification_method(vm_ver.clone())
// TODO: Include just reference
.add_key_agreement(VerificationMethodKind::Resolved(vm_ka))
.build()
.build())
}

pub fn ddo_sov_to_attach(ddo: DidDocumentSov) -> Result<Attachment, AriesVcxError> {
Expand Down Expand Up @@ -154,16 +158,18 @@ pub fn attach_to_ddo_sov(attachment: Attachment) -> Result<DidDocumentSov, Aries
})?;
// TODO: Try to make DidDocumentSov support the legacy DDO if possible - would make
// integration of DidDocument much easier
if let Ok(ddo) = serde_json::from_slice::<DidDocumentSov>(&bytes) {
Ok(ddo)
} else {
let res: AriesDidDoc = serde_json::from_slice(&bytes).map_err(|err| {
AriesVcxError::from_msg(
AriesVcxErrorKind::SerializationError,
format!("Attachment is not base 64 encoded JSON: {attachment:?}, err: {err:?}"),
)
})?;
from_legacy_did_doc_to_sov(res)
match serde_json::from_slice::<DidDocumentSov>(&bytes) {
Ok(ddo) => Ok(ddo),
Err(err) => {
println!("Error deserializing to new DDO: {err}");
let res: AriesDidDoc = serde_json::from_slice(&bytes).map_err(|err| {
AriesVcxError::from_msg(
AriesVcxErrorKind::SerializationError,
format!("Attachment is not base 64 encoded JSON: {attachment:?}, err: {err:?}"),
)
})?;
from_legacy_did_doc_to_sov(res)
}
}
}
_ => Err(AriesVcxError::from_msg(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,7 @@ impl DidExchangeRequester<RequestSent> {
let (our_did_document, _) = did_doc_from_did(&ledger, our_did.clone()).await?;
let invitation_id = format!("{}#{}", their_did, service.id().to_string());

let key = Key::new(
our_did_document
.verification_method()
.first()
.unwrap()
.public_key()
.key_decoded()?,
KeyType::Ed25519,
)?;
let key = our_did_document.verification_method().first().unwrap().public_key()?;
let signed_attach = jws_sign_attach(ddo_sov_to_attach(our_did_document.clone())?, key, &wallet).await?;
let request = construct_request(invitation_id.clone(), our_did.to_string(), Some(signed_attach))?;

Expand All @@ -101,11 +93,7 @@ impl DidExchangeRequester<RequestSent> {
invitation_id,
},
their_did_document,
our_did_document, // Key::from_base58(
// &wallet.key_for_local_did(&our_did.id().to_string()).await?,
// KeyType::X25519,
// )?
// .clone(),
our_did_document,
),
output: request,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::sync::Arc;
use aries_vcx_core::wallet::base_wallet::BaseWallet;
use did_resolver_registry::ResolverRegistry;
use messages::msg_fields::protocols::did_exchange::request::Request;
use public_key::Key;
use url::Url;

pub struct ReceiveRequestConfig {
Expand All @@ -12,4 +13,5 @@ pub struct ReceiveRequestConfig {
pub service_endpoint: Url,
pub routing_keys: Vec<String>,
pub invitation_id: String,
pub invitation_key: Key,
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::sync::Arc;
use did_doc_sov::DidDocumentSov;
use did_resolver_registry::ResolverRegistry;
use messages::{
decorators::thread::Thread,
decorators::{attachment::Attachment, thread::Thread},
msg_fields::protocols::did_exchange::{
request::Request,
response::{Response, ResponseContent, ResponseDecorators},
Expand Down Expand Up @@ -40,10 +40,11 @@ pub fn construct_response(
our_did_document: DidDocumentSov,
invitation_id: String,
request_id: String,
attachment: Option<Attachment>,
) -> Result<Response, AriesVcxError> {
let content = ResponseContent {
did: our_did_document.id().to_string(),
did_doc: Some(ddo_sov_to_attach(our_did_document.clone())?),
did_doc: attachment,
};
let thread = {
let mut thread = Thread::new(request_id.clone());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use messages::msg_fields::protocols::did_exchange::{complete::Complete, response
use crate::{
errors::error::{AriesVcxError, AriesVcxErrorKind},
protocols::did_exchange::{
state_machine::helpers::create_our_did_document,
state_machine::helpers::{create_our_did_document, ddo_sov_to_attach, jws_sign_attach},
states::{completed::Completed, responder::response_sent::ResponseSent},
transition::{transition_error::TransitionError, transition_result::TransitionResult},
},
Expand All @@ -28,6 +28,7 @@ impl DidExchangeResponder<ResponseSent> {
service_endpoint,
routing_keys,
invitation_id,
invitation_key,
}: ReceiveRequestConfig,
) -> Result<TransitionResult<DidExchangeResponder<ResponseSent>, Response>, AriesVcxError> {
let their_ddo = resolve_their_ddo(&resolver_registry, &request).await?;
Expand All @@ -40,7 +41,15 @@ impl DidExchangeResponder<ResponseSent> {
));
}

let response = construct_response(our_did_document.clone(), invitation_id.clone(), request.id.clone())?;
let signed_attach =
jws_sign_attach(ddo_sov_to_attach(our_did_document.clone())?, invitation_key, &wallet).await?;

let response = construct_response(
our_did_document.clone(),
invitation_id.clone(),
request.id.clone(),
Some(signed_attach),
)?;

Ok(TransitionResult {
state: DidExchangeResponder::from_parts(
Expand Down
26 changes: 20 additions & 6 deletions aries_vcx/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ fn vm_method_type_to_key_type(vm_type: &VerificationMethodType) -> VcxResult<Key
}
}

// TODO: Get rid of this please!!!
pub fn from_did_doc_sov_to_legacy(ddo: DidDocumentSov) -> VcxResult<AriesDidDoc> {
let mut new_ddo = AriesDidDoc::default();
new_ddo.id = ddo.id().to_string();
Expand All @@ -138,13 +139,25 @@ pub fn from_did_doc_sov_to_legacy(ddo: DidDocumentSov) -> VcxResult<AriesDidDoc>
.clone()
.into(),
);
if let Some(vm) = ddo.verification_method().first() {
let key = Key::new(
vm.public_key().key_decoded()?,
vm_method_type_to_key_type(vm.verification_method_type())?,
)?;
new_ddo.set_recipient_keys(vec![key.base58()]);
let mut recipient_keys = vec![];
for ka in ddo.resolved_key_agreement() {
recipient_keys.push(ka.public_key()?.base58());
}
for service in ddo.service() {
if let Ok(key_kinds) = service.extra().recipient_keys() {
for key_kind in key_kinds {
match key_kind {
KeyKind::DidKey(key) => {
recipient_keys.push(key.key().base58());
}
KeyKind::Reference(_) => {}
KeyKind::Value(value) => todo!(),
}
}
}
}
new_ddo.set_recipient_keys(recipient_keys);
println!("Converted their ddo {ddo:?} to legacy ddo: {new_ddo:?}");
Ok(new_ddo)
}

Expand Down Expand Up @@ -233,5 +246,6 @@ pub fn from_service_sov_to_legacy(service: ServiceSov) -> AriesService {
..Default::default()
}
}
ServiceSov::Legacy(_) => todo!(),
}
}
4 changes: 4 additions & 0 deletions did_doc_sov/src/extra_fields/didcommv1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ use serde::{Deserialize, Serialize};

use super::{AcceptType, KeyKind};

// TODO: Remove these crazy defaults!!!
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct ExtraFieldsDidCommV1 {
#[serde(default)]
priority: u32,
#[serde(default)]
recipient_keys: Vec<KeyKind>,
#[serde(default)]
routing_keys: Vec<KeyKind>,
#[serde(default)]
accept: Vec<AcceptType>,
Expand Down
Loading

0 comments on commit cee9b94

Please sign in to comment.