Skip to content

Commit

Permalink
finish some TODOs, and add doc metadata
Browse files Browse the repository at this point in the history
Signed-off-by: George Mulhearn <[email protected]>
  • Loading branch information
gmulhearn-anonyome committed Nov 26, 2024
1 parent 8ae721c commit c9464cb
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 25 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions did_core/did_methods/did_cheqd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ serde_json = "1.0.96"
serde = { version = "1.0.160", features = ["derive"] }
thiserror = "1.0.40"
tokio = { version = "1.38.0" }
chrono = { version = "0.4.24", default-features = false }
url = { version = "2.3.1", default-features = false }

[dev-dependencies]
tokio = { version = "1.38.0", default-features = false, features = [
Expand Down
14 changes: 14 additions & 0 deletions did_core/did_methods/did_cheqd/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ pub type DidCheqdResult<T> = Result<T, DidCheqdError>;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum DidCheqdError {
#[error("DID method not supported: {0}")]
MethodNotSupported(String),
#[error("Cheqd network not supported: {0}")]
NetworkNotSupported(String),
#[error("Bad configuration: {0}")]
BadConfiguration(String),
#[error("Transport error: {0}")]
TransportError(#[from] tonic::transport::Error),
#[error("Non-success resolver response: {0}")]
NonSuccessResponse(#[from] tonic::Status),
#[error("Response from resolver is invalid: {0}")]
InvalidResponse(String),
#[error("Invalid DID Document structure resolved: {0}")]
InvalidDidDocument(String),
#[error("Parsing error: {0}")]
ParsingError(#[from] ParsingErrorSource),
#[error(transparent)]
Expand Down
16 changes: 16 additions & 0 deletions did_core/did_methods/did_cheqd/src/error/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ pub enum ParsingErrorSource {
DidDocumentParsingUriError(#[from] UriWrapperError),
#[error("JSON parsing error: {0}")]
JsonError(#[from] serde_json::Error),
#[error("Invalid URL: {0}")]
UrlParsingError(url::ParseError),
#[error("Invalid encoding: {0}")]
Utf8Error(#[from] std::string::FromUtf8Error),
#[error("Invalid encoding: {0}")]
IntConversionError(#[from] std::num::TryFromIntError),
}

impl From<did_parser_nom::ParseError> for DidCheqdError {
Expand All @@ -33,8 +37,20 @@ impl From<serde_json::Error> for DidCheqdError {
}
}

impl From<url::ParseError> for DidCheqdError {
fn from(error: url::ParseError) -> Self {
DidCheqdError::ParsingError(ParsingErrorSource::UrlParsingError(error))
}
}

impl From<std::string::FromUtf8Error> for DidCheqdError {
fn from(error: std::string::FromUtf8Error) -> Self {
DidCheqdError::ParsingError(ParsingErrorSource::Utf8Error(error))
}
}

impl From<std::num::TryFromIntError> for DidCheqdError {
fn from(error: std::num::TryFromIntError) -> Self {
DidCheqdError::ParsingError(ParsingErrorSource::IntConversionError(error))
}
}
41 changes: 25 additions & 16 deletions did_core/did_methods/did_cheqd/src/resolution/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ use did_resolver::{
did_doc::schema::did_doc::DidDocument,
did_parser_nom::Did,
error::GenericError,
shared_types::did_document_metadata::DidDocumentMetadata,
traits::resolvable::{resolution_output::DidResolutionOutput, DidResolvable},
};
use tokio::sync::Mutex;
use tonic::transport::{Channel, Endpoint};

use crate::{
error::DidCheqdResult,
error::{DidCheqdError, DidCheqdResult},
proto::cheqd::{
did::v2::{query_client::QueryClient as DidQueryClient, QueryDidDocRequest},
resource::v2::query_client::QueryClient as ResourceQueryClient,
Expand Down Expand Up @@ -79,8 +80,7 @@ impl DidResolvable for DidCheqdResolver {
did: &Did,
_: &Self::DidResolutionOptions,
) -> Result<DidResolutionOutput, GenericError> {
let doc = self.resolve_did(did).await?;
Ok(DidResolutionOutput::builder(doc).build())
Ok(self.resolve_did(did).await?)
}
}

Expand All @@ -103,14 +103,13 @@ impl DidCheqdResolver {
.networks
.iter()
.find(|n| n.namespace == network)
.unwrap(); // TODO
.ok_or(DidCheqdError::NetworkNotSupported(network.to_owned()))?;

// initialize new
let conn = Endpoint::new(network_config.grpc_url.clone())
.unwrap() // TODO
.map_err(|e| DidCheqdError::BadConfiguration(e.to_string()))?
.connect()
.await
.unwrap(); // TODO
.await?;

let did_client = DidQueryClient::new(conn.clone());
let resource_client = ResourceQueryClient::new(conn);
Expand All @@ -125,21 +124,31 @@ impl DidCheqdResolver {
Ok(client)
}

pub async fn resolve_did(&self, did: &Did) -> DidCheqdResult<DidDocument> {
pub async fn resolve_did(&self, did: &Did) -> DidCheqdResult<DidResolutionOutput> {
let network = did.namespace().unwrap_or(MAINNET_NAMESPACE);
let mut client = self.client_for_network(network).await.unwrap();
// TODO - mainnet vs testnet
// TODO - return doc metadata
// TODO - doc versions
let mut client = self.client_for_network(network).await?;
let did = did.did().to_owned();

let request = tonic::Request::new(QueryDidDocRequest { id: did });
let response = client.did.did_doc(request).await.unwrap();
let response = client.did.did_doc(request).await?;

let query_response = response.into_inner();
let query_doc_res = query_response.value.unwrap(); // TODO
let query_doc = query_doc_res.did_doc.unwrap(); // TODO
let query_doc_res = query_response.value.ok_or(DidCheqdError::InvalidResponse(
"DIDDoc query did not return a value".into(),
))?;
dbg!(&query_doc_res);
let query_doc = query_doc_res.did_doc.ok_or(DidCheqdError::InvalidResponse(
"DIDDoc query did not return a DIDDoc".into(),
))?;

let mut output_builder = DidResolutionOutput::builder(DidDocument::try_from(query_doc)?);

if let Some(query_metadata) = query_doc_res.metadata {
// FUTURE - append linked resources to metadata
output_builder = output_builder
.did_document_metadata(DidDocumentMetadata::try_from(query_metadata)?);
}

DidDocument::try_from(query_doc)
Ok(output_builder.build())
}
}
59 changes: 52 additions & 7 deletions did_core/did_methods/did_cheqd/src/resolution/transformer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::str::FromStr;

use chrono::{DateTime, Utc};
use did_resolver::{
did_doc::schema::{
contexts,
Expand All @@ -10,13 +11,14 @@ use did_resolver::{
verification_method::{PublicKeyField, VerificationMethod, VerificationMethodType},
},
did_parser_nom::Did,
shared_types::did_document_metadata::DidDocumentMetadata,
};
use serde_json::json;

use crate::{
error::DidCheqdError,
error::{DidCheqdError, DidCheqdResult},
proto::cheqd::did::v2::{
DidDoc as CheqdDidDoc, Service as CheqdService,
DidDoc as CheqdDidDoc, Metadata as CheqdDidDocMetadata, Service as CheqdService,
VerificationMethod as CheqdVerificationMethod,
},
};
Expand Down Expand Up @@ -96,7 +98,6 @@ impl TryFrom<CheqdVerificationMethod> for VerificationMethod {

let vm_key_encoded = value.verification_material;

// TODO - lots of todo!()s
let pk = match vm_type {
VerificationMethodType::Ed25519VerificationKey2020 => PublicKeyField::Multibase {
public_key_multibase: vm_key_encoded,
Expand Down Expand Up @@ -132,9 +133,19 @@ impl TryFrom<CheqdVerificationMethod> for VerificationMethod {
public_key_pgp: vm_key_encoded,
},
// cannot infer encoding type from vm type, as multiple are supported: https://ns.did.ai/suites/secp256k1-2019/v1/
VerificationMethodType::EcdsaSecp256k1VerificationKey2019 => todo!(),
VerificationMethodType::EcdsaSecp256k1VerificationKey2019 => {
return Err(DidCheqdError::InvalidDidDocument(
"DidDocument uses VM type of EcdsaSecp256k1VerificationKey2019, cannot process"
.into(),
))
}
// cannot infer encoding type from vm type: https://identity.foundation/EcdsaSecp256k1RecoverySignature2020/lds-ecdsa-secp256k1-recovery2020-0.0.jsonld
VerificationMethodType::EcdsaSecp256k1RecoveryMethod2020 => todo!(),
VerificationMethodType::EcdsaSecp256k1RecoveryMethod2020 => {
return Err(DidCheqdError::InvalidDidDocument(
"DidDocument uses VM type of EcdsaSecp256k1RecoveryMethod2020, cannot process"
.into(),
))
}
};

let vm = VerificationMethod::builder()
Expand All @@ -153,15 +164,49 @@ impl TryFrom<CheqdService> for Service {

fn try_from(value: CheqdService) -> Result<Self, Self::Error> {
// TODO #1301 - fix mapping: https://github.com/hyperledger/aries-vcx/issues/1301
let endpoint = value.service_endpoint.into_iter().next().unwrap(); // TODO
let endpoint =
value
.service_endpoint
.into_iter()
.next()
.ok_or(DidCheqdError::InvalidDidDocument(
"DID Document Service is missing an endpoint".into(),
))?;

let svc = Service::new(
Uri::from_str(&value.id)?,
endpoint.parse().unwrap(), // TODO
endpoint.parse()?,
serde_json::from_value(json!(value.service_type))?,
Default::default(),
);

Ok(svc)
}
}

impl TryFrom<CheqdDidDocMetadata> for DidDocumentMetadata {
type Error = DidCheqdError;

fn try_from(value: CheqdDidDocMetadata) -> Result<Self, Self::Error> {
let mut builder = DidDocumentMetadata::builder();
if let Some(timestamp) = value.created {
builder = builder.created(prost_timestamp_to_dt(timestamp)?);
}
if let Some(timestamp) = value.updated {
builder = builder.updated(prost_timestamp_to_dt(timestamp)?);
}
builder = builder
.deactivated(value.deactivated)
.version_id(value.version_id)
.next_version_id(value.next_version_id);

Ok(builder.build())
}
}

fn prost_timestamp_to_dt(mut timestamp: prost_types::Timestamp) -> DidCheqdResult<DateTime<Utc>> {
timestamp.normalize();
DateTime::from_timestamp(timestamp.seconds, timestamp.nanos.try_into()?).ok_or(
DidCheqdError::Other(format!("Unknown error, bad timestamp: {timestamp:?}").into()),
)
}
7 changes: 5 additions & 2 deletions did_core/did_methods/did_cheqd/tests/resolution.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use did_cheqd::resolution::resolver::{DidCheqdResolver, DidCheqdResolverConfiguration};
use did_resolver::traits::resolvable::DidResolvable;
use serde_json::json;

#[tokio::test]
Expand Down Expand Up @@ -49,7 +50,8 @@ async fn test_resolve_known_mainnet_vector() {
});

let resolver = DidCheqdResolver::new(DidCheqdResolverConfiguration::default());
let doc = resolver.resolve_did(&did).await.unwrap();
let output = resolver.resolve(&did, &()).await.unwrap();
let doc = output.did_document;
assert_eq!(serde_json::to_value(doc.clone()).unwrap(), expected_doc);
assert_eq!(doc, serde_json::from_value(expected_doc).unwrap());
}
Expand Down Expand Up @@ -83,7 +85,8 @@ async fn test_resolve_known_testnet_vector() {
});

let resolver = DidCheqdResolver::new(DidCheqdResolverConfiguration::default());
let doc = resolver.resolve_did(&did).await.unwrap();
let output = resolver.resolve(&did, &()).await.unwrap();
let doc = output.did_document;
assert_eq!(serde_json::to_value(doc.clone()).unwrap(), expected_doc);
assert_eq!(doc, serde_json::from_value(expected_doc).unwrap());
}

0 comments on commit c9464cb

Please sign in to comment.