diff --git a/did_doc/src/lib.rs b/did_doc/src/lib.rs index 248e82c6b5..6253bcfe61 100644 --- a/did_doc/src/lib.rs +++ b/did_doc/src/lib.rs @@ -3,3 +3,5 @@ extern crate serde_json; pub mod error; pub mod schema; + +pub use did_parser; diff --git a/did_doc/src/schema/did_doc.rs b/did_doc/src/schema/did_doc.rs index 84c478392e..60b0729425 100644 --- a/did_doc/src/schema/did_doc.rs +++ b/did_doc/src/schema/did_doc.rs @@ -4,6 +4,8 @@ use did_parser::{Did, DidUrl}; use serde::{Deserialize, Serialize}; use serde_json::Value; +use crate::error::DidDocumentBuilderError; + use super::{ service::Service, types::uri::Uri, @@ -16,7 +18,10 @@ type ControllerAlias = OneOrList; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] #[serde(default)] #[serde(rename_all = "camelCase")] -pub struct DidDocument { +pub struct DidDocument +where + E: Default, +{ id: Did, #[serde(skip_serializing_if = "Vec::is_empty")] also_known_as: Vec, @@ -35,14 +40,17 @@ pub struct DidDocument { #[serde(skip_serializing_if = "Vec::is_empty")] capability_delegation: Vec, #[serde(skip_serializing_if = "Vec::is_empty")] - service: Vec, + service: Vec>, #[serde(skip_serializing_if = "HashMap::is_empty")] #[serde(flatten)] extra: HashMap, } -impl DidDocument { - pub fn builder(id: Did) -> DidDocumentBuilder { +impl DidDocument +where + E: Default, +{ + pub fn builder(id: Did) -> DidDocumentBuilder { DidDocumentBuilder::new(id) } @@ -82,17 +90,24 @@ impl DidDocument { self.capability_delegation.as_ref() } - pub fn service(&self) -> &[Service] { + pub fn service(&self) -> &[Service] { self.service.as_ref() } pub fn extra_field(&self, key: &str) -> Option<&Value> { self.extra.get(key) } + + pub fn validate(&self) -> Result<(), DidDocumentBuilderError> { + Ok(()) + } } #[derive(Debug, Default)] -pub struct DidDocumentBuilder { +pub struct DidDocumentBuilder +where + E: Default, +{ id: Did, also_known_as: Vec, controller: Vec, @@ -102,11 +117,14 @@ pub struct DidDocumentBuilder { key_agreement: Vec, capability_invocation: Vec, capability_delegation: Vec, - service: Vec, + service: Vec>, extra: HashMap, } -impl DidDocumentBuilder { +impl DidDocumentBuilder +where + E: Default, +{ pub fn new(id: Did) -> Self { Self { id, @@ -189,7 +207,7 @@ impl DidDocumentBuilder { self } - pub fn add_service(mut self, service: Service) -> Self { + pub fn add_service(mut self, service: Service) -> Self { self.service.push(service); self } @@ -199,7 +217,7 @@ impl DidDocumentBuilder { self } - pub fn build(self) -> DidDocument { + pub fn build(self) -> DidDocument { let controller = if self.controller.is_empty() { None } else { @@ -249,7 +267,7 @@ mod tests { let service_id = Uri::new("did:example:123456789abcdefghi;service-1").unwrap(); let service_type = "test-service".to_string(); let service_endpoint = "https://example.com/service"; - let service = ServiceBuilder::new(service_id, service_endpoint.try_into().unwrap()) + let service = ServiceBuilder::<()>::new(service_id, service_endpoint.try_into().unwrap()) .unwrap() .add_service_type(service_type) .unwrap() diff --git a/did_doc/src/schema/service.rs b/did_doc/src/schema/service.rs index 51018cad65..0764d7c982 100644 --- a/did_doc/src/schema/service.rs +++ b/did_doc/src/schema/service.rs @@ -1,7 +1,6 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use serde::{Deserialize, Serialize}; -use serde_json::Value; use crate::error::DidDocumentBuilderError; @@ -14,22 +13,26 @@ type ServiceTypeAlias = OneOrList; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] -pub struct Service { +pub struct Service +where + E: Default, +{ id: Uri, #[serde(rename = "type")] service_type: ServiceTypeAlias, service_endpoint: Url, #[serde(flatten)] - #[serde(skip_serializing_if = "HashMap::is_empty")] - #[serde(default)] - extra: HashMap, + extra: E, } -impl Service { +impl Service +where + E: Default, +{ pub fn builder( id: Uri, service_endpoint: Url, - ) -> Result { + ) -> Result, DidDocumentBuilderError> { ServiceBuilder::new(id, service_endpoint) } @@ -41,30 +44,33 @@ impl Service { &self.service_type } - pub fn service_endpoint(&self) -> &str { - self.service_endpoint.as_ref() + pub fn service_endpoint(&self) -> &Url { + &self.service_endpoint } - pub fn extra_field(&self, key: &str) -> Option<&Value> { - self.extra.get(key) + pub fn extra(&self) -> &E { + &self.extra } } #[derive(Debug)] -pub struct ServiceBuilder { +pub struct ServiceBuilder { id: Uri, service_type: HashSet, service_endpoint: Url, - extra: HashMap, + extra: E, } -impl ServiceBuilder { +impl ServiceBuilder +where + E: Default, +{ pub fn new(id: Uri, service_endpoint: Url) -> Result { Ok(Self { id, service_endpoint, service_type: HashSet::new(), - extra: HashMap::new(), + extra: E::default(), }) } @@ -79,12 +85,12 @@ impl ServiceBuilder { Ok(self) } - pub fn add_extra_field(mut self, key: String, value: Value) -> Self { - self.extra.insert(key, value); + pub fn add_extra(mut self, extra: E) -> Self { + self.extra = extra; self } - pub fn build(self) -> Result { + pub fn build(self) -> Result, DidDocumentBuilderError> { if self.service_type.is_empty() { Err(DidDocumentBuilderError::MissingField("type")) } else { @@ -106,21 +112,30 @@ mod tests { Uri::new("http://example.com").unwrap() } + #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] + #[serde(rename_all = "camelCase")] + pub struct ExtraSov { + pub priority: u32, + pub recipient_keys: Vec, + pub routing_keys: Vec, + } + #[test] fn test_service_builder_basic() { let id = create_valid_uri(); let service_endpoint = "http://example.com/endpoint"; let service_type = "DIDCommMessaging".to_string(); - let service = ServiceBuilder::new(id.clone(), service_endpoint.try_into().unwrap()) - .unwrap() - .add_service_type(service_type.clone()) - .unwrap() - .build() - .unwrap(); + let service = + ServiceBuilder::::new(id.clone(), service_endpoint.try_into().unwrap()) + .unwrap() + .add_service_type(service_type.clone()) + .unwrap() + .build() + .unwrap(); assert_eq!(service.id(), &id); - assert_eq!(service.service_endpoint(), service_endpoint); + assert_eq!(service.service_endpoint().as_ref(), service_endpoint); assert_eq!(service.service_type(), &OneOrList::List(vec![service_type])); } @@ -129,18 +144,24 @@ mod tests { let id = create_valid_uri(); let service_endpoint = "http://example.com/endpoint"; let service_type = "DIDCommMessaging".to_string(); - let extra_key = "foo".to_string(); - let extra_value = Value::String("bar".to_string()); - - let service = ServiceBuilder::new(id, service_endpoint.try_into().unwrap()) + let recipient_keys = vec!["foo".to_string()]; + let routing_keys = vec!["bar".to_string()]; + let extra = ExtraSov { + priority: 0, + recipient_keys: recipient_keys.clone(), + routing_keys: routing_keys.clone(), + }; + + let service = ServiceBuilder::::new(id, service_endpoint.try_into().unwrap()) .unwrap() .add_service_type(service_type) .unwrap() - .add_extra_field(extra_key.clone(), extra_value.clone()) + .add_extra(extra) .build() .unwrap(); - assert_eq!(service.extra_field(&extra_key).unwrap(), &extra_value); + assert_eq!(service.extra().recipient_keys, recipient_keys); + assert_eq!(service.extra().routing_keys, routing_keys); } #[test] @@ -149,7 +170,7 @@ mod tests { let service_endpoint = "http://example.com/endpoint"; let service_type = "DIDCommMessaging".to_string(); - let service = ServiceBuilder::new(id, service_endpoint.try_into().unwrap()) + let service = ServiceBuilder::::new(id, service_endpoint.try_into().unwrap()) .unwrap() .add_service_type(service_type.clone()) .unwrap() @@ -166,7 +187,7 @@ mod tests { let id = create_valid_uri(); let service_endpoint = "http://example.com/endpoint"; - let res = ServiceBuilder::new(id, service_endpoint.try_into().unwrap()) + let res = ServiceBuilder::::new(id, service_endpoint.try_into().unwrap()) .unwrap() .add_service_type("".to_string()); assert!(res.is_err()); @@ -188,7 +209,7 @@ mod tests { "serviceEndpoint": "https://example.com/endpoint" }"##; - let service: Service = serde_json::from_str(service_serialized).unwrap(); + let service: Service = serde_json::from_str(service_serialized).unwrap(); assert_eq!( service.id(), &Uri::new("did:sov:HR6vs6GEZ8rHaVgjg2WodM#did-communication").unwrap() @@ -197,16 +218,14 @@ mod tests { service.service_type(), &OneOrList::One("did-communication".to_string()) ); - assert_eq!(service.service_endpoint(), "https://example.com/endpoint"); assert_eq!( - service.extra_field("priority").unwrap(), - &Value::Number(0.into()) + service.service_endpoint().as_ref(), + "https://example.com/endpoint" ); + assert_eq!(service.extra().priority, 0); assert_eq!( - service.extra_field("recipientKeys").unwrap(), - &Value::Array(vec![Value::String( - "did:sov:HR6vs6GEZ8rHaVgjg2WodM#key-agreement-1".to_string() - )]) + service.extra().recipient_keys, + vec!["did:sov:HR6vs6GEZ8rHaVgjg2WodM#key-agreement-1".to_string()] ); } } diff --git a/did_doc/src/schema/types/url.rs b/did_doc/src/schema/types/url.rs index ff736bf3cf..b35d738a75 100644 --- a/did_doc/src/schema/types/url.rs +++ b/did_doc/src/schema/types/url.rs @@ -1,3 +1,5 @@ +use std::{fmt::Display, str::FromStr}; + use serde::{Deserialize, Serialize}; use url::Url as UrlDep; @@ -20,8 +22,34 @@ impl TryFrom<&str> for Url { } } +impl FromStr for Url { + type Err = DidDocumentBuilderError; + + fn from_str(s: &str) -> Result { + Ok(Self(UrlDep::parse(s)?)) + } +} + +impl From for Url { + fn from(url: UrlDep) -> Self { + Self(url) + } +} + +impl From for UrlDep { + fn from(url: Url) -> Self { + url.0 + } +} + impl AsRef for Url { fn as_ref(&self) -> &str { self.0.as_str() } } + +impl Display for Url { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.as_str().fmt(f) + } +} diff --git a/did_doc/src/schema/utils/mod.rs b/did_doc/src/schema/utils/mod.rs index 117c38b269..088ea8bda2 100644 --- a/did_doc/src/schema/utils/mod.rs +++ b/did_doc/src/schema/utils/mod.rs @@ -1,3 +1,5 @@ +use std::fmt::{Debug, Display}; + use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] @@ -6,3 +8,12 @@ pub enum OneOrList { One(T), List(Vec), } + +impl Display for OneOrList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OneOrList::One(t) => write!(f, "{}", t), + OneOrList::List(t) => write!(f, "{:?}", t), + } + } +} diff --git a/did_doc/tests/serde.rs b/did_doc/tests/serde.rs index e8b33fa26b..ce3cd94ee7 100644 --- a/did_doc/tests/serde.rs +++ b/did_doc/tests/serde.rs @@ -73,7 +73,7 @@ const VALID_DID_DOC_JSON: &str = r##" #[test] fn test_deserialization() { - let did_doc: DidDocument = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); + let did_doc: DidDocument<()> = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); assert_eq!( did_doc.id(), @@ -181,11 +181,11 @@ fn test_deserialization() { #[test] fn test_serialization() { - let did_doc: DidDocument = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); + let did_doc: DidDocument<()> = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); let serialized_json = serde_json::to_string(&did_doc).unwrap(); - let original_json_value: DidDocument = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); - let serialized_json_value: DidDocument = serde_json::from_str(&serialized_json).unwrap(); + let original_json_value: DidDocument<()> = serde_json::from_str(VALID_DID_DOC_JSON).unwrap(); + let serialized_json_value: DidDocument<()> = serde_json::from_str(&serialized_json).unwrap(); assert_eq!(serialized_json_value, original_json_value); } diff --git a/did_parser/src/did.rs b/did_parser/src/did.rs index ed5c04e52e..2266410ca0 100644 --- a/did_parser/src/did.rs +++ b/did_parser/src/did.rs @@ -1,11 +1,12 @@ use std::convert::TryFrom; use std::fmt::{Display, Formatter}; +use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use crate::{error::ParseError, utils::parse::parse_did_method_id, DidRange}; -#[derive(Default, Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Did { did: String, method: DidRange, @@ -48,12 +49,30 @@ impl TryFrom for Did { } } +impl FromStr for Did { + type Err = ParseError; + + fn from_str(did: &str) -> Result { + Self::parse(did.to_string()) + } +} + impl Display for Did { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.did) } } +impl Default for Did { + fn default() -> Self { + Self { + did: "did:example:123456789abcdefghi".to_string(), + method: 4..11, + id: 12..30, + } + } +} + impl Serialize for Did { fn serialize(&self, serializer: S) -> Result where diff --git a/did_parser/src/did_url.rs b/did_parser/src/did_url.rs index 5eb7f29747..069cc9efe2 100644 --- a/did_parser/src/did_url.rs +++ b/did_parser/src/did_url.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, fmt::Display}; +use std::{collections::HashMap, fmt::Display, str::FromStr}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -156,6 +156,14 @@ impl TryFrom for DidUrl { } } +impl FromStr for DidUrl { + type Err = ParseError; + + fn from_str(did: &str) -> Result { + Self::parse(did.to_string()) + } +} + impl Display for DidUrl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.did_url) diff --git a/did_resolver/src/traits/resolvable/mod.rs b/did_resolver/src/traits/resolvable/mod.rs index 4aa48da81d..4984deb586 100644 --- a/did_resolver/src/traits/resolvable/mod.rs +++ b/did_resolver/src/traits/resolvable/mod.rs @@ -11,9 +11,11 @@ use self::{resolution_options::DidResolutionOptions, resolution_output::DidResol #[async_trait] pub trait DidResolvable { + type ExtraFields: Default; + async fn resolve( &self, did: &Did, options: &DidResolutionOptions, - ) -> Result; + ) -> Result, GenericError>; } diff --git a/did_resolver/src/traits/resolvable/resolution_output.rs b/did_resolver/src/traits/resolvable/resolution_output.rs index b73c8f75d9..d40205e280 100644 --- a/did_resolver/src/traits/resolvable/resolution_output.rs +++ b/did_resolver/src/traits/resolvable/resolution_output.rs @@ -9,14 +9,14 @@ use crate::shared_types::did_document_metadata::DidDocumentMetadata; // non-empty field in DidResolutionOutput in the error case. #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] #[serde(rename_all = "camelCase")] -pub struct DidResolutionOutput { - did_document: DidDocument, +pub struct DidResolutionOutput { + did_document: DidDocument, did_resolution_metadata: DidResolutionMetadata, did_document_metadata: DidDocumentMetadata, } -impl DidResolutionOutput { - pub fn builder(did_document: DidDocument) -> DidResolutionOutputBuilder { +impl DidResolutionOutput { + pub fn builder(did_document: DidDocument) -> DidResolutionOutputBuilder { DidResolutionOutputBuilder { did_document, did_resolution_metadata: None, @@ -24,7 +24,7 @@ impl DidResolutionOutput { } } - pub fn did_document(&self) -> &DidDocument { + pub fn did_document(&self) -> &DidDocument { &self.did_document } @@ -37,13 +37,13 @@ impl DidResolutionOutput { } } -pub struct DidResolutionOutputBuilder { - did_document: DidDocument, +pub struct DidResolutionOutputBuilder { + did_document: DidDocument, did_resolution_metadata: Option, did_document_metadata: Option, } -impl DidResolutionOutputBuilder { +impl DidResolutionOutputBuilder { pub fn did_resolution_metadata( mut self, did_resolution_metadata: DidResolutionMetadata, @@ -57,7 +57,7 @@ impl DidResolutionOutputBuilder { self } - pub fn build(self) -> DidResolutionOutput { + pub fn build(self) -> DidResolutionOutput { DidResolutionOutput { did_document: self.did_document, did_resolution_metadata: self.did_resolution_metadata.unwrap_or_default(), diff --git a/did_resolver_registry/src/lib.rs b/did_resolver_registry/src/lib.rs index ccbc81a38d..588fbce591 100644 --- a/did_resolver_registry/src/lib.rs +++ b/did_resolver_registry/src/lib.rs @@ -13,7 +13,7 @@ use did_resolver::{ use error::DidResolverRegistryError; pub struct ResolverRegistry { - resolvers: HashMap>, + resolvers: HashMap>>, // TODO: Use e.g. hashmap } impl ResolverRegistry { @@ -23,7 +23,11 @@ impl ResolverRegistry { } } - pub fn register_resolver(&mut self, method: String, resolver: Box) { + pub fn register_resolver( + &mut self, + method: String, + resolver: Box>, + ) { self.resolvers.insert(method, resolver); } @@ -35,7 +39,7 @@ impl ResolverRegistry { &self, did: &Did, options: &DidResolutionOptions, - ) -> Result { + ) -> Result, GenericError> { let method = did.method(); match self.resolvers.get(method) { Some(resolver) => resolver.resolve(did, options).await, @@ -57,11 +61,13 @@ mod tests { #[async_trait] #[automock] impl DidResolvable for DummyDidResolver { + type ExtraFields = (); + async fn resolve( &self, did: &Did, _options: &DidResolutionOptions, - ) -> Result { + ) -> Result, GenericError> { Ok(DidResolutionOutput::builder( DidDocumentBuilder::new(Did::parse(did.did().to_string()).unwrap()).build(), ) @@ -92,7 +98,7 @@ mod tests { .times(1) .return_once(move |_, _| { let future = async move { - Err::(Box::new(DummyResolverError)) + Err::, GenericError>(Box::new(DummyResolverError)) }; Pin::from(Box::new(future)) }); @@ -126,7 +132,7 @@ mod tests { .times(1) .return_once(move |_, _| { let future = async move { - Ok::( + Ok::, GenericError>( DidResolutionOutput::builder( DidDocumentBuilder::new(Did::parse(did.to_string()).unwrap()).build(), ) @@ -193,7 +199,7 @@ mod tests { .times(1) .return_once(move |_, _| { let future = async move { - Ok::( + Ok::, GenericError>( DidResolutionOutput::builder( DidDocumentBuilder::new(Did::parse(did.to_string()).unwrap()).build(), ) diff --git a/did_resolver_sov/src/dereferencing/utils.rs b/did_resolver_sov/src/dereferencing/utils.rs index 1d12da1f26..cbcb2f5a72 100644 --- a/did_resolver_sov/src/dereferencing/utils.rs +++ b/did_resolver_sov/src/dereferencing/utils.rs @@ -13,10 +13,11 @@ use did_resolver::{ resolvable::resolution_output::DidResolutionOutput, }, }; +use serde::Serialize; use crate::error::DidSovError; -pub fn service_by_id(services: &[Service], predicate: F) -> Option<&Service> +pub fn service_by_id(services: &[Service], predicate: F) -> Option<&Service> where F: Fn(&str) -> bool, { @@ -35,8 +36,8 @@ where .find(|auth| predicate(auth.id().did_url())) } -fn content_stream_from( - did_document: &DidDocument, +fn content_stream_from( + did_document: &DidDocument, did_url: &DidUrl, ) -> Result>, DidSovError> { let fragment = did_url.fragment().ok_or_else(|| { @@ -70,8 +71,8 @@ fn content_stream_from( } // TODO: Currently, only fragment dereferencing is supported -pub(crate) fn dereference_did_document( - resolution_output: &DidResolutionOutput, +pub(crate) fn dereference_did_document( + resolution_output: &DidResolutionOutput, did_url: &DidUrl, ) -> Result>>, DidSovError> { let content_stream = content_stream_from(resolution_output.did_document(), did_url)?; @@ -97,7 +98,7 @@ mod tests { use did_resolver::traits::resolvable::resolution_output::DidResolutionOutput; use serde_json::Value; - fn example_did_document_builder() -> DidDocumentBuilder { + fn example_did_document_builder() -> DidDocumentBuilder<()> { let verification_method = VerificationMethod::builder( DidUrl::parse("did:example:123456789abcdefghi#keys-1".to_string()).unwrap(), "did:example:123456789abcdefghi" @@ -132,18 +133,13 @@ mod tests { .build() .unwrap(); - DidDocument::builder( - "did:example:123456789abcdefghi" - .to_string() - .try_into() - .unwrap(), - ) - .add_verification_method(verification_method) - .add_service(agent_service) - .add_service(messaging_service) + DidDocument::builder(Default::default()) + .add_verification_method(verification_method) + .add_service(agent_service) + .add_service(messaging_service) } - fn example_resolution_output() -> DidResolutionOutput { + fn example_resolution_output() -> DidResolutionOutput<()> { DidResolutionOutput::builder(example_did_document_builder().build()).build() } diff --git a/did_resolver_sov/src/resolution/extra_fields.rs b/did_resolver_sov/src/resolution/extra_fields.rs new file mode 100644 index 0000000000..86e3c93e31 --- /dev/null +++ b/did_resolver_sov/src/resolution/extra_fields.rs @@ -0,0 +1,90 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)] +#[serde(rename_all = "camelCase")] +pub struct ExtraFieldsSov { + #[serde(default)] + priority: u32, + #[serde(default)] + recipient_keys: Vec, + #[serde(default)] + routing_keys: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + accept: Vec, +} + +impl ExtraFieldsSov { + pub fn builder() -> ExtraFieldsSovBuilder { + ExtraFieldsSovBuilder::default() + } + + pub fn priority(&self) -> u32 { + self.priority + } + + pub fn recipient_keys(&self) -> &[String] { + self.recipient_keys.as_ref() + } + + pub fn routing_keys(&self) -> &[String] { + self.routing_keys.as_ref() + } + + pub fn accept(&self) -> &[String] { + self.accept.as_ref() + } +} + +#[derive(Default)] +pub struct ExtraFieldsSovBuilder { + priority: u32, + recipient_keys: Vec, + routing_keys: Vec, + accept: Vec, +} + +impl ExtraFieldsSovBuilder { + pub fn set_priority(&mut self, priority: u32) -> &mut Self { + self.priority = priority; + self + } + + pub fn set_recipient_keys(&mut self, recipient_keys: Vec) -> &mut Self { + self.recipient_keys = recipient_keys; + self + } + + pub fn add_recipient_key(&mut self, recipient_key: String) -> &mut Self { + self.recipient_keys.push(recipient_key); + self + } + + pub fn set_routing_keys(&mut self, routing_keys: Vec) -> &mut Self { + self.routing_keys = routing_keys; + self + } + + pub fn add_routing_key(&mut self, routing_key: String) -> &mut Self { + self.routing_keys.push(routing_key); + self + } + + pub fn set_accept(&mut self, accept: Vec) -> &mut Self { + self.accept = accept; + self + } + + pub fn add_accept(&mut self, accept: String) -> &mut Self { + self.accept.push(accept); + self + } + + pub fn build(&self) -> ExtraFieldsSov { + ExtraFieldsSov { + priority: self.priority, + recipient_keys: self.recipient_keys.clone(), + routing_keys: self.routing_keys.clone(), + accept: self.accept.clone(), + } + } +} diff --git a/did_resolver_sov/src/resolution/mod.rs b/did_resolver_sov/src/resolution/mod.rs index 054d33feef..8e5ea2a20d 100644 --- a/did_resolver_sov/src/resolution/mod.rs +++ b/did_resolver_sov/src/resolution/mod.rs @@ -1,4 +1,6 @@ +mod extra_fields; mod resolver; mod utils; +pub use extra_fields::ExtraFieldsSov; pub use resolver::DidSovResolver; diff --git a/did_resolver_sov/src/resolution/resolver.rs b/did_resolver_sov/src/resolution/resolver.rs index fbd73cfc47..435d1e61cf 100644 --- a/did_resolver_sov/src/resolution/resolver.rs +++ b/did_resolver_sov/src/resolution/resolver.rs @@ -17,7 +17,10 @@ use crate::{ reader::AttrReader, }; -use super::utils::{is_valid_sovrin_did_id, ledger_response_to_ddo}; +use super::{ + utils::{is_valid_sovrin_did_id, ledger_response_to_ddo}, + ExtraFieldsSov, +}; pub struct DidSovResolver { ledger: Arc, @@ -31,11 +34,13 @@ impl DidSovResolver { #[async_trait] impl DidResolvable for DidSovResolver { + type ExtraFields = ExtraFieldsSov; + async fn resolve( &self, parsed_did: &Did, options: &DidResolutionOptions, - ) -> Result { + ) -> Result, GenericError> { if let Some(accept) = options.accept() { if accept != &MediaType::DidJson { return Err(Box::new(DidSovError::RepresentationNotSupported( diff --git a/did_resolver_sov/src/resolution/utils.rs b/did_resolver_sov/src/resolution/utils.rs index 69828c070e..76f5f25d9e 100644 --- a/did_resolver_sov/src/resolution/utils.rs +++ b/did_resolver_sov/src/resolution/utils.rs @@ -59,11 +59,11 @@ pub(super) fn is_valid_sovrin_did_id(id: &str) -> bool { id.chars().all(|c| base58_chars.contains(c)) } -pub(super) async fn ledger_response_to_ddo( +pub(super) async fn ledger_response_to_ddo( did: &str, resp: &str, verkey: String, -) -> Result { +) -> Result, DidSovError> { let (service_id, ddo_id) = prepare_ids(did)?; let service_data = get_data_from_response(resp)?; @@ -176,12 +176,14 @@ mod tests { } }"#; let verkey = "9wvq2i4xUa5umXoThe83CDgx1e5bsjZKJL4DEWvTP9qe".to_string(); - let resolution_output = ledger_response_to_ddo(did, resp, verkey).await.unwrap(); + let resolution_output = ledger_response_to_ddo::<()>(did, resp, verkey) + .await + .unwrap(); let ddo = resolution_output.did_document(); assert_eq!(ddo.id().to_string(), "did:example:1234567890"); assert_eq!(ddo.service()[0].id().to_string(), "did:example:1234567890"); assert_eq!( - ddo.service()[0].service_endpoint().to_string(), + ddo.service()[0].service_endpoint().as_ref(), "https://example.com/" ); assert_eq!( diff --git a/did_resolver_web/src/resolution/resolver.rs b/did_resolver_web/src/resolution/resolver.rs index 6e5b4e75bf..2176210d9b 100644 --- a/did_resolver_web/src/resolution/resolver.rs +++ b/did_resolver_web/src/resolution/resolver.rs @@ -65,7 +65,13 @@ impl DidResolvable for DidWebResolver where C: Connect + Send + Sync + Clone + 'static, { - async fn resolve(&self, did: &Did, options: &DidResolutionOptions) -> Result { + type ExtraFields = (); + + async fn resolve( + &self, + did: &Did, + options: &DidResolutionOptions, + ) -> Result, GenericError> { if did.method() != "web" { return Err(Box::new(DidWebError::MethodNotSupported(did.method().to_string()))); } diff --git a/did_resolver_web/tests/resolution.rs b/did_resolver_web/tests/resolution.rs index 69edeb4eaa..4d7b4bb7e8 100644 --- a/did_resolver_web/tests/resolution.rs +++ b/did_resolver_web/tests/resolution.rs @@ -88,7 +88,7 @@ async fn create_mock_server(port: u16) -> String { #[tokio::test] async fn test_did_web_resolver() { - fn verify_did_document(did_document: &DidDocument) { + fn verify_did_document(did_document: &DidDocument<()>) { assert_eq!(did_document.id().to_string(), "did:web:example.com".to_string()); assert_eq!(did_document.verification_method().len(), 3); assert_eq!(did_document.authentication().len(), 2);